If I compile the following in Ubuntu 16.04 / gcc 7.3
struct VecA {
float data[4];
};
struct VecB {
float x;
float y;
float z;
float w;
};
// Requires stack protection
VecA getA() {return {1.0f, 1.0f, 1.0f, 1.0f};}
// Does not require stack protection
VecB getB() {return {1.0f, 1.0f, 1.0f, 1.0f};}
Like so:
g++ -O3 -c -o result test.cpp
objdump -d result
I get:
0000000000000000 <_Z4getAv>:
0: 48 83 ec 18 sub $0x18,%rsp
4: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
b: 00 00
d: 48 89 44 24 08 mov %rax,0x8(%rsp)
12: 31 c0 xor %eax,%eax
14: f3 0f 7e 05 00 00 00 movq 0x0(%rip),%xmm0 # 1c <_Z4getAv+0x1c>
1b: 00
1c: 48 8b 44 24 08 mov 0x8(%rsp),%rax
21: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
28: 00 00
2a: 75 09 jne 35 <_Z4getAv+0x35>
2c: 66 0f 6f c8 movdqa %xmm0,%xmm1
30: 48 83 c4 18 add $0x18,%rsp
34: c3 retq
35: e8 00 00 00 00 callq 3a <_Z4getAv+0x3a>
3a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000000040 <_Z4getBv>:
40: f3 0f 7e 05 00 00 00 movq 0x0(%rip),%xmm0 # 48 <_Z4getBv+0x8>
47: 00
48: 66 0f 6f c8 movdqa %xmm0,%xmm1
4c: c3 retq
Which "looks" like linux stack protection is being applied to VecA
. A little bit on the defensive side, but I can understand how a compiler could reach that conclusion.
However, This is where i'm getting confused:
I can't reproduce this on godbolt.org, even with stack protection explicitly on. I can make it happen for BOTH functions with -fstack-protector-all
but that's expected, and uninteresting.
https://gcc.godbolt.org/z/ePR98P
Also, it seems that, on my system, explicitly using the stack protector is removing the protection from getA()
g++ -O3 -c -o -fstack-protector result test.cpp
objdump -d result
0000000000000000 <_Z4getAv>:
0: f3 0f 7e 05 00 00 00 movq 0x0(%rip),%xmm0 # 8 <_Z4getAv+0x8>
7: 00
8: 66 0f 6f c8 movdqa %xmm0,%xmm1
c: c3 retq
d: 0f 1f 00 nopl (%rax)
0000000000000010 <_Z4getBv>:
10: f3 0f 7e 05 00 00 00 movq 0x0(%rip),%xmm0 # 18 <_Z4getBv+0x8>
17: 00
18: 66 0f 6f c8 movdqa %xmm0,%xmm1
1c: c3 retq
So my questions are:
Why are my local results that much different than what's being generated on godbolt.org?
Is there a reasonable explanation behind the behavior on my system? Especially regarding -fstack-protector
removing protection.
It is reasonable to assert that both functions should be generating equivalent assembly in optimized code?
Edit:
Full version string:
g++ --version
g++ (Ubuntu 7.3.0-21ubuntu1~16.04) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
The default on Ubuntu's gcc is -fstack-protector-strong
, not -fstack-protector-all
. (The gcc manual lists available options).
https://lwn.net/Articles/584225/ describes "strong". It really likes to protect arrays, but structs with no array members can't be indexed so there's much less chance of overflow.
On Godbolt, that produces stack protection for VecA but not VecB, like on your desktop. (And BTW, you can use g++ -S -masm=intel -O3
to get Intel-syntax, or objdump -drwC -Mintel
, since you linked to Intel-syntax on Godbolt.)
You can use g++ -S -fverbose-asm -O3 foo.cpp
to include comments showing all the implied and explicit options gcc used when compiling. On Godbolt, uncheck the //
icon to not hide asm comments, like this.
# GNU C++14 (GCC-Explorer-Build) version 7.3.0 (x86_64-linux-gnu)
# compiled by GNU C version 5.4.0 20160609, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.16.1-GMP
# GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
# options passed: -fdiagnostics-color=always -imultiarch x86_64-linux-gnu
# -iprefix /opt/compiler-explorer/gcc-7.3.0/bin/../lib/gcc/x86_64-linux-gnu/7.3.0/
# -D_GNU_SOURCE
# /tmp/compiler-explorer-compiler11885-54-1u26why.tdoy/example.cpp
# -masm=intel -mtune=generic -march=x86-64
# -auxbase-strip /tmp/compiler-explorer-compiler11885-54-1u26why.tdoy/output.s
# -g -O3 -std=gnu++14 -fstack-protector-strong -fverbose-asm
# options enabled: -faggressive-loop-optimizations -falign-labels
# -fasynchronous-unwind-tables -fauto-inc-dec -fbranch-count-reg
# -fcaller-saves -fchkp-check-incomplete-type -fchkp-check-read
# -fchkp-check-write -fchkp-instrument-calls -fchkp-narrow-bounds
# -fchkp-optimize -fchkp-store-bounds -fchkp-use-static-bounds
# -fchkp-use-static-const-bounds -fchkp-use-wrappers -fcode-hoisting
# -fcombine-stack-adjustments -fcommon -fcompare-elim -fcprop-registers
# -fcrossjumping -fcse-follow-jumps -fdefer-pop
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With