Building libgcc for mcmodel=kernel: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
(building libgcc with -mcmodel=kernel)
 
(improvements. also address mcmodel=large.)
Line 1: Line 1:
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.
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>


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):
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]]).
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:

Afterwards, you can compile and link your kernel with the generated cross compiler using <tt>-mcmodel=kernel</tt> or <tt>-mcmodel=large</tt>, and <tt>-mno-red-zone</tt>, and link with <tt>crtbegin.o</tt> and <tt>crtend.o</tt>.

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 <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 ==
Then you can compile and link your kernel with the generated cross compiler using -mcmodel=kernel and linking with crtbegin.o and crtend.o.

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 ==
This procedure was tested and works at least for GCC 6.3 and GCC 7.1
* [[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

See Also