OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 2:28 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: How to place multiboot header at proper offset?
PostPosted: Sun Aug 11, 2019 8:23 am 
Offline

Joined: Sat Aug 10, 2019 11:46 am
Posts: 6
I am trying to complete Bare Bones for my operating system. When I link sources to kernel executable with a makefile from Bare Bones tutorial it locates text section at 1M offset (1). When I erase line ". = 1M;" (2),
text section is located at 2M offset. If I separate multiboot and text sections (3), linker store multiboot section after text section. How to fix that problem?
Linker scripts and "x86_64-elf-readelf" outputs for executables files:
(1)
Code:
ENTRY(loader)

SECTIONS
{
    . = 1M;
    .text BLOCK(4K) : ALIGN(4K)
   {
      *(.multiboot)
      *(.text)
   }

   /* Read-only data. */
   .rodata BLOCK(4K) : ALIGN(4K)
   {
      *(.rodata)
   }

   /* Read-write data (initialized) */
   .data BLOCK(4K) : ALIGN(4K)
   {
      *(.data)
   }

   /* Read-write data (uninitialized) and stack */
   .bss BLOCK(4K) : ALIGN(4K)
   {
      *(COMMON)
      *(.bss)
   }
}

Code:
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000100000  00100000
       00000000000003ac  0000000000000000  AX       0     0     4096
  [ 2] .rodata           PROGBITS         0000000000101000  00101000
       000000000000000c  0000000000000000   A       0     0     4096
  [ 3] .eh_frame         PROGBITS         0000000000101010  00101010
       000000000000010c  0000000000000000   A       0     0     8
  [ 4] .data             PROGBITS         0000000000102000  00102000
       0000000000000008  0000000000000000  WA       0     0     4096
  [ 5] .bss              NOBITS           0000000000103000  00102008
       0000000000004018  0000000000000000  WA       0     0     4096
  [ 6] .comment          PROGBITS         0000000000000000  00102008
       0000000000000011  0000000000000001  MS       0     0     1
  [ 7] .symtab           SYMTAB           0000000000000000  00102020
       0000000000000408  0000000000000018           8    17     8
  [ 8] .strtab           STRTAB           0000000000000000  00102428
       00000000000001b2  0000000000000000           0     0     1
  [ 9] .shstrtab         STRTAB           0000000000000000  001025da
       0000000000000047  0000000000000000           0     0     1


(2)
Code:
ENTRY(loader)

SECTIONS
{
    .text BLOCK(4K) : ALIGN(4K)
   {
      *(.multiboot)
      *(.text)
   }

   /* Read-only data. */
   .rodata BLOCK(4K) : ALIGN(4K)
   {
      *(.rodata)
   }

   /* Read-write data (initialized) */
   .data BLOCK(4K) : ALIGN(4K)
   {
      *(.data)
   }

   /* Read-write data (uninitialized) and stack */
   .bss BLOCK(4K) : ALIGN(4K)
   {
      *(COMMON)
      *(.bss)
   }
}

Code:
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00200000
       00000000000003ac  0000000000000000  AX       0     0     4096
  [ 2] .rodata           PROGBITS         0000000000001000  00201000
       000000000000000c  0000000000000000   A       0     0     4096
  [ 3] .eh_frame         PROGBITS         0000000000001010  00201010
       000000000000010c  0000000000000000   A       0     0     8
  [ 4] .data             PROGBITS         0000000000002000  00202000
       0000000000000008  0000000000000000  WA       0     0     4096
  [ 5] .bss              NOBITS           0000000000003000  00202008
       0000000000004018  0000000000000000  WA       0     0     4096
  [ 6] .comment          PROGBITS         0000000000000000  00202008
       0000000000000011  0000000000000001  MS       0     0     1
  [ 7] .symtab           SYMTAB           0000000000000000  00202020
       0000000000000408  0000000000000018           8    17     8
  [ 8] .strtab           STRTAB           0000000000000000  00202428
       00000000000001b2  0000000000000000           0     0     1
  [ 9] .shstrtab         STRTAB           0000000000000000  002025da
       0000000000000047  0000000000000000           0     0     1

(3)
Code:
ENTRY(loader)

SECTIONS
{
    . = 1M;
    .multiboot :
    {
        *(.multiboot)
    }
    .text BLOCK(4K) : ALIGN(4K)
   {
      
      *(.text)
   }

   /* Read-only data. */
   .rodata BLOCK(4K) : ALIGN(4K)
   {
      *(.rodata)
   }

   /* Read-write data (initialized) */
   .data BLOCK(4K) : ALIGN(4K)
   {
      *(.data)
   }

   /* Read-write data (uninitialized) and stack */
   .bss BLOCK(4K) : ALIGN(4K)
   {
      *(COMMON)
      *(.bss)
   }
}

Code:
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .multiboot        PROGBITS         0000000000100000  00003008
       000000000000000c  0000000000000000           0     0     4
  [ 2] .comment          PROGBITS         0000000000000000  00003014
       0000000000000011  0000000000000001  MS       0     0     1
  [ 3] .text             PROGBITS         0000000000001000  00001000
       000000000000039c  0000000000000000  AX       0     0     4096
  [ 4] .rodata           PROGBITS         0000000000002000  00002000
       000000000000000c  0000000000000000   A       0     0     4096
  [ 5] .eh_frame         PROGBITS         0000000000002010  00002010
       000000000000010c  0000000000000000   A       0     0     8
  [ 6] .data             PROGBITS         0000000000003000  00003000
       0000000000000008  0000000000000000  WA       0     0     4096
  [ 7] .bss              NOBITS           0000000000004000  00003008
       0000000000004018  0000000000000000  WA       0     0     4096
  [ 8] .symtab           SYMTAB           0000000000000000  00003028
       0000000000000420  0000000000000018           9    18     8
  [ 9] .strtab           STRTAB           0000000000000000  00003448
       00000000000001b2  0000000000000000           0     0     1
  [10] .shstrtab         STRTAB           0000000000000000  000035fa
       0000000000000052  0000000000000000           0     0     1

As I understood from Bare Bones tutorial, multiboot header should be located at < 8K offset, so I should solve this problem to make my kernel work.


Top
 Profile  
 
 Post subject: Re: How to place multiboot header at proper offset?
PostPosted: Sun Aug 11, 2019 10:04 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
Assuming that you are using a 32-bit cross compiler, why are you using x86_64-elf-readelf?


Top
 Profile  
 
 Post subject: Re: How to place multiboot header at proper offset?
PostPosted: Sun Aug 11, 2019 10:16 am 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 1584
Hi,

First of all, the multiboot struct must be located in the first 8K IN THE FILE. This means it doesn't matter what VMA you choose (1M or 2M), the only thing that matters is the file offset. Likewise, the 8 byte alignment refers to the file offset, not the memory address where the struct is loaded.

Second, assuming you have put your struct in the ".multiboot" section, this script should work:
Code:
SECTIONS
{
    .text BLOCK(4K) : ALIGN(4K)
   {
      KEEP(*(.multiboot))
      *(.text)
   }
...
Normally the linker will place the section in the same order as they appear in the source. But to be sure, you can use the KEEP() pseudo-function to tell the linker not to rearrange that certain ".multiboot" section. If you experience problems with the alignment, I would suggest to put the ELF header inside the text section too, that way your text segment will share the same alignment as the file offset. The ". = X" directive only sets the VMA, and not the file offset. (Think about this: it is possible that a text segment should be aligned at 4K when loaded in memory, but it is stored in the file at offset 0xE4 for example. Use readelf to print out the segments (Program Headers). Here's such an example readelf output: according to the Program Headers, the text segment must be loaded at 0xffffffffffe02000 (which is 4K aligned), but stored at offset 0x78 (which is not 4K aligned)).

Cheers,
bzt


Top
 Profile  
 
 Post subject: Re: How to place multiboot header at proper offset?
PostPosted: Sun Aug 11, 2019 11:34 am 
Offline

Joined: Sat Aug 10, 2019 11:46 am
Posts: 6
bzt wrote:
Hi,

First of all, the multiboot struct must be located in the first 8K IN THE FILE. This means it doesn't matter what VMA you choose (1M or 2M), the only thing that matters is the file offset. Likewise, the 8 byte alignment refers to the file offset, not the memory address where the struct is loaded.

Second, assuming you have put your struct in the ".multiboot" section, this script should work:
Code:
SECTIONS
{
    .text BLOCK(4K) : ALIGN(4K)
   {
      KEEP(*(.multiboot))
      *(.text)
   }
...
Normally the linker will place the section in the same order as they appear in the source. But to be sure, you can use the KEEP() pseudo-function to tell the linker not to rearrange that certain ".multiboot" section. If you experience problems with the alignment, I would suggest to put the ELF header inside the text section too, that way your text segment will share the same alignment as the file offset. The ". = X" directive only sets the VMA, and not the file offset. (Think about this: it is possible that a text segment should be aligned at 4K when loaded in memory, but it is stored in the file at offset 0xE4 for example. Use readelf to print out the segments (Program Headers). Here's such an example readelf output: according to the Program Headers, the text segment must be loaded at 0xffffffffffe02000 (which is 4K aligned), but stored at offset 0x78 (which is not 4K aligned)).

Cheers,
bzt

Hi,
Thanks for your reply. Adding KEEP() does not solve this problem. Here are some more details.
Objdump output:
Code:
Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         000003d9  0000000000100000  0000000000100000  00100000  2**12
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .rodata       00000034  0000000000101000  0000000000101000  00101000  2**12
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .eh_frame     0000010c  0000000000101038  0000000000101038  00101038  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .data         00000008  0000000000102000  0000000000102000  00102000  2**12
                  CONTENTS, ALLOC, LOAD, DATA
  4 .bss          00004018  0000000000103000  0000000000103000  00102008  2**12
                  ALLOC
  5 .comment      00000011  0000000000000000  0000000000000000  00102008  2**0
                  CONTENTS, READONLY

Output of readelf:
Code:
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x100000
  Start of program headers:          64 (bytes into file)
  Start of section headers:          1058344 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         1
  Size of section headers:           64 (bytes)
  Number of section headers:         10
  Section header string table index: 9

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000100000  00100000
       00000000000003d9  0000000000000000  AX       0     0     4096
  [ 2] .rodata           PROGBITS         0000000000101000  00101000
       0000000000000034  0000000000000000   A       0     0     4096
  [ 3] .eh_frame         PROGBITS         0000000000101038  00101038
       000000000000010c  0000000000000000   A       0     0     8
  [ 4] .data             PROGBITS         0000000000102000  00102000
       0000000000000008  0000000000000000  WA       0     0     4096
  [ 5] .bss              NOBITS           0000000000103000  00102008
       0000000000004018  0000000000000000  WA       0     0     4096
  [ 6] .comment          PROGBITS         0000000000000000  00102008
       0000000000000011  0000000000000001  MS       0     0     1
  [ 7] .symtab           SYMTAB           0000000000000000  00102020
       0000000000000408  0000000000000018           8    17     8
  [ 8] .strtab           STRTAB           0000000000000000  00102428
       00000000000001b2  0000000000000000           0     0     1
  [ 9] .shstrtab         STRTAB           0000000000000000  001025da
       0000000000000047  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000102008 0x0000000000107018  RWE    0x200000

Section to Segment mapping:
  Segment Sections...
   00     .text .rodata .eh_frame .data .bss

There is no dynamic section in this file.

There are no relocations in this file.

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

Symbol table '.symtab' contains 43 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000100000     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000101000     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000101038     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000102000     0 SECTION LOCAL  DEFAULT    4
     5: 0000000000103000     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS obj/loader.o
     8: 0000000000000001     0 NOTYPE  LOCAL  DEFAULT  ABS ALIGN
     9: 0000000000000002     0 NOTYPE  LOCAL  DEFAULT  ABS MEMINFO
    10: 0000000000000003     0 NOTYPE  LOCAL  DEFAULT  ABS FLAGS
    11: 000000001badb002     0 NOTYPE  LOCAL  DEFAULT  ABS MAGIC
    12: ffffffffe4524ffb     0 NOTYPE  LOCAL  DEFAULT  ABS CHECKSUM
    13: 0000000000004000     0 NOTYPE  LOCAL  DEFAULT  ABS STACKSIZE
    14: 0000000000103000     0 NOTYPE  LOCAL  DEFAULT    5 stack_bottom
    15: 0000000000107000     0 NOTYPE  LOCAL  DEFAULT    5 stack_top
    16: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS kernel.c
    17: 0000000000100040    83 FUNC    GLOBAL DEFAULT    1 terminal_cls
    18: 0000000000107000     1 OBJECT  GLOBAL DEFAULT    5 terminal_color
    19: 0000000000100110   113 FUNC    GLOBAL DEFAULT    1 terminal_nsputc
    20: 0000000000100280    35 FUNC    GLOBAL DEFAULT    1 terminal_nswrite
    21: 0000000000100380    21 FUNC    GLOBAL DEFAULT    1 terminal_init
    22: 0000000000102000     8 OBJECT  GLOBAL DEFAULT    4 VGA_POINTER
    23: 000000000010102c     4 OBJECT  GLOBAL DEFAULT    2 VGA_HEIGHT
    24: 0000000000100190   183 FUNC    GLOBAL DEFAULT    1 terminal_putc
    25: 0000000000101030     4 OBJECT  GLOBAL DEFAULT    2 VGA_WIDTH
    26: 00000000001003a0    57 FUNC    GLOBAL DEFAULT    1 kernel_main
    27: 0000000000107004     4 OBJECT  GLOBAL DEFAULT    5 terminal_foreground_color
    28: 00000000001002b0    35 FUNC    GLOBAL DEFAULT    1 terminal_write
    29: 000000000010000c    14 FUNC    GLOBAL DEFAULT    1 _start
    30: 0000000000107008     4 OBJECT  GLOBAL DEFAULT    5 terminal_column
    31: 00000000001002e0    68 FUNC    GLOBAL DEFAULT    1 terminal_nsputs
    32: 0000000000107000     0 NOTYPE  GLOBAL DEFAULT    5 __bss_start
    33: 00000000001000a0    98 FUNC    GLOBAL DEFAULT    1 terminal_scroll
    34: 000000000010700c     4 OBJECT  GLOBAL DEFAULT    5 terminal_background_color
    35: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND loader
    36: 0000000000101028     4 OBJECT  GLOBAL DEFAULT    2 TAB_SIZE
    37: 0000000000102008     0 NOTYPE  GLOBAL DEFAULT    4 _edata
    38: 0000000000107018     0 NOTYPE  GLOBAL DEFAULT    5 _end
    39: 0000000000100250    33 FUNC    GLOBAL DEFAULT    1 strlen
    40: 0000000000100330    68 FUNC    GLOBAL DEFAULT    1 terminal_puts
    41: 0000000000107010     4 OBJECT  GLOBAL DEFAULT    5 terminal_row
    42: 0000000000100020    29 FUNC    GLOBAL DEFAULT    1 terminal_putentryat

No version information found in this file.

OS was compiled with the latest gcc && binutils releases (9.1.0 and 2.32). Target is x86_64. Full source code is available on GitHub here:
https://github.com/YuRaZaKa/CactOS
(linker script is located at src folder).

UPD: I don't understand the differences between VMA and file offset. Where I could read about that?


Top
 Profile  
 
 Post subject: Re: How to place multiboot header at proper offset?
PostPosted: Sun Aug 11, 2019 12:14 pm 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
Multiboot only supports 32-bit executables.


Top
 Profile  
 
 Post subject: Re: How to place multiboot header at proper offset?
PostPosted: Sun Aug 11, 2019 4:56 pm 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 1584
Yeah, I missed that, iansjack is right, you can't load 64 bit ELFs with Multiboot. You need a 32 bit protmode to 64 bit longmode trampoline code for that:
- start32: this is a small Assembly function that contains 32 bit code, ELF64 entry point points here. It is responsible for setting up long mode (paging, CR0, GDT etc.).
- start64: this function is written in C (traditionally called kmain or kernel_main) compiled for 64 bit which suits ELF64; start32 jumps here with a FAR JMP that loads the 64 bit CS selector too. This could be any virtual address if you set up non-identical mapped paging in start32.

I think this wiki page will be useful to you.

yuriyzam wrote:
Code:
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000102008 0x0000000000107018  RWE    0x200000
This is definitely not right. You should see 0x10000 in the VirtAddr/PhysAddr fields, and only 0x2008 in FileSiz field. I assume your executable is bigger than it should be by almost a megabyte?
If you have an almost 1M filling at the beginning of your executable, there's no wonder GRUB can't find the Multiboot struct in the first 8K.

yuriyzam wrote:
UPD: I don't understand the differences between VMA and file offset. Where I could read about that?
Try these:
https://sourceware.org/binutils/docs/ld/Basic-Script-Concepts.html#Basic-Script-Concepts
https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html#Output-Section-LMA

In short:
- file offset: this is simply the byte position within the executable file; assuming the text segment is the first and does not include the file headers, then its offset equals to the elf header size. It makes your life easier if you put the file headers in the text segment, so Offset 0 is good and desirable.
- LMA: this is the load address where the segments of your executable should be loaded in memory. In your case should be 1M, definitely not 0.
- VMA: the virtual address where the segments supposed to be seen by your code. If not specified otherwise, this equals to LMA by default.

An example: Offset=0x100, LMA=0x1000 (PhysAddr), VMA=0xC000000 (VirtAddr). This means that the segment starts in the file at offset 256, which should be loaded into memory at 4K, and the code segment contains instructions that are accessing that segment at 3G. This makes perfect sense if the ELF loader does not use the MMU, and the first thing in the ELF executable's initialization code is to map the physical address 4K to the virtual address 3G.

Now in your case the Program Headers tells the dynamic linker to load your entire ELF file from the start of memory (Offset=0 and PhysAddr=0, size=0x102008). To properly align your text segment I believe your ELF has almost a megabyte of zeros (or NOPs, 0x90). This won't work, because you can't overwrite BIOS ROM, Option ROMs, EBDA and other system memory (from 0xA0000-0xEFFFF, if my memory serves, it is ok to use the region 0xF0000-0xFFFFF). What you need is to set the load address to 0x10000 to eliminate the padding and overwriting memory under 0x10000. You can do that by specifying the address with ". =" in the SECTIONS block, or by using the AT keyword or a MEMORY region layout (this one is mostly used in embedded systems with fixed memory layouts, I'd suggest to use the first two instead). Depending how you write your script, you may also need to specify "nmagic" and "-z max-page-size" to your linker. It is not documented, but the former forces padding with fills.

Cheers,
bzt


Top
 Profile  
 
 Post subject: Re: How to place multiboot header at proper offset?
PostPosted: Wed Aug 14, 2019 9:51 am 
Offline

Joined: Sat Aug 10, 2019 11:46 am
Posts: 6
Okay, after a couple of days I solved this issue using multiboot 2 and bootstrapping. Thanks a lot for your help!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: thewrongchristian and 77 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group