为什么出现错误 24:文件描述符也可能在 asm 中打开

Why getting error 24: too may file descriptor opened in asm

问题number1:

有这个nasm:

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 ,之前没有 pushing rbp,然后 command terminated,虽然之前没有调用函数,因此不需要压入基指针.那么为什么需要它(在编译器的眼中),并且会终止?

问题 1

您误以为这与文件描述符有关。这不是报道的内容。

正如您在评论中所解释的,24 是您在 运行 程序之后 echo $? 时显示的数字。这是程序的退出代码;通常,值 return 来自 main 函数或传递给 exit()。它可以是您想要的任何值,通常 not 对应于 errno 值。

那么为什么你的程序给出的退出代码是 24?如果 main returns,那么退出代码就是它的 return 值。函数的 return 值在 return 时应保留在 rax 寄存器中(假设它是整数或指针类型)。但是你永远不会触及 rax 寄存器,所以它仍然包含 printf return 时留在那里的值。现在 printf returns 它成功打印的字符数,对于您选择的字符串是... 24(数一数)。

"too many open file descriptors" 的 errno 代码也出现了 24 只是巧合 - 这完全无关。

如果您想以退出代码 0 退出以表示成功,那么您应该 xor rax, rax 就在 ret.

之前

您没有显示将其更改为 int 0x80 以自己调用 _exit 系统调用时使用的确切代码。但在那种情况下,退出代码将是您进行系统调用时 ebx 寄存器中的任何内容。也许您的代码在 ebx 中输入了零,或者您很幸运,它恰好已经包含了零。

(旁注:int 0x80 是 32 位系统调用的接口,不适用于您似乎正在编写的 64 位程序,尽管它可能在少数情况下工作例。64位系统调用接口使用syscall指令,在ABI的A.2.1中有说明。)

问题 2

你必须对齐堆栈。

从程序集调用 C 函数时(在本例中为 printf),the x86-64 ABI Section 3.2.2 要求您将堆栈对齐到 16 字节边界。堆栈在 调用 main 之前适当对齐,并且 call 压入的 return 地址减去 8 个字节。

因此,如果您在代码中根本不接触堆栈,调用 printf 时堆栈将无法正确对齐,这可能会导致崩溃。 (汇编器不会帮你做这件事;那不是它的工作。)但是当你按下 rbp 时,它会再减去 8 个字节并使堆栈正确对齐。因此,要么保留该代码,要么自己对齐堆栈。

无论哪种情况,请记住,如果您更改代码以将更多内容压入堆栈,则必须在进行任何函数调用之前相应地进行调整。