I've very recently decided to give x86-64 assembly a go. I've run into a problem with displaying argv
Yes the code I've written is bad, and it makes assumptions and doesn't check for errors, I know, but I really don't think that's the cause of this problem.
Here's my programme boiled down to its core.
.globl _start
.text
main:
_start:
movl $10,%edx # No. of chars to write
movq 16(%rsp),%rcx # argv[1]
movl $1,%ebx # stdout
movl $4,%eax # write
int $0x80
movl $0,%ebx
movl $1,%eax
int $0x80
I run my programme ./myprog helloworldddddddddd
So argv[0] =./myprog and argv[1] = helloworlddddddddddd or whatever I typed
My programme should write the first ten characters in argv[1] to stdout.
Except it doesn't work. Write is returning -14, which is error EFAULT? Which means bad address.
So I wrote this instead
.globl _start
.text
main:
_start:
movq 16(%rsp),%rax
movq $bob,%rbx
subq %rcx,%rcx
.Lloop:
movb (%rax,%rcx),%dl
movb %dl,(%rbx,%rcx)
cmpb $0,%dl
je .Ldone
addq $1,%rcx
jmp .Lloop
.Ldone: movl $10,%edx
movq $bob,%rcx
movl $1,%ebx
movl $4,%eax
int $0x80
movl $0,%ebx
movl $1,%eax
int $0x80
.comm bob,50
It copies argv[1] to an area of memory I've called bob, and then tries to write this copy to stdout. I'm sure it is abysmal x86, but it works. If I compile and run the programme, it outputs whatever was in argv[1]
Finally I wrote this in C
#include <unistd.h>
int main(int argc, char **argv) {
write(1,argv[1],10);
return 0;
}
Which is more like my first programme than my second, but also works. By this stage I am totally baffled.
So it seems to me that the "write" system call isn't allowed to read my programme's argv array, yet it can read a copy. Oh, and if I just write it in C, it works. This seems totally bizarre. Can anyone tell me what's going on, and why?
Edit:
It's been pointed out that I was using mixed 32 bit and 64 bit code. so I changed to 100% 64bit.
First programme:
.globl _start
.text
main:
_start:
movl $10,%edx # No. of chars to write
movl 16(%rsp),%esi # argv[1]
movl $1,%edi # stdout
movl $1,%eax # write
syscall
movl $0,%edi
movl $60,%eax
syscall
Second programme:
.globl _start
.text
main:
_start:
movq 16(%rsp),%rax
movq $bob,%rbx
subq %rcx,%rcx
.Lloop:
movb (%rax,%rcx),%dl
movb %dl,(%rbx,%rcx)
cmpb $0,%dl
je .Ldone
addq $1,%rcx
jmp .Lloop
.Ldone: movl $10,%edx # No. of chars to write
movq $bob,%rsi # buffer
movl $1,%edi # stdout
movl $1,%eax # write
syscall
movl $0,%edi # return 0
movl $60,%eax # exit
syscall
.comm bob,50
Still the same error, the first programme still fails to work even though it's now 64bit, and the second programme still works, even though it too is now 64bit
Strace for 64bit version of first programme. (The one that doesn't work):
execve("./Myprog", ["./Myprog", "bananablahblah"], [/* 46 vars */]) = 0
write(1, 0x1491f543, 10) = -1 EFAULT (Bad address)
_exit(0) = ?
+++ exited with 0 +++
You are making three major errors here:
You are confusing main
with _start
. They are not synonymous — the standard C library implementation of _start
does some important initialization before calling main
. You probably don't want to try to reimplement _start
— don't define it in your executable; link against libc to get it.
You are trying to use 32-bit system calls ( int $0x80
) in a 64-bit executable. This does not work correctly; in particular, it cannot read memory that exists above the 4GB boundary, including on your stack! You must use the syscall
instruction to make 64-bit system calls. Keep in mind, however, that it uses a slightly different calling convention, and uses different call numbers!
You are using 32-bit instructions and registers in some locations where you need the 64-bit equivalents. This sometimes works for low pointers and values, but truncates some other values. Make a habit of always using 64-bit instructions and registers in 64-bit code unless you specifically need something smaller (eg, an 8-bit register for a char
).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.