Still learning Assembly. This program is a simple guessing game to test most of the new things I've learned! Any advice and all topical comments on code optimization and conventions is appreciated!
Compiled as follows using VS2017 x64 Native Tools Command Prompt
:
> nasm -g -fwin64 guess.asm > cl /Zi guess.obj msvcrt.lib legacy_stdio_definitions.lib
guess.asm
;; bits 64
default rel
extern time, srand, rand
extern printf, scanf
%macro str 2
%2: db %1, 0
%endmacro
; use DQ to define a quad-word, DD to define a double-word, DW to define a word, and DB to define a byte.
section .rdata ; immutable predefined variables
str "Enter your guess (1-100): ", prompt
str "%u", scan_fmt
str "ERROR! Input was not a number!", scan_fail
str {"Too high!", 10}, too_high
str {"Too low!", 10}, too_low
str {"You guessed it!", 13, 10}, congrats
; use RESQ to reserve a number of quad-words, RESD to reserve a number of double-words, RESW to reserve a number of words, and RESB to reserve a number of bytes.
section .bss ; mutable undefined variables
target: resb 4 ; 4 bytes of storage (enough for a 32bit number)
section .text
global main
main:
stack_reserve: equ 40 ; 32 + 8
sub rsp, stack_reserve ; shadow space for callees + 8 bytes for stack alignment
;; calculate the random number
xor rax, rax
mov rcx, rax ; clear rax and rcx
call time
mov rcx, rax
call srand
call rand
;; rand = (rand % 100) + 1
xor rdx, rdx ; clear rdx
mov rcx, 100
div rcx
inc rdx
mov [target], rdx
;mov rcx, scan_fmt
;call printf
.check:
lea rcx, [prompt]
call printf
; memory from rsp+0..31 has potentially been stepped on by printf
; leave RSP where it is, ready for another call
;;; scanf into that 8-byte block of stack space above the shadow space, or into our *own* shadow space
lea rdx, [rsp+32] ; stack addresses are normally 64-bit, can't get away with edx
lea rcx, [scan_fmt]
mov dword [rdx], 0 ; instead of error check, set n = 0 in case of I/O error
call scanf
cmp eax, 1 ; success = exactly 1 conversion
jnz .scanf_fail ; error check
mov r8d, [rsp+32] ; r8d: 32-bit unsigned number to be checked
cmp r8d, [target]
jg .too_high
jl .too_low
lea rcx, [congrats]
call printf
.end:
;xor eax,eax ; return 0
movzx eax, byte [rsp+32] ; return EXIT_SUCCESS(0) or EXIT_FAILURE(1)
add rsp, stack_reserve
ret
.too_high:
lea rcx, [too_high]
call printf
jmp .check
.too_low:
lea rcx, [too_low]
call printf
jmp .check
.scanf_fail:
lea rcx, [scan_fail]
call printf
jmp .end