我在linux上使用NASM编写一个基本的汇编程序,它从C库(printf)调用一个函数。不幸的是,我这样做会导致分段错误。注释掉对printf的调用允许程序无错误地运行。
; Build using these commands:
; nasm -f elf64 -g -F stabs <filename>.asm
; gcc <filename>.o -o <filename>
;
SECTION .bss ; Section containing uninitialized data
SECTION .data ; Section containing initialized data
text db "hello world",10 ;
SECTION .text ; Section containing code
global main
extern printf
;-------------
;MAIN PROGRAM BEGINS HERE
;-------------
main:
push rbp
mov rbp,rsp
push rbx
push rsi
push rdi ;preserve registers
****************
;code i wish to execute
push text ;pushing address of text on to the stack
;x86-64 uses registers for first 6 args, thus should have been:
;mov rdi,text (place address of text in rdi)
;mov rax,0 (place a terminating byte at end of rdi)
call printf ;calling printf from c-libraries
add rsp,8 ;reseting the stack to pre "push text"
**************
pop rdi ;preserve registers
pop rsi
pop rbx
mov rsp,rbp
pop rbp
ret
答案 0 :(得分:3)
x86_64不会将堆栈用于前6个args。您需要在适当的寄存器中加载它们。那些是:
rdi, rsi, rdx, rcx, r8, r9
我用来记住前两个的技巧是想象函数是memcpy
实现为rep movsb
,
答案 1 :(得分:1)
您需要熟悉正在使用的调用约定。 AMD64上的Linux使用System V AMD64 ABI。从该文件中我们了解到:
call
之前以16字节对齐,因此在函数条目RSP-8上对齐(在call
本身推送返回地址之后。)所以对于电话
printf ("Hello World\n");
你有
.section .rodata
format db "Hello World", 10, 0
.section .text
my_function:
sub rsp, 8
; with RSP 16-byte aligned, e.g. from sub rsp,8 or an odd number of pushes
mov edi, format ; or in PIC code: lea rdi, [rel format]
; mov rsi, 2nd arg if any
xor eax, eax ; no FP args
call printf
add rsp, 8
ret
请注意字符串上的0
终结符:C字符串是隐式长度,以0
字节终止。
答案 2 :(得分:0)
你正在调用一个varargs函数 - printf需要一个可变数量的参数,你必须在参数堆栈中考虑它。见这里:http://www.csee.umbc.edu/portal/help/nasm/sample.shtml#printf1