OSDev.org https://forum.osdev.org/ |
|
How to place multiboot header at proper offset? https://forum.osdev.org/viewtopic.php?f=1&t=33821 |
Page 1 of 1 |
Author: | yuriyzam [ Sun Aug 11, 2019 8:23 am ] |
Post subject: | How to place multiboot header at proper offset? |
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. |
Author: | iansjack [ Sun Aug 11, 2019 10:04 am ] |
Post subject: | Re: How to place multiboot header at proper offset? |
Assuming that you are using a 32-bit cross compiler, why are you using x86_64-elf-readelf? |
Author: | bzt [ Sun Aug 11, 2019 10:16 am ] |
Post subject: | Re: How to place multiboot header at proper offset? |
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 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)).{ .text BLOCK(4K) : ALIGN(4K) { KEEP(*(.multiboot)) *(.text) } ... Cheers, bzt |
Author: | yuriyzam [ Sun Aug 11, 2019 11:34 am ] |
Post subject: | Re: How to place multiboot header at proper offset? |
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 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)).{ .text BLOCK(4K) : ALIGN(4K) { KEEP(*(.multiboot)) *(.text) } ... 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? |
Author: | iansjack [ Sun Aug 11, 2019 12:14 pm ] |
Post subject: | Re: How to place multiboot header at proper offset? |
Multiboot only supports 32-bit executables. |
Author: | bzt [ Sun Aug 11, 2019 4:56 pm ] |
Post subject: | Re: How to place multiboot header at proper offset? |
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 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 |
Author: | yuriyzam [ Wed Aug 14, 2019 9:51 am ] |
Post subject: | Re: How to place multiboot header at proper offset? |
Okay, after a couple of days I solved this issue using multiboot 2 and bootstrapping. Thanks a lot for your help! |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |