linux asm x86生成段错误

时间:2010-12-15 22:23:39

标签: linux assembly x86

我正在学习一些Linux的汇编程序,我有这个示例程序,它应该调用write syscall并在屏幕上打印“Hello,World!”,但它会产生段错误。我在空闲时间学习,而不是做作业,我不再去上学了!

有人能看到这段代码有什么问题吗?

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!'

3 个答案:

答案 0 :(得分:2)

适合我。这就是我所做的(注意,我在64位机器上,所以我有一个额外的标志来创建一个32位二进制文​​件):

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!'

命令:

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

产生了警告,但没关系。

/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

然后我跑了:

$ ./test

确实输出"Hello, World!"(没有换行符)。没有段错误。

答案 1 :(得分:1)

我对linux程序集并不是很熟悉,但这是猜测:

调用API时,必须使用特定的调用约定。约定指定的内容之一是在API调用中保留的寄存器列表。在您的情况下,错误是使用dec bl而不是xor ebx, ebx。因为bl用作输入参数,所以它不太可能被保留。 mov al, 1也是如此,写mov eax, 1

更安全

我同意@Greg Hewgil,你获取字符串地址的方式很不寻常。使用字符串编写与位置无关的代码的常见方法是:

...
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

答案 2 :(得分:0)

如果编译并在64位内核下运行,此代码可能会崩溃。 64位返回地址不适合32位ecx寄存器,你必须弹出rcx。此外,此代码使用32位API,在64位内核下可能无法使用。您应该使用64位API,如我的博文中所述:x86-64 assembly on Linux