我正在尝试定义一些调用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
我完全感到困惑,并想知道是否有人可以解释为什么会发生这种情况?
答案 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
函数。但是这次ret
从main
函数返回,程序结束。
关于为什么exit
调用失败,我无法分辨,因为我没有可用的64位系统。但你可以从libc中反汇编exit
函数,看看它是如何在那里完成的。我的猜测是int LINUX
接口只有32位,因为它只存在于历史兼容性,而64位linux则不是那么老。