X86-64: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
mNo edit summary
added "Linking a 64-bit ELF64 kernel against a 32-bit ELF32 bootstrap (for use with Multiboot)" section
Line 64: Line 64:


This LP64 means Longs and Pointers are 64bits wide. LL is a special case and means long-long...
This LP64 means Longs and Pointers are 64bits wide. LL is a special case and means long-long...

== Linking a 64-bit ELF64 kernel against a 32-bit ELF32 bootstrap (for use with Multiboot) ==

<source lang="bash">

# I assume that you've already compiled and linked your 64-bit kernel


# your 64-bit kernel
kernel64="build/kernel64.bin"

# its base address -- make sure it doesn't overlap with the kernel32 sections!
kernel64_baseaddress="0x00140000"

# the symbols from it you want available in your 32-bit loader
kernel64export32_symbols="k_GDT k_GDTptr k_PML4 k_PML3 k_PML2 k_PML1_first8M kinit64 k_multibootdata k64_sbss k64_ebss k_pages k_npages"


kernel64export32_ldscript=`mktemp`
kernel64_section=`mktemp`


# generate .kernel64 section's data
readelf -SW "$kernel64" | python -c "`cat <<EOF
import re, sys
regex=r"\[\s*\d+\]\s*(?!NULL)(\S+)\s+(PROGBITS|NOBITS)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)"
baseaddress=$kernel64_baseaddress
k64f = open("$kernel64", "r")
f = open("$kernel64_section", "w")
for line in sys.stdin:
r = re.search(regex, line)
if not r:
continue
section, stype, LMA, offset, size = r.groups()
LMA, offset, size = map(lambda s: int(s, 16), (LMA, offset, size))
if LMA < baseaddress:
raise ValueError("section ('%s' offset=0x%08x size=0x%08x ) at address < 0x%x" % (section, offset, size, baseaddress))
k64f.seek(offset)
if stype == "PROGBITS":
f.seek(LMA-baseaddress)
f.write(k64f.read(size))
f.close()
EOF`" || fail

# export wanted symbols from kernel64
readelf -sW "$kernel64" | python -c "`cat <<EOF
import re, sys
regex=r"\s*\:\s+([0-9a-fA-F]+)\s+\d+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)"
syms=filter(len,"$kernel64export32_symbols".split(" "))
f = open("$kernel64export32_ldscript", "w")
for line in sys.stdin:
r = re.search(regex, line)
if not r:
continue
val, sym = r.groups()
if not sym in syms:
continue
val = int(val, 16)
if val > 0xffffffff:
raise ValueError("symbol value must be below 0xffffffff limit")
f.write('"%s" = %s;\n' % (sym, hex(val)))
f.close()
EOF`" || fail


# now we have to build the 32-bit loader

# your actual lines may vary, change to your needs
gcc -m32 -Wall -Wextra -nostdlib -nostartfiles -nodefaultlibs -Isrc -O5 -fno-strict-aliasing -c \
src/start64/start64.c -o build/start64/start64.o
nasm -f elf32 \
src/start64/loader32.asm -o build/start64/loader32.o

# add the contents of $kernel64_section as a section in one of the 32-bit object files
objcopy --add-section .kernel64="$kernel64_section" \
--set-section-flag .kernel64=alloc,data,load,contents \
build/start64/loader32.o || fail

# link the previous two files, taking care to include (-T) the autogenerated syms file
ld -melf_i386 -T src/start64/linker.ld -T "$kernel64export32_ldscript" -o kernel.bin \
build/start64/start64.o build/start64/loader32.o || fail

</source>