I have problems accessing the process command line from Linux 64 bit Assembly program. To reproduce this with minimal code, I made this 32-bit program which prints first 5 characters of the program name:
.section .text .globl _start _start: movl %esp, %ebp movl $4, %eax # write movl $1, %ebx # stdout movl 4(%ebp), %ecx # program name address (argv[0]) movl $5, %edx # hard-coded length int $0x80 movl $1, %eax movl $0, %ebx int $0x80
This program is working. When I translate it to 64 bit and run in Linux 64, it doesn't print anything:
.section .text .globl _start _start: movq %rsp, %rbp movq $4, %rax movq $1, %rbx movq 8(%rbp), %rcx # program name address ? movq $5, %rdx int $0x80 movq $1, %rax movq $0, %rbx int $0x80
Where is my mistake?
As stated in the X86_64 ABI: Use the
syscall
instruction instead ofint $0x80
. The Kernel uses different registers in 64 Bit as syscall arguments, and the number assigned for a syscall function varies between i386 and x86_64, too.An example - in german, sorry - can be found here:
http://zygentoma.de/codez/linux_assembler.php
You are loading the correct address into
%rcx
.int 0x80
then invokes the 32-bit syscall interface. That truncates the address to 32 bits, which makes it incorrect. (If you use a debugger and set a breakpoint just after the firstint 0x80
, you will see that it returns with -14 in%eax
, which is-EFAULT
.)The second syscall,
exit
, works OK because the truncation to 32 bits doesn't do any harm in that case.If you want to pass a 64-bit address to a system call, you will have to use the 64-bit syscall interface:
syscall
, notint 0x80
;Here is a working version of your code: