Page 1 of 1

Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 2:27 am
by robbiedobbie
Hey all,

I've been working on porting my kernel (which is still in very early stages), to 64bit so that I don't have to go through all the trouble later. I've been succesfull in getting it to switch from 32 to 64 (running from higher half), and running my c/c++ code. However, when I try to link crtbegin.o and crtend.o into the kernel, to get the global constructors working, I get linker errors.

They are being caused by the higher half kernel, but I don't know how to solve it.

The command used to link:

Code: Select all

/home/rob/opt/cross/bin/x86_64-elf-g++ -T linker.ld -nostdlib -ffreestanding -z max-page-size=0x1000 -g -ggdb -o bin/kernel src/bootstrap.o src/start64.o src/crti.o /home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtbegin.o src/main.o /home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtend.o src/crtn.o -lgcc
The error it gives:

Code: Select all

/home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtbegin.o: In function `deregister_tm_clones':
crtstuff.c:(.text+0x1): relocation truncated to fit: R_X86_64_32 against symbol `__TMC_END__' defined in .jcr section in bin/kernel
crtstuff.c:(.text+0x8): relocation truncated to fit: R_X86_64_32S against `.tm_clone_table'
crtstuff.c:(.text+0x21): relocation truncated to fit: R_X86_64_32 against `.tm_clone_table'
/home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtbegin.o: In function `register_tm_clones':
crtstuff.c:(.text+0x41): relocation truncated to fit: R_X86_64_32 against symbol `__TMC_END__' defined in .jcr section in bin/kernel
crtstuff.c:(.text+0x49): relocation truncated to fit: R_X86_64_32S against `.tm_clone_table'
crtstuff.c:(.text+0x6f): relocation truncated to fit: R_X86_64_32 against `.tm_clone_table'
/home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtbegin.o: In function `__do_global_dtors_aux':
crtstuff.c:(.text+0x8f): relocation truncated to fit: R_X86_64_32 against symbol `__DTOR_END__' defined in .dtors section in /home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtend.o
crtstuff.c:(.text+0x96): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0xc6): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0xe6): relocation truncated to fit: R_X86_64_32 against `.eh_frame'
crtstuff.c:(.text+0xeb): additional relocation overflows omitted from the output
collect2: error: ld returned 1 exit status
My linker.ld:

Code: Select all

kernel_VMA = 0xffff800000000000;
kernel_LMA = 0x100000;

/* start from the entry point */
ENTRY(_bootstrap)
SECTIONS
{
    . = kernel_LMA;

    .text_boot :
    {
        src/bootstrap.o (.text)
    }

    . = . + kernel_VMA;

    .text : AT(ADDR(.text) - kernel_VMA + kernel_LMA)
    {
        code = .;
        *(.text)
		*(.text*)

        /* read only data */
        *(.rodata*)
        *(.rdata*)

        . = ALIGN(4096);
    }

    .data : AT(ADDR(.data) - kernel_VMA + kernel_LMA)
    {
        data = .;
        *(.data)

        . = ALIGN(4096);
    }

    _end_data = .;

    .bss : AT(ADDR(.bss) - kernel_VMA + kernel_LMA)
    {
        *(.bss)
        . = ALIGN(4096);
    }

    .ehframe : AT(ADDR(.ehframe) - kernel_VMA + kernel_LMA)
    {
        ehframe = .;
        *(.ehframe)
        . = ALIGN(4096);
    }

    _end = .;
}
I've tried using -mcmodel=kernel and -mcmodel=medium as switches to the linker, but this didn't make any difference.

Does anyone have an idea how to solve this?

Thank you in advance,

Rob

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 2:41 am
by Combuster
Why are the constructor sections missing from your linker script?

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 2:51 am
by robbiedobbie
That's stupid of me #-o

I tried adding them by adding

Code: Select all

        *(.ctor*)
        *(.dtor*)
to the data section of the linkerscript, but it does not change anything. Am I missing some other sections?

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 4:26 am
by xenos
For linking your kernel in that address range you need to tell GCC to use the large memory model (add -mcmodel=large). Otherwise it will generate instructions that use 32 bit addresses (which are smaller), and ld cannot fill these with high 64 bit memory addresses. In the large memory model GCC will use 64 bit addresses by default.

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 4:35 am
by robbiedobbie
I didn't try the large option before, since I though it wasn't implemented yet.

Unfortunately though it doesn't work either. The linker doesn't give an error that it's not implemented, but it still gives the relocation truncated errors.

Now what I find really weird, is that lots of the errors result from sections like jcr, which are for java code according to the elf documentation?

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 5:29 am
by Owen
Code outside the -2GB to 2GB range of the address space requires complex additional considerations (that is, the compiler needs to insert lots of MOVABS instructions and such in order to get full arbitrary 64-bit addresses into registers). The default CRT files are not built with these settings.

Place your kernel in the -2GB region of the address space, i.e. 0xFFFFFFFF80000000 (Build it with -mcmodel=kernel)

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 5:43 am
by xenos
What does your compiler command line look like?

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 5:59 am
by robbiedobbie
@Owen
Hmm, I will try with the smaller addresses, but I would prefer using this bigger address.

@XenOS
Currently my whole makefile looks like this: CC=/home/rob/opt/cross/bin/x86_64-elf-gcc

Code: Select all

CXX=/home/rob/opt/cross/bin/x86_64-elf-g++
ASM=yasm

ASMFLAGS=-f elf64
CXXFLAGS= -O2 -std=c++11 -ffreestanding -Wall -Wextra -fno-exceptions -fno-rtti -nostdlib -mcmodel=large
LDFLAGS=-T linker.ld -nostdlib -ffreestanding -z max-page-size=0x1000 -mcmodel=large

LDFLAGSDBG= -g -ggdb
CFLAGSDBG= -g -ggdb
CXXFLAGSDBG= -g -ggdb
ASMFLAGSDBG= -g dwarf2

CRTBEGIN_OBJ:=$(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
CRTEND_OBJ:=$(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)
OBJFILES=src/main.o

default: release

all: clean release

debug: LDFLAGS+=${LDFLAGSDBG}
debug: ASMFLAGS+=${ASMFLAGSDBG}
debug: CFLAGS+=$(CFLAGSDBG)
debug: CXXFLAGS+=$(CXXFLAGSDBG)
debug: release

release: src/bootstrap.o src/start64.o src/crti.o ${OBJFILES} src/crtn.o
	mkdir -p bin
	${CXX} ${LDFLAGS} -o bin/kernel src/bootstrap.o src/start64.o src/crti.o ${CRTBEGIN_OBJ} ${OBJFILES} ${CRTEND_OBJ} src/crtn.o -mcmodel=large -lgcc 

.s.o:
	${ASM} ${ASMFLAGS} -o $@ $<
.c.o:
	${CXX} ${CXXFLAGS} -o $@ -c $<

clean:
	rm -Rf src/*.o

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 6:22 am
by bluemoon
robbiedobbie wrote:Hmm, I will try with the smaller addresses, but I would prefer using this bigger address.
May I know the reason?

note that mcmodel=kernel only require the static code to put in the address range. It do not restrict the use of 64-bit data pointers and function pointers.

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 6:28 am
by robbiedobbie
There was no real reason for the kernel design or something. It was more like, it should be possible, so I wanna try it :P

Re: Linking crt*.o in 64bit kernel image

Posted: Sun May 18, 2014 7:22 am
by robbiedobbie
Ok, so I have been changing everything to the other base adress, but still have similar issues.

I'm now using -mcmodel=kernel on the compilation of my c files and on my link command. There are less errors, but the following remain:

Code: Select all

/home/rob/opt/cross/bin/x86_64-elf-g++ -T linker.ld -nostdlib -ffreestanding -z max-page-size=0x1000 -mcmodel=kernel -g -ggdb -o bin/kernel src/bootstrap.o src/start64.o src/crti.o /home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtbegin.o src/main.o /home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtend.o src/crtn.o -lgcc 
/home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtbegin.o: In function `deregister_tm_clones':
crtstuff.c:(.text+0x1): relocation truncated to fit: R_X86_64_32 against symbol `__TMC_END__' defined in .jcr section in bin/kernel
crtstuff.c:(.text+0x21): relocation truncated to fit: R_X86_64_32 against `.tm_clone_table'
/home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtbegin.o: In function `register_tm_clones':
crtstuff.c:(.text+0x41): relocation truncated to fit: R_X86_64_32 against symbol `__TMC_END__' defined in .jcr section in bin/kernel
crtstuff.c:(.text+0x6f): relocation truncated to fit: R_X86_64_32 against `.tm_clone_table'
/home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtbegin.o: In function `__do_global_dtors_aux':
crtstuff.c:(.text+0x8f): relocation truncated to fit: R_X86_64_32 against symbol `__DTOR_END__' defined in .dtors section in /home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtend.o
crtstuff.c:(.text+0xe6): relocation truncated to fit: R_X86_64_32 against `.eh_frame'
/home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtbegin.o: In function `frame_dummy':
crtstuff.c:(.text+0x10f): relocation truncated to fit: R_X86_64_32 against `.bss'
crtstuff.c:(.text+0x114): relocation truncated to fit: R_X86_64_32 against `.eh_frame'
crtstuff.c:(.text+0x11e): relocation truncated to fit: R_X86_64_32 against `.jcr'
/home/rob/opt/cross/lib/gcc/x86_64-elf/4.9.0/crtend.o: In function `__do_global_ctors_aux':
crtstuff.c:(.text+0x6): relocation truncated to fit: R_X86_64_32 against `.ctors'
collect2: error: ld returned 1 exit status
Since I figgured that the crtstuff.c is compiled with the compilation of the crosscompiler, I also tried to compile the whole crosscompiler again with -mcmodel=kernel, which didn't result in any improvements.

It looks like my crtbegin.o is simply incompatible with memory adresses like this. How can I solve this?

Re: Linking crt*.o in 64bit kernel image

Posted: Tue Sep 02, 2014 12:39 pm
by PinkyNoBrain
Hi robbiedobbie,

I encountered the same issue myself when trying to add c++ global constructor calling to my 64bit higher half kernel and think i may have found a solution :D

Its a bit ugly but this is what i did:
  • (as you say) crtbegin.o and crtend.o are built from crtstuff.c during compilation of the crosscompiler so i rebuilt my crosscompiler and piped the build output to a file
  • I borrowed crtstuff.c and included it in my own source files
  • I greped the build output file for crtstuff.c which gave me the two commands used to build it (once for crtbegin.o and once for crtend.o)
  • I added entries fro crtbegin.o and crtend.o to my makefile, building with the commands identified above
  • I had to update some of the -I statements in the compile commands to include some directories from the gcc source bundle
  • I also added -mcmodel=kernel to both command
  • After all that i was able to build my own crtbegin.o and crtend.o and use them to call my global constrctuors :D
This is not an ideal solution but i think its preferable to remaking the whole of libgcc with mcmodel=kernel. Hopefully its clear and it works for you.

Let me know if you need any more details,

Thanks,

Pinky

Re: Linking crt*.o in 64bit kernel image

Posted: Sat Mar 21, 2015 9:08 am
by robbiedobbie
Hi PinkyNoBrain,

I never noticed your reply, but I want to thank you, since it actually did help!

I started over from scratch recently, and again encountered the problem of having a higher half 64bit kernel and linking crtbegin.o and crtend.o. I got it working by seperately compiling crtstuff.c with mcmodel=kernel./

Thank you!

Re: Linking crt*.o in 64bit kernel image

Posted: Mon Apr 13, 2015 4:03 am
by nbdd0121
I found this when I encountered the same problem, and I eventually solved this. I just post here for a note: what I do is add CFLAGS_FOR_TARGET='-g -O2 -mcmodel=large' when making all-target-libgcc.