简体   繁体   English

使用-O2与-O1时Cygwin64 gcc C /汇编器崩溃

[英]Cygwin64 gcc C/assembler crash when using -O2 vs -O1

I have the following code (two files): 我有以下代码(两个文件):

main.c main.c中

#include <stdio.h>

void print();
void asm_print();

int main() {
    asm_print();
    printf("done\n");

    return 0;
}

void print() {
    printf("printing with number: %d\n", 1);
    // printf("printing without number\n");
}

lib.s lib.s

    .intel_syntax noprefix
    .text

    .globl asm_print
asm_print:
    push    rbp
    mov     rbp, rsp
    call    print
    mov     rsp, rbp
    pop     rbp
    ret

expected output 预期产量

printing with number: 1
done

If I compile on linux using gcc4.9.3 and the command line: 如果我使用gcc4.9.3和命令行在Linux上编译:

gcc -O2 -m64 -Wall -Wextra -Werror -std=gnu99 main.c lib.s

everything works fine. 一切正常。 This also works if I use –O1 or –O3. 如果我使用–O1或–O3,这也适用。 If I compile on cygwin64 using gcc4.9.3 and the command line: 如果我使用gcc4.9.3和命令行在cygwin64上编译:

gcc –O1 -m64 -Wall -Wextra -Werror -std=gnu99 main.c lib.s

everything works fine. 一切正常。

If, however, I change the above to use –O2 or –O3, only the first line of output is produced. 但是,如果我将以上内容更改为使用–O2或–O3,则仅生成第一行输出。 If in the function print() I comment out the first line and uncomment the second line, I get the expected output: 如果在函数print()中我注释掉第一行并取消注释第二行,则得到预期的输出:

printing without number
done

regardless of the amount of optimization I use. 不管我使用了多少优化。 Can anyone suggest what is wrong with the code such that I get the expected output regardless of the amount of optimization used on cygwin64? 任何人都可以建议代码出什么问题了,无论我在cygwin64上使用了多少优化,我都能得到预期的输出?

The problem is that the windows 64 bit ABI is different than the 32-bit ABI, and requires the caller to allocate scratch parameter (home) space of 32 bytes on the stack for use by the callee. 问题是Windows 64位ABI与32位ABI不同,并且要求调用者在堆栈上分配32字节的临时参数(宿主)空间,以供被调用者使用。

http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/ https://msdn.microsoft.com/en-us/library/tawsa7cb.aspx http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/ https://msdn.microsoft.com/en-us/library/tawsa7cb.aspx

So what you need to do is to decrement the stack by at least 32 before the call. 因此,您需要做的是在调用之前将堆栈递减至少32。 In addition, x64 requires maintaining the stack pointer on a multiple of 16 bytes. 另外,x64需要将堆栈指针保持在16字节的倍数上。 The 64 bit return address is 8 bytes, so you actually need to move rsp by 40, 56, etc. 64位返回地址是8个字节,因此您实际上需要将rsp移动40、56等。

asm_print:
    push    rbp
    mov     rbp, rsp
    sub     rsp, 40
    call    print
    add     rsp, 40
    pop     rbp
    ret

Presumably, when you call print / printf with just a string constant, it doesn't actually use any of the scratch space, so nothing bad happens. 据推测,当您仅使用字符串常量调用print / printf时,它实际上并没有使用任何暂存空间,因此不会发生任何不良情况。 On the other hand, when you use the %d format, it needs the parameter space, and clobbers your saved registers on the stack. 另一方面,当您使用%d格式时,它需要参数空间,并将保存的寄存器复制到堆栈中。

The reason it works with optimization disabled, is that the print function doesn't use the home space, and allocates parameter space when it calls printf. 禁用优化功能的原因是print函数不使用宿主空间,而是在调用printf时分配参数空间。 If you use -O2, the compiler does tail-call elimination and replaces the "call printf" instruction with a "jmp printf". 如果使用-O2,则编译器会执行尾部调用消除操作,并将“ call printf”指令替换为“ jmp printf”。 This essentially results in re-using the parameter space that was supposed to be allocated by asm_print. 这实质上导致重新使用原本由asm_print分配的参数空间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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