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