Building libgcc for mcmodel=kernel

Revision as of 22:44, 4 July 2017 by Rod (talk | contribs) (building libgcc with -mcmodel=kernel)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

In x86_64 you might want to build the kernel with -mcmodel=kernel if it will be located and linked to the higher half of the virtual memory.

If you also link it with crtbegin.o and crtend.o (as said in Calling_Global_Constructors), you may get errors when linking, like:

.../crtbegin.o: In function `deregister_tm_clones':
crtstuff.c:(.text+0x2): relocation truncated to fit: R_X86_64_32 against symbol `__TMC_END__' defined in .dtors section in ...
crtstuff.c:(.text+0x1d): relocation truncated to fit: R_X86_64_32 against `.tm_clone_table'
.../crtbegin.o: In function `register_tm_clones':
crtstuff.c:(.text+0x31): relocation truncated to fit: R_X86_64_32 against symbol `__TMC_END__' defined in .dtors section in ...
crtstuff.c:(.text+0x5f): relocation truncated to fit: R_X86_64_32 against `.tm_clone_table'
.../crtbegin.o: In function `__do_global_dtors_aux':
crtstuff.c:(.text+0x88): relocation truncated to fit: R_X86_64_32 against symbol `__DTOR_END__' defined in .dtors section in ...
.../crtend.o
crtstuff.c:(.text+0x8e): relocation truncated to fit: R_X86_64_32 against `.dtors'
crtstuff.c:(.text+0xdb): relocation truncated to fit: R_X86_64_32 against `.eh_frame'
.../crtbegin.o: In function `frame_dummy':
crtstuff.c:(.text+0x10c): relocation truncated to fit: R_X86_64_32 against `.bss'
crtstuff.c:(.text+0x111): relocation truncated to fit: R_X86_64_32 against `.eh_frame'
.../crtend.o: In function `__do_global_ctors_aux':
crtstuff.c:(.text+0x13): relocation truncated to fit: R_X86_64_32 against `.ctors'
collect2: error: ld returned 1 exit status

The solution is to build a specific cross compiler, with libgcc (where crtbegin.o and crtend.o are generated, from crtstuff.c) compiled, like the kernel, with -mcmodel=kernel. This may require a workaround, that might be (starting from the GCC_Cross-Compiler recipe):

First compile binutils as usual, then add the binaries to the PATH, and start to compile gcc. When compiling libgcc with -mcmodel=kernel, it will fail. Then patch the Makefile to disable PIC, repeat and continue:

# (...)
mkdir build
cd build
../gcc-*/configure --target=$TARGET --disable-nls --enable-languages=c,c++ --without-headers --prefix=$PREFIX
make all-gcc
make all-target-libgcc CFLAGS_FOR_TARGET='-g -O2 -mcmodel=kernel' || true
# will fail with: cc1: error: code model kernel does not support PIC mode
sed -i 's/PICFLAG/DISABLED_PICFLAG/g' $TARGET/libgcc/Makefile
make all-target-libgcc CFLAGS_FOR_TARGET='-g -O2 -mcmodel=kernel'
make install-gcc
make install-target-libgcc

Then you can compile and link your kernel with the generated cross compiler using -mcmodel=kernel and linking with crtbegin.o and crtend.o.

This procedure was tested and works at least for GCC 6.3 and GCC 7.1