问题number1:
有这种鼻音:
section .data
dat db "write out this:%x", 0xa, 0x0
section .text
global main
extern printf
main:
push rbp
mov rbp, rsp
mov rdi, dat
mov esi, 0xdeedbeef
call printf
leave
ret
给出错误号24
-打开太多文件描述符。
但如果更改为int 80h
,而不是
leave
ret
将终止无错误,那是怎么回事?
另外,问题数字2]如果我没有通过:
进行呼叫约定push rbp
mov rbp, rsp
并且仅是mov rbp, rsp
,之前没有push
调用rbp
,然后是command terminated
,尽管之前没有调用任何函数,所以不需要推送基址指针。那么,为什么需要它(在编译器看来)并且将终止?
您误认为这与文件描述符有关。这不是正在报告的内容。
正如您在注释中所解释的,24是运行程序后echo $?
时显示的数字。这是程序的退出代码;通常,从main
函数返回或传递给exit()
的值。它可以是您想要的任何内容,通常not对应于errno
值。
那么为什么您的程序给出的退出代码为24?如果返回main
,则退出代码为其返回值。函数返回时,它的返回值应保留在rax
寄存器中(假定它是整数或指针类型)。但是您永远不要触摸rax
寄存器,因此它仍然包含printf
返回时保留在其中的值。现在printf
返回成功打印的字符数,对于您选择的字符串,该字符数是... 24(计数'em)。
这只是一个巧合,errno代码的“打开的文件描述符太多”也发生了24个-这是完全不相关的。
如果要以成功的退出代码0退出以表示成功,则应在xor rax, rax
之前添加ret
。>>
您未显示将其更改为int 0x80
来自己调用_exit
syscall时使用的确切代码。但是在那种情况下,退出代码将是您进行系统调用时ebx
寄存器中的代码。也许您的代码在ebx
中放置了零,或者也许您很幸运,它恰好已经包含零。
int 0x80
指令,并在ABI的A.2.1中进行了说明。)问题2
您必须对齐纸叠。[从汇编中调用C函数时(在这种情况下为syscall
),printf
要求将堆栈对齐到16字节边界。堆栈在对the x86-64 ABI Section 3.2.2的调用之前[[before
main
推送的返回地址减去8个字节。 因此,如果您根本不触摸代码中的堆栈,则在调用call
时将无法正确对齐堆栈,这可能导致崩溃。 (汇编程序不会帮助您执行此操作;这不是它的工作。)但是,当您按printf
时,它将再减去8个字节,并使堆栈正确对齐。因此,要么保留该代码,要么自己对齐堆栈。