当我写了如下汇编时
bash
; nasm -f elf64 -g -F dwarf charsin.asm
; gcc charsin.o -no-pie -o charsin
; ld -o eatclib eatclib.o
; gdb eatclib
[SECTION .data]
SPrompt db 'Enter string data, followed by Enter: ',0
IPrompt db 'Enter an integer value, followed by Enter: ',10,0
IFormat db "%d",0
SShow db 'The string you entered was: %s',0
IShow db 'The Integer value you entered was: %5d',10,0
[SECTION .bss]
IntVal resd 1
InString resb 128
[SECTION .text]
extern stdin
extern fgets
extern printf
extern scanf
global main
main:
push rbp
mov rbp,rsp
push rbx
push rsi
push rdi
;push SPrompt
mov rdi,SPrompt ; 传递参数
mov rax,0
call printf
;add rsp,8
; rdi,rsi,rdx,rcx分别保存第1,2,3,4个参数
;push qword [stdin]
;push 72
;push InString
mov rdi,InString
mov rsi,72
mov rdx,[stdin]
mov rax,0
call fgets
;add rsp,24
;push InString
;push SShow
mov rdi,SShow
mov rsi,InString
;在汇编代码中,若是调用变长参数的函数,需要使用al这个寄存器记录使用到的向量寄存器数量。
;这段代码中eax中存放的不是系统调用号,存放的是向量寄存器使用到的数量0,因为printf使用的是变长参数。
mov rax,0
call printf
;add rsp,16
mov rax,0
push IPrompt
mov rdi,IPrompt ; 传递参数
call printf
add rsp,8
;push IntVal
;push IFormat
mov rdi,IFormat
mov rsi,IntVal ; 保留数字的内存地址
xor rax,rax
call scanf
;add rsp,16
;mov rax, 0 ;sys_read 系统调用号
;mov rdi, 0 ; 文件描述符 标准输入
;mov rsi,IntVal ; 保留数字的内存地址
;mov rdx, 4
;syscall
xor rsi,rsi
mov rax,0
mov rdi,IShow ; 传递格式参数
mov esi,[IntVal]
call printf
;add rsp,16
pop rdi
pop rsi
pop rbx
mov rsp,rbp
pop rbp
ret
编译后,系统会如下段错误(Segmentation fault (core dumped)).
在函数的开始/结束处使用 sub rsp, 8/add rsp, 8 将堆栈重新对齐到 16函数执行调用之前的字节。
bash
; nasm -f elf64 -g -F dwarf charsin.asm
; gcc charsin.o -no-pie -o charsin
; ld -o eatclib eatclib.o
; gdb eatclib
[SECTION .data]
SPrompt db 'Enter string data, followed by Enter: ',0
IPrompt db 'Enter an integer value, followed by Enter: ',10,0
IFormat db "%d",0
SShow db 'The string you entered was: %s',0
IShow db 'The Integer value you entered was: %5d',10,0
[SECTION .bss]
IntVal resd 1
InString resb 128
[SECTION .text]
extern stdin
extern fgets
extern printf
extern scanf
global main
main:
push rbp
mov rbp,rsp
push rbx
push rsi
push rdi
;在函数的开始/结束处使用 sub rsp, 8/add rsp, 8 将堆栈重新对齐到 16函数执行调用之前的字节。
sub rsp, 8
;push SPrompt
mov rdi,SPrompt ; 传递参数
mov rax,0
call printf
;add rsp,8
; rdi,rsi,rdx,rcx分别保存第1,2,3,4个参数
;push qword [stdin]
;push 72
;push InString
mov rdi,InString
mov rsi,72
mov rdx,[stdin]
mov rax,0
call fgets
;add rsp,24
;push InString
;push SShow
mov rdi,SShow
mov rsi,InString
;在汇编代码中,若是调用变长参数的函数,需要使用al这个寄存器记录使用到的向量寄存器数量。
;这段代码中eax中存放的不是系统调用号,存放的是向量寄存器使用到的数量0,因为printf使用的是变长参数。
mov rax,0
call printf
;add rsp,16
mov rax,0
push IPrompt
mov rdi,IPrompt ; 传递参数
call printf
add rsp,8
;push IntVal
;push IFormat
mov rdi,IFormat
mov rsi,IntVal ; 保留数字的内存地址
xor rax,rax
call scanf
;add rsp,16
;mov rax, 0 ;sys_read 系统调用号
;mov rdi, 0 ; 文件描述符 标准输入
;mov rsi,IntVal ; 保留数字的内存地址
;mov rdx, 4
;syscall
xor rsi,rsi
mov rax,0
mov rdi,IShow ; 传递格式参数
mov esi,[IntVal]
call printf
;add rsp,16
;在函数的开始/结束处使用 sub rsp, 8/add rsp, 8 将堆栈重新对齐到 16函数执行调用之前的字节。
add rsp, 8
pop rdi
pop rsi
pop rbx
mov rsp,rbp
pop rbp
ret
编译后,程序运行正常。