从Linux 64位汇编程序访问进程命令行时遇到问题。 为了用最less的代码重现这一点,我制作了这个打印程序名称前5个字符的32位程序:
.section .text .globl _start _开始: movl%esp,%ebp movl $ 4,%eax#写入 movl $ 1,%ebx#stdout movl 4(%ebp),%ecx#程序名称地址(argv [0]) movl $ 5,%edx#硬编码的长度 int $ 0x80 movl $ 1,%eax movl $ 0,%ebx int $ 0x80
这个程序正在工作。 当我将它翻译成64位并在Linux 64上运行时,它不会打印任何内容:
.section .text .globl _start _开始: movq%rsp,%rbp movq $ 4,%rax movq $ 1,%rbx movq 8(%rbp),%rcx#程序名称地址? movq $ 5,%rdx int $ 0x80 movq $ 1,%rax movq $ 0,%rbx int $ 0x80
我的错误在哪里?
您正在将正确的地址加载到%rcx
。
int 0x80
然后调用32位系统调用接口。 这将地址截断为32位,这使得它不正确。 (如果你使用一个调试器并在第一个int 0x80
后面设置一个断点,你会发现它返回的时候是-14,在%eax
中是-EFAULT
。)
第二个系统调用exit
工作正常,因为截断到32位在这种情况下不会造成任何伤害。
如果要将64位地址传递给系统调用,则必须使用64位系统调用接口:
syscall
,而不是int 0x80
; 这里是你的代码的工作版本:
.section .text .globl _start _start: movq %rsp, %rbp movq $1, %rax movq $1, %rdi movq 8(%rbp), %rsi # program name address ? movq $5, %rdx syscall movq $60, %rax movq $0, %rdi syscall
如X86_64 ABI所述 :使用syscall
指令而不是int $0x80
。 内核在64位中使用不同的寄存器作为系统调用参数,为系统调用函数分配的编号也在i386和x86_64之间变化。
一个例子 – 在德国,对不起 – 可以在这里找到:
http://zygentoma.de/codez/linux_assembler.php