汇编子例程被调用两次,甚至没有从主程序调用

发布于 2024-12-20 18:47:04 字数 811 浏览 4 评论 0原文

我正在尝试定义一些在其中调用 printf 的子例程。 一个非常简单的示例如下:

extern printf
LINUX        equ     80H
EXIT         equ     60

section .data
    intfmt: db "%ld", 10, 0

segment .text
    global  main

main:
    call os_return      ; return to operating system

os_return:
    mov  rax, EXIT      ; Linux system call 60 i.e. exit ()
    mov  rdi, 0     ; Error code 0 i.e. no errors
    int  LINUX      ; Interrupt Linux kernel

test:
    push rdi
    push rsi
    mov rsi, 10
    mov rdi, intfmt
    xor rax, rax
    call printf
    pop rdi
    pop rsi
    ret

这里 test 只是调用 printf 将数字 10 输出到屏幕。我不希望它被调用,因为我没有调用它。

然而,在编译和运行时:

nasm -f elf64 test.asm
gcc -m64 -o test test.o

我得到输出:

10
10

我完全感到困惑,想知道是否有人可以解释为什么会发生这种情况?

I'm trying to define some subroutines that have calls to printf in them.
A very trivial example is as follows:

extern printf
LINUX        equ     80H
EXIT         equ     60

section .data
    intfmt: db "%ld", 10, 0

segment .text
    global  main

main:
    call os_return      ; return to operating system

os_return:
    mov  rax, EXIT      ; Linux system call 60 i.e. exit ()
    mov  rdi, 0     ; Error code 0 i.e. no errors
    int  LINUX      ; Interrupt Linux kernel

test:
    push rdi
    push rsi
    mov rsi, 10
    mov rdi, intfmt
    xor rax, rax
    call printf
    pop rdi
    pop rsi
    ret

Here test just has a call to printf that outputs the number 10 to the screen. I would not expect this to get called as I have no call to it.

However when compiling and running:

nasm -f elf64 test.asm
gcc -m64 -o test test.o

I get the output:

10
10

I'm totally baffled and wondered if someone could explain why this is happening?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

缺⑴份安定 2024-12-27 18:47:05

int 80H 调用 32 位系统调用接口,该接口 a) 使用 32 位系统调用号,b) 供 32 位代码使用,而不是 64 位代码。您的代码实际上是使用随机参数执行 umask 系统调用。

对于 64 位系统调用,请改用 syscall 指令:

...
os_return:
    mov  rax, EXIT      ; Linux system call 60 i.e. exit ()
    mov  rdi, 0     ; Error code 0 i.e. no errors
    syscall         ; Interrupt Linux kernel
...

int 80H invokes the 32-bit system call interface, which a) uses the 32-bit system call numbers and b) is intended for use by 32-bit code, not 64-bit code. Your code is actually performing a umask system call with random parameters.

For a 64-bit system call, use the syscall instruction instead:

...
os_return:
    mov  rax, EXIT      ; Linux system call 60 i.e. exit ()
    mov  rdi, 0     ; Error code 0 i.e. no errors
    syscall         ; Interrupt Linux kernel
...
月光色 2024-12-27 18:47:05

我想说的是,您对 exit 的调用失败了,因此当它返回时,它会转到 test 函数,该函数会打印前 10 个。

然后当您使用 < code>ret 您将返回到调用 os_return 之后的指令,即 os_return。对 exit 的调用再次失败,并再次转到 test 函数。但这次 retmain 函数返回,程序结束。

关于为什么 exit 调用失败,我无法判断,因为我没有可用的 64 位系统。但是您可以从 libc 中反汇编 exit 函数,看看它是如何完成的。我的猜测是 int LINUX 接口只是 32 位的,因为它的存在只是为了历史兼容性,而 64 位 Linux 并不那么古老。

I would say that your call to exit is failing, so when it returns, it falls through to the test function, that prints the first 10.

Then when you return with ret you go back to the instruction just after the call os_return, that is, well os_return. The call to exit fails again and falls through to the test function again. But this time the ret returns from the main function and the program ends.

About why is the exit call failing, I cannot tell as I don't have a 64-bit system available. But you could disassemble the exit function from libc and see how it is done there. My guess is that the int LINUX interface is 32-bit only, as it exists only for historic compatibility, and 64-bit linux in not so old.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文