【问题标题】:assembly subroutines get called twice without even being called from main汇编子例程被调用两次,甚至没有从 main 调用
【发布时间】:2011-12-11 14:20:51
【问题描述】:

我正在尝试定义一些调用 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

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

【问题讨论】:

    标签: linux gcc assembly x86-64 subroutine


    【解决方案1】:

    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
    ...
    

    【讨论】:

    • 谢谢!我是否将值 60 (EXIT) 放入 rdi 而不是 rax,类似于调用 printf?
    • 不,将系统调用号放入rax 并将第一个参数放入rdi 是正确的。有关内核系统调用 ABI 的一些文档以及与用户级调用约定的区别,请参见 x86-64.org/documentation/abi.pdf(特别是附录 A)。
    • 很抱歉一直纠缠你,但我将“int LINUX”行更改为调用 syscall 并将 extern syscall 添加到顶部,但仍然得到两个十。你有没有机会给我看一个如何调用系统调用的小例子?非常感谢:)
    • 查看编辑的答案:我说的是syscall x86-64 指令(这是最接近使用int 80h 处理的64 位指令),而不是syscall() 库函数.
    • 这就是我感到困惑的原因。它有效 - 感谢您的所有帮助!
    【解决方案2】:

    我会说你对exit 的调用失败了,所以当它返回时,它会通过test 函数来打印前10 个。

    然后,当您返回 ret 时,您将返回到 call os_return 之后的指令,即 os_return。退出调用再次失败并再次落入test 函数。但这次retmain函数返回,程序结束。

    关于exit 调用失败的原因,我无法确定,因为我没有可用的 64 位系统。但是你可以从 libc 中反汇编 exit 函数,看看它是如何在那里完成的。我的猜测是int LINUX 接口只有 32 位,因为它只是为了历史兼容性而存在,而 64 位 linux 还不算老。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 2022-11-28
    • 1970-01-01
    • 2013-04-16
    相关资源
    最近更新 更多