为什么出现错误 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
,之前没有 push
ing 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 个字节并使堆栈正确对齐。因此,要么保留该代码,要么自己对齐堆栈。
无论哪种情况,请记住,如果您更改代码以将更多内容压入堆栈,则必须在进行任何函数调用之前相应地进行调整。
问题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
,之前没有 push
ing 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 个字节并使堆栈正确对齐。因此,要么保留该代码,要么自己对齐堆栈。
无论哪种情况,请记住,如果您更改代码以将更多内容压入堆栈,则必须在进行任何函数调用之前相应地进行调整。