2011-12-11 43 views
5

我想要定义一些调用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 

我完全感到困惑,不知道,如果有人可以解释为什么发生这种情况?

回答

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

谢谢!是否将值60(EXIT)放入rdi中,而不是rax,类似于调用printf? –

+0

不,将系统调用号码放在'rax'中,并将第一个参数放在'rdi'中是正确的。请参阅http://www.x86-64.org/documentation/abi.pdf(特别是附录A),了解内核系统调用ABI的一些文档以及与用户级调用约定的差异。 –

+0

对不起,我一直在喋喋不休,但我改变了“int LINUX”这一行来调用系统调用,并将extern系统调用添加到顶端,仍然得到了两个十。有没有可能向我展示一个如何调用系统调用的小例子?非常感谢:) –

2

我会说,你到exit调用失败,所以当它返回时,它落空至test功能,打印的第10位。

然后当你ret返回你回去的指令就在call os_return之后,也就是os_return。退出的呼叫再次失败并再次进入test函数。但这一次从main函数返回ret并且程序结束。

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

相关问题