嗯,我有一个32位c内核代码,我按如下方式链接:
i686-elf-ld entry.o kernel.o cursor.o -Ttext 0x100000 -e kmain -o kernel.elf
objcopy -O binary kernel.elf kernel.o
这不是与OS开发人员有关的问题,而是与链接程序有关的问题。当我执行readelf -s kernel.elf
时,我得到:
Symbol table '.symtab' contains 29 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00100000 0 SECTION LOCAL DEFAULT 1
2: 001002f4 0 SECTION LOCAL DEFAULT 2
3: 0010035c 0 SECTION LOCAL DEFAULT 3
4: 00101454 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 SECTION LOCAL DEFAULT 5
6: 00000000 0 SECTION LOCAL DEFAULT 6
7: 00000000 0 SECTION LOCAL DEFAULT 7
8: 00000000 0 SECTION LOCAL DEFAULT 8
9: 00000000 0 SECTION LOCAL DEFAULT 9
10: 00000000 0 SECTION LOCAL DEFAULT 10
11: 00000000 0 FILE LOCAL DEFAULT ABS kernel/entry.asm
12: 00000000 0 FILE LOCAL DEFAULT ABS dadio.c
13: 00000000 0 FILE LOCAL DEFAULT ABS kernel.c
14: 0010022d 11 FUNC LOCAL DEFAULT 1 block_number
15: 00100238 69 FUNC LOCAL DEFAULT 1 pmmngr_free_block
16: 00000000 0 FILE LOCAL DEFAULT ABS kernel/src/asm/cursor.asm
17: 0010005d 251 FUNC GLOBAL DEFAULT 1 printf
18: 0010027d 48 FUNC GLOBAL DEFAULT 1 pmmgr_free_range
19: 001002b0 0 NOTYPE GLOBAL DEFAULT 1 set_cursor
20: 001002d1 0 NOTYPE GLOBAL DEFAULT 1 get_cursor
21: 00100007 86 FUNC GLOBAL DEFAULT 1 clear
22: 00101458 0 NOTYPE GLOBAL DEFAULT 4 __bss_start
23: 00101454 4 OBJECT GLOBAL DEFAULT 4 _physical_memory_table
24: 00100195 152 FUNC GLOBAL DEFAULT 1 pmmngr_init
25: 00101458 0 NOTYPE GLOBAL DEFAULT 4 _edata
26: 00101458 0 NOTYPE GLOBAL DEFAULT 4 _end
27: 00100000 0 NOTYPE GLOBAL DEFAULT 1 start
28: 00100158 61 FUNC GLOBAL DEFAULT 1 kmain
[当我执行readelf -S kernel.elf
时我得到:
There are 14 section headers, starting at offset 0x2044:
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 00100000 001000 0002f1 00 AX 0 0 16
[ 2] .rodata PROGBITS 001002f4 0012f4 000066 00 A 0 0 4
[ 3] .eh_frame PROGBITS 0010035c 00135c 0000f8 00 A 0 0 4
[ 4] .data PROGBITS 00101454 001454 000004 00 WA 0 0 4
[ 5] .comment PROGBITS 00000000 001458 000011 01 MS 0 0 1
[ 6] .debug_aranges PROGBITS 00000000 001469 000040 00 0 0 1
[ 7] .debug_info PROGBITS 00000000 0014a9 00032c 00 0 0 1
[ 8] .debug_abbrev PROGBITS 00000000 0017d5 0001c9 00 0 0 1
[ 9] .debug_line PROGBITS 00000000 00199e 000195 00 0 0 1
[10] .debug_str PROGBITS 00000000 001b33 0001ed 01 MS 0 0 1
[11] .symtab SYMTAB 00000000 001d20 0001d0 10 12 17 4
[12] .strtab STRTAB 00000000 001ef0 0000d1 00 0 0 1
[13] .shstrtab STRTAB 00000000 001fc1 000082 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)
对我来说这似乎是标准的...这是问题,当我执行readelf -l kernel.elf
时,得到以下信息:
Elf file type is EXEC (Executable file)
Entry point 0x100158
There are 2 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x000ff000 0x000ff000 0x01454 0x01454 R E 0x1000
LOAD 0x001454 0x00101454 0x00101454 0x00004 0x00004 RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .text .rodata .eh_frame
01 .data
此0xff000来自哪里??我不明白这个价值是如何产生的?另外,objcopy是否会查看程序头表,然后输出相应的原始二进制文件?
我可能不太了解链接器:(
要了解这种情况-您需要了解各节和各节之间的区别。
您在命令中为Addr
部分指定.text
,默认情况下offset
= 0x1000
。
ld
的手册:
--section-alignment Sets the section alignment. Sections in memory will always begin at addresses which are a multiple of this number. Defaults to 0x1000. [This option is specific to the i386 PE targeted port of the linker]
section-alignment
不是您的目标标志,但显示0x1000
是预期的默认值。
0x100000-0x1000 = 0xff000
如果需要使用段,则可以使用-Ttext-segment=org
标志。
为了更紧密地使用链接器,您可以编写自己的脚本 [link],以避免出现默认值,在某些情况下,这对于内核开发是不可接受的。您可以查看一个适用于linux x86内核的文件 [link]。
objcopy
根据您的情况用于简化构建系统,并替换链接描述文件。但这不是一个好方法。它解析obj
结构并将其转换为二进制文件,通常只在其中放置代码和数据特定的部分。