C++ 为什么我的混合(C+;+;,asm)程序会给我一个分段错误?
下面是一个x86汇编程序,由NASM在64位CentOS下通过远程终端进行汇编,该终端没有gdb,也不允许安装 main.cpp 生成文件 输出:C++ 为什么我的混合(C+;+;,asm)程序会给我一个分段错误?,c++,assembly,makefile,x86,nasm,C++,Assembly,Makefile,X86,Nasm,下面是一个x86汇编程序,由NASM在64位CentOS下通过远程终端进行汇编,该终端没有gdb,也不允许安装 main.cpp 生成文件 输出: [me@my_remote_server basic-assm]$ make nasm -o func.o -f elf -g -l func.lst func.asm g++ -m32 -c -g -O0 main.cpp &> errors.txt g++ -m32 -g -o test main.o func.o [me@my_r
[me@my_remote_server basic-assm]$ make
nasm -o func.o -f elf -g -l func.lst func.asm
g++ -m32 -c -g -O0 main.cpp &> errors.txt
g++ -m32 -g -o test main.o func.o
[me@my_remote_server basic-assm]$ ./test
Segmentation fault
[me@my_remote_server basic-assm]$
为什么我的程序会给我一个分段错误?我已经根据@MichaelPetch和@PeterCordes的评论进行了修改,并从以下源代码中获得了所需的输出: 函数
printf之后,您没有将4添加到ESP以从堆栈中删除指向
hello
的指针?而且ECX是一个易失性寄存器,可能会被printf破坏,因此您应该使用一个寄存器(非易失性),如EBX。在调用printfTrygdb
之前,您可能还需要在16字节边界上对齐堆栈,您将命令键入为gbd
。尝试在没有调试器的情况下学习asm是一种巨大的时间浪费,当您知道从何处开始查找问题时,许多错误就会变得简单。如果您使用GDB,或者至少生成一个核心文件并在另一台机器上使用GDB进行调试,问题会好得多。je end\u while\u loop\lt
跳转或跳转到下一条指令,不管是哪条指令。此时,您的ret
会将堆栈中的任何内容弹出到EIP中,但它不是您的返回地址。像普通人一样使用jne while\u loop\lt
,而不是有条件地跳过jmp
。另外,您可以在不保存/恢复的情况下销毁调用方的ebx
,因此如果调用方没有崩溃,您就很幸运了。也可以调用printf
,ESP未按16对齐。(在调用此函数的调用之前,它被对齐了16个字节,因此重新对齐它需要12个字节的ESP偏移量,但您只需执行4个字节(1次推送)。)保存/恢复EBX会让您更接近,然后您只需在函数序言/尾声中再进行一次虚拟推送/弹出。(或sub/add esp,4
)。尝试用C编写它,并查看gcc-O2-m32-S-masm=intel
(它使用类似masm的GAS语法,而不是NASM语法,但非常接近)的输出。另请参阅。尽管gcc可能会完全展开5个迭代循环。也许只需将循环计数更改为10000,就可以看到gcc如何在遵守ABI/调用约定的同时优化函数。
extern printf
section .data
hello: db 'Hello World!', 20
helloLen: equ $-hello
section .text
global looping_test
looping_test: ; print "Hello World" 5 times
mov ecx, 0; initialize the counter
while_loop_lt:
push hello
call printf
inc ecx
cmp ecx, 4; This is exit control loop.
je end_while_loop_lt
end_while_loop_lt:
ret
CC = g++
ASMBIN = nasm
all : asm cc link
asm :
$(ASMBIN) -o func.o -f elf -g -l func.lst func.asm
cc :
$(CC) -m32 -c -g -O0 main.cpp &> errors.txt
link :
$(CC) -m32 -g -o test main.o func.o
clean :
rm *.o
rm test
rm errors.txt
rm func.lst
[me@my_remote_server basic-assm]$ make
nasm -o func.o -f elf -g -l func.lst func.asm
g++ -m32 -c -g -O0 main.cpp &> errors.txt
g++ -m32 -g -o test main.o func.o
[me@my_remote_server basic-assm]$ ./test
Segmentation fault
[me@my_remote_server basic-assm]$
extern printf
section .data
hello: db "Hello World!", 20
helloLen: equ $-hello
section .text
global looping_test
looping_test: ; print "Hello World" 5 times
mov ebx, 0 ; initialize the counter
while_loop_lt:
push hello
call printf
add esp, 4
inc ebx
cmp ebx, 5 ; This is exit control loop.
je end_while_loop_lt
jmp while_loop_lt
end_while_loop_lt:
ret