[英]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.