I'm looking for a gcc
command-line flag or other settings to produce GOTOFF
relocations rather than GOT
relocations for my statically linked, position-independent i386 executable. More details on what I was trying below.
My source file g1.s
looks like this:
extern int answer;
int get_answer1() { return answer; }
My other source file g2.s
looks like this:
extern int answer;
int get_answer2() { return answer; }
I compile them with gcc -m32 -fPIE -Os -static -S -ffreestanding -fomit-frame-pointer -fno-unwind-tables -fno-asynchronous-unwind-tables g1.c
for i386.
I get the following assembly output:
.file "g1.c"
.text
.globl get_answer1
.type get_answer1, @function
get_answer1:
call __x86.get_pc_thunk.cx
addl $_GLOBAL_OFFSET_TABLE_, %ecx
movl answer@GOT(%ecx), %eax
movl (%eax), %eax
ret
.size get_answer1, .-get_answer1
.section .text.__x86.get_pc_thunk.cx,"axG",@progbits,__x86.get_pc_thunk.cx,comdat
.globl __x86.get_pc_thunk.cx
.hidden __x86.get_pc_thunk.cx
.type __x86.get_pc_thunk.cx, @function
__x86.get_pc_thunk.cx:
movl (%esp), %ecx
ret
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",@progbits
Here is how to reproduce this behavior online with GCC 7.2: https://godbolt.org/g/XXkxJh
Instead of GOT
above, I'd like to get GOTOFF
, and the movl %(eax), %eax
should disappear, so the assembly code for the function should look like this:
get_answer1:
call __x86.get_pc_thunk.cx
addl $_GLOBAL_OFFSET_TABLE_, %ecx
movl answer@GOTOFF(%ecx), %eax
ret
I have verified that this GOTOFF
assembly version is what works, and the GOT
version doesn't work (because it has an extra pointer indirection).
How can I convince gcc
to generate the GOTOFF
version? I've tried various combinations of -fPIC
, -fpic
, -fPIE
, -fpie
, -pie
, -fno-plt
. None of them worked, all of them made gcc
produce the GOT
version.
I couldn't find any i386-specific flag on https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html or any generic flag here: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
In fact, I'm getting GOTOFF
relocations for "..."
string literals, and I also want to get them for extern
variables.
The final output is a statically linked executable in a custom binary format (for which I've written a GNU ld linker script). There is no dynamic linking and no shared libraries. The address randomization is performed by a custom loader, which is free to load the executable to any address. So I do need position-independent code. There is no per-segment memory mapping: the entire executable is loaded as is, contiguously.
All the documentation I've been able to find online talk about position-independent executables which are dynamically linked, and I wasn't able to find anything useful there.
You have to inform the compiler that global variables will end up in the same loadable module after linking. This is done by specifying their visibility as "hidden", either via the attribute:
__attribute__((visibility("hidden")))
extern int answer;
int get_answer1() { return answer; }
or using the pragma:
#pragma GCC visibility push(hidden)
extern int answer;
// In your case there is no need to restore visibility
// #pragma GCC visibility pop
int get_answer1() { return answer; }
(but note that -fvisibility=hidden
only affects definitions, not declarations, so it's not useful for this purpose)
Since you are linking everything together in the end, you can attach hidden visibility to everything. You can put
#pragma GCC visibility push(hidden)
in a separate file (say vis.h
) and include it everywhere using -include vis.h
. Or even say gcc -include <(echo '#pragma GCC visibility push(hidden)')
if your build system allows that.
Under -flto -fpie -pie
GCC will deduce hidden visibility automatically.