C++ 为什么我的混合(C+;+;,asm)程序会给我一个分段错误?

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

下面是一个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_remote_server basic-assm]$ ./test
Segmentation fault
[me@my_remote_server basic-assm]$

为什么我的程序会给我一个分段错误?

我已经根据@MichaelPetch和@PeterCordes的评论进行了修改,并从以下源代码中获得了所需的输出:

函数
printf之后,您没有将4添加到ESP以从堆栈中删除指向
hello
的指针?而且ECX是一个易失性寄存器,可能会被printf破坏,因此您应该使用一个寄存器(非易失性),如EBX。在调用printfTry
gdb
之前,您可能还需要在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