Building libgcc for mcmodel=kernel: Difference between revisions
[unchecked revision] | [unchecked revision] |
(building libgcc with -mcmodel=kernel) |
(improvements. also address mcmodel=large.) |
||
Line 1: | Line 1: | ||
In x86_64 you |
In x86_64, if you link (e.g. through a linker script) your kernel directly to the higher half of the virtual memory, you might want to build the kernel with <tt>-mcmodel=kernel</tt> or <tt>-mcmodel=large</tt>. |
||
Also, if you link with <tt>libgcc</tt> and use <tt>crtbegin.o</tt> and <tt>crtend.o</tt> (see [[Calling_Global_Constructors]]), you might wand to build <tt>libgcc</tt> with <tt>-mcmodel=kernel</tt> or <tt>-mcmodel-large</tt>. |
|||
Otherwise, you may get errors when linking, either from <tt>crtstuff.c</tt> or from kernel code, like: |
|||
If you also link it with crtbegin.o and crtend.o (as said in [[Calling_Global_Constructors]]), you may get errors when linking, like: |
|||
<source lang="text"> |
<source lang="text"> |
||
.../crtbegin.o: In function `deregister_tm_clones': |
.../crtbegin.o: In function `deregister_tm_clones': |
||
Line 22: | Line 25: | ||
</source> |
</source> |
||
One solution is to build a specific cross compiler, used only for kernel compilation (different from the one used for the userland), with <tt>libgcc</tt> (where <tt>crtbegin.o</tt> and <tt>crtend.o</tt> are generated, from <tt>crtstuff.c</tt>) compiled, like the kernel, with <tt>-mcmodel=kernel</tt> or <tt>-mcmodel=large</tt>. As far as we can tell, you could even mix the two modes, e.g.: compile the kernel with <tt>-mcmodel=kernel</tt> and <tt>libgcc</tt> with <tt>-mcmodel=large</tt> or the other way around. |
|||
In this case we also use <tt>-mno-red-zone</tt> to compile <tt>libgcc</tt> because it may be needed for the kernel (see [[Libgcc_without_red_zone]]). |
|||
⚫ | |||
⚫ | |||
⚫ | |||
Starting from the [[GCC_Cross-Compiler]] recipe, and using <tt>TARGET=x86_64-elf</tt>, we can proceed as in the next sections. |
|||
== Compiling libgcc with -mcmodel=kernel == |
|||
⚫ | This may require a workaround. First compile <tt>binutils</tt> as usual, then add the binaries to the <tt>PATH</tt>, and start to compile <tt>gcc</tt>. When compiling <tt>libgcc</tt> with <tt>-mcmodel=kernel</tt>, it will fail. Then patch the <tt>Makefile</tt> to disable <tt>PIC</tt>, repeat and continue: |
||
<source lang='bash'> |
<source lang='bash'> |
||
Line 32: | Line 45: | ||
../gcc-*/configure --target=$TARGET --disable-nls --enable-languages=c,c++ --without-headers --prefix=$PREFIX |
../gcc-*/configure --target=$TARGET --disable-nls --enable-languages=c,c++ --without-headers --prefix=$PREFIX |
||
make all-gcc |
make all-gcc |
||
make all-target-libgcc CFLAGS_FOR_TARGET='-g -O2 -mcmodel=kernel' || true |
make all-target-libgcc CFLAGS_FOR_TARGET='-g -O2 -mcmodel=kernel -mno-red-zone' || true |
||
# will fail with: cc1: error: code model kernel does not support PIC mode |
# will fail with: cc1: error: code model kernel does not support PIC mode |
||
sed -i 's/PICFLAG/DISABLED_PICFLAG/g' $TARGET/libgcc/Makefile |
sed -i 's/PICFLAG/DISABLED_PICFLAG/g' $TARGET/libgcc/Makefile |
||
make all-target-libgcc CFLAGS_FOR_TARGET='-g -O2 -mcmodel=kernel' |
make all-target-libgcc CFLAGS_FOR_TARGET='-g -O2 -mcmodel=kernel -mno-red-zone' |
||
make install-gcc |
make install-gcc |
||
make install-target-libgcc |
make install-target-libgcc |
||
</source> |
</source> |
||
== Compiling libgcc with -mcmodel=large == |
|||
⚫ | |||
First compile <tt>binutils</tt> as usual, then add the binaries to the <tt>PATH</tt>, and start to compile <tt>gcc</tt>. Then compile <tt>libgcc</tt> with <tt>-mcmodel=large</tt>: |
|||
<source lang='bash'> |
|||
# (...) |
|||
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=large -mno-red-zone' |
|||
make install-gcc |
|||
make install-target-libgcc |
|||
</source> |
|||
== See Also == |
|||
⚫ | |||
* [[GCC_Cross-Compiler]] |
|||
* [[Libgcc]] |
|||
* [[Libgcc_without_red_zone]] |
|||
* [[Calling_Global_Constructors]] |
Revision as of 15:54, 5 July 2017
In x86_64, if you link (e.g. through a linker script) your kernel directly to the higher half of the virtual memory, you might want to build the kernel with -mcmodel=kernel or -mcmodel=large.
Also, if you link with libgcc and use crtbegin.o and crtend.o (see Calling_Global_Constructors), you might wand to build libgcc with -mcmodel=kernel or -mcmodel-large.
Otherwise, you may get errors when linking, either from crtstuff.c or from kernel code, 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
One solution is to build a specific cross compiler, used only for kernel compilation (different from the one used for the userland), with libgcc (where crtbegin.o and crtend.o are generated, from crtstuff.c) compiled, like the kernel, with -mcmodel=kernel or -mcmodel=large. As far as we can tell, you could even mix the two modes, e.g.: compile the kernel with -mcmodel=kernel and libgcc with -mcmodel=large or the other way around.
In this case we also use -mno-red-zone to compile libgcc because it may be needed for the kernel (see Libgcc_without_red_zone).
Afterwards, you can compile and link your kernel with the generated cross compiler using -mcmodel=kernel or -mcmodel=large, and -mno-red-zone, and link with crtbegin.o and crtend.o.
These recipes were tested and work at least for GCC 6.3 and GCC 7.1.
Starting from the GCC_Cross-Compiler recipe, and using TARGET=x86_64-elf, we can proceed as in the next sections.
Compiling libgcc with -mcmodel=kernel
This may require a workaround. 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 -mno-red-zone' || 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 -mno-red-zone'
make install-gcc
make install-target-libgcc
Compiling libgcc with -mcmodel=large
First compile binutils as usual, then add the binaries to the PATH, and start to compile gcc. Then compile libgcc with -mcmodel=large:
# (...)
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=large -mno-red-zone'
make install-gcc
make install-target-libgcc