简体   繁体   中英

linux asm x86 producing segfault

I am learning a bit of assembler for linux and I have this example program that is just supposed to call the write syscall and print 'Hello, World!'on the screen, however it produces a segfault. I'm learning in my free time, not homework, I no longer go to school!

Can anybody see anything wrong with this code?

xor eax,eax
xor ebx,ebx
xor ecx,ecx
xor edx,edx
jmp short string
code:
pop     ecx
mov     bl,1
mov     dl,13
mov     al,4
int     0x80
dec     bl
mov     al,1
int     0x80
string:
call code
db      'Hello, World!'

Works for me. Here's what I did (note, I'm on a 64-bit machine so I have an extra flag to create a 32-bit binary):

test.asm

_start:
xor eax,eax
xor ebx,ebx
xor ecx,ecx
xor edx,edx
jmp short string
code:
pop     ecx
mov     bl,1
mov     dl,13
mov     al,4
int     0x80
dec     bl
mov     al,1
int     0x80
string:
call code
db      'Hello, World!'

commands:

$ nasm -felf test.asm -o test.o
$ gcc -m32 -nostdlib -nostdinc test.o -o test

which produced a warning, but that's ok.

/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.1/../../../../x86_64-pc-linux-gnu/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080

Then I ran:

$ ./test

and it indeed output "Hello, World!" (without a newline). No segfault.

I'm not very familiar with linux assembly, but here is a guess:

When calling APIs, you have to use a specific calling convention. One of the things that are specified by a convention is the list of registers that are preserved across the API call. In your case, the error is using dec bl instead of xor ebx, ebx . Because bl is used as input parameter, it's quite unlikely that it will be preserved. The same for mov al, 1 , it's safer to write mov eax, 1

And I'm agree with @Greg Hewgil, your way of obtaining the address of string is quite unusual. The common way to write position independent code with strings is this:

...
call my_print
db 'hello world!', 0
...

my_print:
pop ecx
xor edx, edx
lp:
cmp byte [ecx + edx], 0
inc edx
jne lp
lea eax, [ecx + edx] 
push eax // return address
dec edx
mov eax, 4
int 0x80
ret

This code is likely to crash if compiled and run under a 64bit kernel. The 64bit return address will not fit into the 32bit ecx register, you would have to pop rcx instead. Furthermore, this code uses the 32bit API, which may not be available under a 64bit kernel. You should use the 64bit API instead, as described in my blog post: x86-64 assembly on Linux .

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM