簡體   English   中英

使用-O2與-O1時Cygwin64 gcc C /匯編器崩潰

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

我有以下代碼(兩個文件):

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

    .intel_syntax noprefix
    .text

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

預期產量

printing with number: 1
done

如果我使用gcc4.9.3和命令行在Linux上編譯:

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

一切正常。 如果我使用–O1或–O3,這也適用。 如果我使用gcc4.9.3和命令行在cygwin64上編譯:

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

一切正常。

但是,如果我將以上內容更改為使用–O2或–O3,則僅生成第一行輸出。 如果在函數print()中我注釋掉第一行並取消注釋第二行,則得到預期的輸出:

printing without number
done

不管我使用了多少優化。 任何人都可以建議代碼出什么問題了,無論我在cygwin64上使用了多少優化,我都能得到預期的輸出?

問題是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

因此,您需要做的是在調用之前將堆棧遞減至少32。 另外,x64需要將堆棧指針保持在16字節的倍數上。 64位返回地址是8個字節,因此您實際上需要將rsp移動40、56等。

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

據推測,當您僅使用字符串常量調用print / printf時,它實際上並沒有使用任何暫存空間,因此不會發生任何不良情況。 另一方面,當您使用%d格式時,它需要參數空間,並將保存的寄存器復制到堆棧中。

禁用優化功能的原因是print函數不使用宿主空間,而是在調用printf時分配參數空間。 如果使用-O2,則編譯器會執行尾部調用消除操作,並將“ call printf”指令替換為“ jmp printf”。 這實質上導致重新使用原本由asm_print分配的參數空間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM