程序集子程序被调用两次,甚至没有从main调用

时间:2011-12-11 14:20:51

标签: linux gcc assembly x86-64 subroutine

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

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

但是在编译和运行时:

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

我得到了输出:

10
10

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

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

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

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

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