How to link 32- and 64-bit code together?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
aerkiaga
Posts: 4
Joined: Wed Mar 18, 2020 7:23 am

How to link 32- and 64-bit code together?

Post by aerkiaga »

So, I'm compiling my 32-bit bootstrap code with the following commands:

Code: Select all

i686-elf-gcc -c $(C_FILE) -o $(O_FILE) -std=gnu99 -ffreestanding -O2 -Wall -Wextra -DKERNEL_MODE=64 #for C source files
i686-elf-gcc $(S_FILE) -o $(O_FILE) -ffreestanding -nostdlib -r -DKERNEL_MODE=64 #for .S assembly files
i686-elf-as $(S_FILE) -o $(O_FILE) #for .s assembly files
i686-elf-gcc -T boot32.ld -o boot32.o -ffreestanding -O2 -nostdlib -r $(OBJ32) -lgcc
Then compiling my 64-bit kernel with:

Code: Select all

x86_64-elf-gcc -c $(C_FILE) -o $(O_FILE) -std=gnu99 -ffreestanding -O2 -Wall -Wextra -DKERNEL_MODE=64 #for C source files
x86_64-elf-gcc $(S_FILE) -o $(O_FILE) -ffreestanding -nostdlib -r -DKERNEL_MODE=64 #for .S assembly files
x86_64-elf-objcopy -O elf64-x86-64 -B i386 -I binary $(BINARY_DATA) $(BINARY_OBJECT) #for binary data
Finally, I link everything with:

Code: Select all

x86_64-elf-gcc -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib boot32.o $(OBJ64) -lgcc
At which point I get an error message:

Code: Select all

[...]x86_64-elf/bin/ld: i386 architecture of input file `boot32.o' is incompatible with i386:x86-64 output
And then, a couple undefined references in boot32.o to symbols defined in the 64-bit code. Now, what is the best way to link this together? I know I could manually parse the 64-bit symbol table, or even use objcopy somehow to move the 64-bit sections into the 32-bit object file by hand, with the two exported symbols at defined addresses. But this looks extremely ugly to do, and I think I'm missing something about 32- and 64-bit executable formats.

Also, I'm using Multiboot, so the bootstrap code *must* be 32-bit, and the entire image loadable by the bootloader.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: How to link 32- and 64-bit code together?

Post by pvc »

Compile everything as 64 bit. Link as 64 bit too. In your .S files add .code32 directive in places where you have 32 bit code and .code64 where you have 64 bit code (I am not very familiar with GNU assembler, but I think, this is how you do it). There is even .code16 directive if you need it. Loader file can be either raw binary, 32 bit ELF or 64 bit ELF. QEMU's built-in loader can't load 64 bit ELF files (not without a patch), but GRUB can. You will still start in 32 bit mode, but ELF file itself can be 64 bit.
Try lower half kernel first, since high half one needs some extra linker script tweaks and compiler flags.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How to link 32- and 64-bit code together?

Post by iansjack »

Have a look at this wiki article, but be sure to read the linked material too: https://wiki.osdev.org/Creating_a_64-bit_kernel

I use Grub to start a 32-bit "kernel" which then jumps to a 64-bit module, as described in the article. Some information needs to be passed to the 64-bit code; I do this in a structure located at a fixed address (which can be overwritten once the data has been transferred).
aerkiaga
Posts: 4
Joined: Wed Mar 18, 2020 7:23 am

Re: How to link 32- and 64-bit code together?

Post by aerkiaga »

I think I've come up with a solution:

Code: Select all

x86_64-elf-objcopy -O elf32-x86-64 -I elf32-i386 boot32.o boot32.o
x86_64-elf-objcopy -O elf32-x86-64 -I elf64-x86-64 kernel.o kernel.o
x86_64-elf-gcc -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib boot32.o kernel.o -Xlinker -m -Xlinker elf32_x86_64
x86_64-elf-objcopy -O elf32-i386 -I elf32-x86-64 myos.bin myos.bin
It links everything together and emits no errors. All symbols are linked properly and have the right addresses as far as I've tested. I still haven't managed to get the 64-bit code to run though...
aerkiaga
Posts: 4
Joined: Wed Mar 18, 2020 7:23 am

Re: How to link 32- and 64-bit code together?

Post by aerkiaga »

Okay, now it works perfectly. Does anybody want me to put this in the wiki? I mean, the solution wasn't really that obvious, it would be useful to have it in "Creating a 64-bit kernel" in case somebody wants to code (parts of) their 32-bit bootstrap in C and not just use assembly and ".code32" or have to write a dedicated loader.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: How to link 32- and 64-bit code together?

Post by pvc »

Correct me if I am wrong, but I think this method may be a little bit problematic for high half kernels and address spans larger that 4GiB. I mean, 32 bit ELF expects 32 bit addresses. Some relocation types may be impossible if you use 64 bit addresses in 32 bit ELF.
aerkiaga
Posts: 4
Joined: Wed Mar 18, 2020 7:23 am

Re: How to link 32- and 64-bit code together?

Post by aerkiaga »

Don't worry, my original idea was to put my kernel in the first 4 GiB so addresses were the same in 32 and 64 bit modes. In fact, I'll possibly make a lower half kernel. I know it's a bad idea, but I think I know what I'm doing. Well, if someone finds out how to link this better, please tell me :)
Post Reply