Page 1 of 1

Linking kernel at 0xFFFF800000000000 (AMD64)

Posted: Thu Aug 06, 2009 3:31 pm
by dosfan
Hi

I've been working on a long mode kernel for a couple of weeks now. I use the a.out kludge to load a a 64bit ELF with GRUB. My 32bit stub makes it into long mode and reaches my C entry point no problem when linked at 0xFFFFFFFF80010000.

I can't seem to link at 0xFFFF800000010000!!. I've read a few moans on this forum about this but no real solution. Anyone know what causes this :

Code: Select all

arch/amd64/entry.o: In function `_multiboot':
(.text+0xc): relocation truncated to fit: R_X86_64_32 against `.text'
My linker script is as the 64bit kernel wiki page.

I'm using a x86_64-elf cross compiler on Cygwin I built myself. GCC 4.3.3.

The function its moaning about is actually the multiboot header for GRUB.
KERNEL_VMA = 0xFFFF800000000000

Code: Select all

_multiboot:
    .long 0x1BADB002
    .long 0x00010002
    .long  (0 - 0x1badb002 - 0x00010002)
    .long (_multiboot-KERNEL_VMA)
    .long (_code-KERNEL_VMA)
    .long (_data_end-KERNEL_VMA)
    .long (_end-KERNEL_VMA)
    .long (_entry-KERNEL_VMA)
Bearing in mind this all works fine when using the higher address........ :shock:
Cheers!

Re: Linking kernel at 0xFFFF800000000000 (AMD64)

Posted: Thu Aug 06, 2009 3:40 pm
by AndreaOrru
Add -mcmodel=large to your CFLAGS.

Re: Linking kernel at 0xFFFF800000000000 (AMD64)

Posted: Thu Aug 06, 2009 3:49 pm
by dosfan
Sorry should have included that. I already have -mcmodel=large in my CFLAGS.

Re: Linking kernel at 0xFFFF800000000000 (AMD64)

Posted: Thu Aug 06, 2009 6:37 pm
by whowhatwhere
I'm not sure as this is guessing, but I believe on amd64, ".long" gives the equivalent of a unsigned 32 bit integral value. When it gets thrown in with the VMA mod, I think the value + the offset is too large for the ".long" directive. When I had this problem, someone suggested using ".quad" however, that would just give an unsigned 64 bit integral value. The real issue is that the multiboot section must be placed at an absolute load address < 2GB for the compiler to "like" it.

Code: Select all

OUTPUT_FORMAT(elf64-x86-64)
ENTRY(kmain)
SECTIONS
{
    /* This should place the multiboot header just */
    /* about 32 bytes above the program headers. */
    .multiboot : AT(SIZEOF_HEADERS+32) {
        _multiboot = .;
        *(.multiboot)
        . = ALIGN(4096);
    }
    . = KERNEL_VMA;

    .text : AT(ADDR(.text) - KERNEL_VMA)
    {
        _code = .;
        *(.text)
        *(.rodata*)
        . = ALIGN(4096);
    }

   .data : AT(ADDR(.data) - KERNEL_VMA)
   {
        _data = .;
        *(.data)
        . = ALIGN(4096);
   }

   .ehframe : AT(ADDR(.ehframe) - KERNEL_VMA)
   {
       _ehframe = .;
       *(.ehframe)
        . = ALIGN(4096);
   }

   .bss : AT(ADDR(.bss) - KERNEL_VMA)
   {
       _bss = .;
       *(.bss)
       . = ALIGN(4096);
   }

   _end = .;

   /DISCARD/ :
   {
        *(.comment)
   }
}
I'm not sure if this will work, because it's been about a year since I did any serious OSDev work. I won't be held liable if it blows up your computer, causes black holes, causes space time inversions or eats pets or loved ones. (Other Disclaimer Here)