Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
linux asm x86产生故障_Linux_Assembly_X86 - Fatal编程技术网

linux asm x86产生故障

linux asm x86产生故障,linux,assembly,x86,Linux,Assembly,X86,我正在学习一点linux汇编程序,我有一个示例程序,它应该调用write系统调用并打印“Hello,World!”但是,在屏幕上,它会产生segfault。我在空闲时间学习,不是做作业,我不再上学了 有人能看出这个代码有什么问题吗 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 0x8

我正在学习一点linux汇编程序,我有一个示例程序,它应该调用write系统调用并打印“Hello,World!”但是,在屏幕上,它会产生segfault。我在空闲时间学习,不是做作业,我不再上学了

有人能看出这个代码有什么问题吗

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

我对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

我对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

如果在64位内核下编译和运行,此代码可能会崩溃。64位返回地址将不适合32位ecx寄存器,您必须弹出rcx。此外,此代码使用32位API,在64位内核下可能不可用。您应该改用64位API,如我的博客文章所述:。

如果在64位内核下编译和运行,此代码可能会崩溃。64位返回地址将不适合32位ecx寄存器,您必须弹出rcx。此外,此代码使用32位API,在64位内核下可能不可用。您应该改用64位API,正如我在博客文章中所述:。

对我有用。以下是我所做的(注意,我在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

它确实输出了
“你好,世界!”
(没有换行符)。没有故障。

适合我。以下是我所做的(注意,我在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

它确实输出了
“你好,世界!”
(没有换行符)。没有segfault。

我必须说,这是一种相当不寻常的方法,将字符串地址加载到
ecx
中。它是先产生输出然后产生segfault,还是在产生segfault之前不产生输出?@Greg:同意,尽管这是编写位置无关外壳代码的最常见方法之一……我必须说,将字符串的地址加载到
ecx
,这是一种相当不寻常的方法。它是先产生输出,然后产生segfault,还是在segfaulting之前不产生输出?@Greg:同意,尽管这是编写位置无关外壳代码的最常用方法之一……您的“常用”方法与OP没有特别不同。您仍然在数据之前执行
jmp
,然后执行
调用
右回,最后执行
pop
将数据的地址输入寄存器。唯一的区别是在所有这些之后如何使用寄存器。@Evan Teran:区别在于字符串出现在使用它的地方,长度是自动计算的。我几乎不能调用搜索
'\0'
的循环“自动”。你的“通用”方法与OP没有特别不同。您仍然在数据之前执行
jmp
,然后执行
调用
右回,最后执行
pop
将数据的地址输入寄存器。唯一的区别是在所有这些之后如何使用寄存器。@Evan Teran:区别在于字符串出现在使用它的地方,并且长度是自动计算的。我几乎无法调用搜索
'\0'
的循环“自动”。看起来这就是问题所在。看起来这就是问题所在。