如何控制grub从磁盘加载到内存的内容量?
How to control the amount of contents loaded into memory from disk by grub?
我正在开发一个由 grub 启动的玩具 OS。
但是,内核映像中的某些部分(尤其是 objcopy-ed 到原始内核映像的部分)在启动时不会加载到物理内存中。 (即跳转到内核精灵定义的 ENTRY 后)
这里有一些问题。
是什么决定了grub从磁盘加载到内存的内容的大小?我可以配置它吗?
或者大小是固定的,我是否应该从磁盘中手动读取其余部分?
################更新################
There are 21 section headers, starting at offset 0x279bfc:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 01000000 001000 009a79 00 AX 0 0 16
[ 2] .rodata PROGBITS 0100a000 00b000 0012b0 00 A 0 0 4096
[ 3] .eh_frame PROGBITS 0100b2b0 00c2b0 0041b0 00 A 0 0 4
[ 4] .data PROGBITS 02000000 011000 002400 00 WA 0 0 4096
[ 5] .bss NOBITS 02002400 013400 108430 00 WA 0 0 1024
[ 6] .percpu_data PROGBITS 0210a880 11b880 002880 00 WA 0 0 4096
[ 7] .comment PROGBITS 00000000 11e100 000011 01 MS 0 0 1
[ 8] .debug_aranges PROGBITS 00000000 11e118 000620 00 0 0 8
[ 9] .debug_info PROGBITS 00000000 11e738 011352 00 0 0 1
[10] .debug_abbrev PROGBITS 00000000 12fa8a 004750 00 0 0 1
[11] .debug_line PROGBITS 00000000 1341da 00577b 00 0 0 1
[12] .debug_str PROGBITS 00000000 139955 00403c 01 MS 0 0 1
[13] .debug_loc PROGBITS 00000000 13d991 008966 00 0 0 1
[14] .debug_ranges PROGBITS 00000000 1462f7 000840 00 0 0 1
[15] .part1 PROGBITS 0c000000 147000 096ba8 00 A 0 0 1
[16] .part2 PROGBITS 0c100000 1de000 096b58 00 A 0 0 1
[17] .srtos_conf PROGBITS 0c1a0000 275000 00064f 00 A 0 0 1
[18] .symtab SYMTAB 00000000 275650 002780 10 19 157 4
[19] .strtab STRTAB 00000000 277dd0 001d64 00 0 0 1
[20] .shstrtab STRTAB 00000000 279b34 0000c7 00 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),
p (processor specific)
Elf file type is EXEC (Executable file)
Entry point 0x1000038
There are 2 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x01000000 0x01000000 0x0f460 0x0f460 R E 0x1000
LOAD 0x011000 0x02000000 0x02000000 0x10d100 0x10d100 RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .text .rodata .eh_frame
01 .data .bss .percpu_data
特别是,我想让 GRUB 加载 .part1
、.part2
和 .srtos_conf
部分。
我猜它们没有加载,因为它们不是程序的一部分 headers。
如何将这些部分添加为程序 headers?
目前,这些使用 objcopy --add-section XXX
合并到内核中,节标志为 alloc,readonly,load,contents
。
我必须使用哪个选项才能将这些部分添加到程序中 headers?
向 ELF 添加新部分的 objcopy 方法似乎过于有限。
https://reverseengineering.stackexchange.com/a/14780 表示不可能
以这种方式添加程序头条目。
我建议使用 objcopy 为 .part1
等创建目标文件,
然后在构建 kernel.elf 时将这些指定为链接器的附加输入。 Objcopy 将放置文件
.data
部分中的内容,并将创建符号
_binary_x_start
/_binary_x_end
/ _binary_x_size
为了方便。
举个例子:
从任何类型的文件创建目标文件(替换您的目标三元组):
i686-elf-objcopy --input binary -B i386 -O elf32-i386 x x.o
将 x.o 添加到链接器输入可扩展 .data
输出部分以包含
文件内容,自然会导致它被加载程序加载。
如果需要,您可以使用链接描述文件控制文件的加载位置。
(具有正确参数的 objcopy 也可以为您执行此操作,但是链接描述文件
通常是一种更清洁的方法。
例如,要将文件专门放置在 0x200000,您可以这样做:
/* ... */
.data : {
*(EXCLUDE_FILE(x.o) .data)
}
. = 0x0200000;
.foo : {
x.o (.data)
}
/* ... */
当然你也可以重命名目标文件中的部分以避免
EXCLUDE_FILE
这里。
您可能想要查看的另一个选项是使用多重引导模块。将文件作为模块可能是一种更简单的方法,但让您无法控制 where/how 它们的加载。
它还将您与多重启动联系在一起,超出您的想象(我喜欢我的引导加载程序简单且可更换 ;-)。
我正在开发一个由 grub 启动的玩具 OS。
但是,内核映像中的某些部分(尤其是 objcopy-ed 到原始内核映像的部分)在启动时不会加载到物理内存中。 (即跳转到内核精灵定义的 ENTRY 后)
这里有一些问题。
是什么决定了grub从磁盘加载到内存的内容的大小?我可以配置它吗?
或者大小是固定的,我是否应该从磁盘中手动读取其余部分?
################更新################
There are 21 section headers, starting at offset 0x279bfc:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 01000000 001000 009a79 00 AX 0 0 16
[ 2] .rodata PROGBITS 0100a000 00b000 0012b0 00 A 0 0 4096
[ 3] .eh_frame PROGBITS 0100b2b0 00c2b0 0041b0 00 A 0 0 4
[ 4] .data PROGBITS 02000000 011000 002400 00 WA 0 0 4096
[ 5] .bss NOBITS 02002400 013400 108430 00 WA 0 0 1024
[ 6] .percpu_data PROGBITS 0210a880 11b880 002880 00 WA 0 0 4096
[ 7] .comment PROGBITS 00000000 11e100 000011 01 MS 0 0 1
[ 8] .debug_aranges PROGBITS 00000000 11e118 000620 00 0 0 8
[ 9] .debug_info PROGBITS 00000000 11e738 011352 00 0 0 1
[10] .debug_abbrev PROGBITS 00000000 12fa8a 004750 00 0 0 1
[11] .debug_line PROGBITS 00000000 1341da 00577b 00 0 0 1
[12] .debug_str PROGBITS 00000000 139955 00403c 01 MS 0 0 1
[13] .debug_loc PROGBITS 00000000 13d991 008966 00 0 0 1
[14] .debug_ranges PROGBITS 00000000 1462f7 000840 00 0 0 1
[15] .part1 PROGBITS 0c000000 147000 096ba8 00 A 0 0 1
[16] .part2 PROGBITS 0c100000 1de000 096b58 00 A 0 0 1
[17] .srtos_conf PROGBITS 0c1a0000 275000 00064f 00 A 0 0 1
[18] .symtab SYMTAB 00000000 275650 002780 10 19 157 4
[19] .strtab STRTAB 00000000 277dd0 001d64 00 0 0 1
[20] .shstrtab STRTAB 00000000 279b34 0000c7 00 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),
p (processor specific)
Elf file type is EXEC (Executable file)
Entry point 0x1000038
There are 2 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x01000000 0x01000000 0x0f460 0x0f460 R E 0x1000
LOAD 0x011000 0x02000000 0x02000000 0x10d100 0x10d100 RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .text .rodata .eh_frame
01 .data .bss .percpu_data
特别是,我想让 GRUB 加载 .part1
、.part2
和 .srtos_conf
部分。
我猜它们没有加载,因为它们不是程序的一部分 headers。
如何将这些部分添加为程序 headers?
目前,这些使用 objcopy --add-section XXX
合并到内核中,节标志为 alloc,readonly,load,contents
。
我必须使用哪个选项才能将这些部分添加到程序中 headers?
向 ELF 添加新部分的 objcopy 方法似乎过于有限。 https://reverseengineering.stackexchange.com/a/14780 表示不可能 以这种方式添加程序头条目。
我建议使用 objcopy 为 .part1
等创建目标文件,
然后在构建 kernel.elf 时将这些指定为链接器的附加输入。 Objcopy 将放置文件
.data
部分中的内容,并将创建符号
_binary_x_start
/_binary_x_end
/ _binary_x_size
为了方便。
举个例子:
从任何类型的文件创建目标文件(替换您的目标三元组):
i686-elf-objcopy --input binary -B i386 -O elf32-i386 x x.o
将 x.o 添加到链接器输入可扩展 .data
输出部分以包含
文件内容,自然会导致它被加载程序加载。
如果需要,您可以使用链接描述文件控制文件的加载位置。 (具有正确参数的 objcopy 也可以为您执行此操作,但是链接描述文件 通常是一种更清洁的方法。
例如,要将文件专门放置在 0x200000,您可以这样做:
/* ... */
.data : {
*(EXCLUDE_FILE(x.o) .data)
}
. = 0x0200000;
.foo : {
x.o (.data)
}
/* ... */
当然你也可以重命名目标文件中的部分以避免
EXCLUDE_FILE
这里。
您可能想要查看的另一个选项是使用多重引导模块。将文件作为模块可能是一种更简单的方法,但让您无法控制 where/how 它们的加载。
它还将您与多重启动联系在一起,超出您的想象(我喜欢我的引导加载程序简单且可更换 ;-)。