在Linux 64位处理命令行

从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