对于一个elf文件,我们可以通过readelf命令,搭配-S选项,查看该elf的section。
Contents
一、源代码
比如对应如下的汇编文件,文件中定义了两个section。
.text .global _start _start: lb x5, 0(sp) lb x6, 0(sp) lb x7, 0(sp) lb x8, 0(sp) lb x9, 0(sp) lb x10, 0(sp) lb x11, 0(sp) .data .word 0x55555555 .word 0x55555555 .word 0x55555555 .word 0x55555555 .word 0x55555555 .word 0x55555555 .word 0x55555555 .word 0x55555555 .word 0x55555555 .word 0x55555555 .word 0x55555555 .word 0x55555555
链接脚本
OUTPUT_ARCH("riscv") ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text) } . = 0x90000000; .data : { *(.data) } }
链接脚本
编译的命令:
riscv-nuclei-elf-gcc a.S -Ta.lds -nostdlib -nostartfiles -o a.elf
对于得到的elf的文件,使用readelf -S 查看section信息,得到以下信息。
There are 7 section headers, starting at offset 0x20f8: 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 80000000 001000 00001c 00 AX 0 0 2 [ 2] .data PROGBITS 90000000 002000 000030 00 WA 0 0 1 [ 3] .riscv.attributes LOPROC+0x3 00000000 002030 000033 00 0 0 1 [ 4] .symtab SYMTAB 00000000 002064 000050 10 5 4 4 [ 5] .strtab STRTAB 00000000 0020b4 000008 00 0 0 1 [ 6] .shstrtab STRTAB 00000000 0020bc 000039 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查看segment信息,得到如下:
Elf file type is EXEC (Executable file) Entry point 0x80000000 There are 2 program headers, starting at offset 52
Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x001000 0x80000000 0x80000000 0x0001c 0x0001c R E 0x1000 LOAD 0x002000 0x90000000 0x90000000 0x00030 0x00030 RW 0x1000
Section to Segment mapping: Segment Sections... 00 .text 01 .data |
现在我想往elf文件中,插入两个section,分别是:
-
text_1:该section内容和.text section内容一致
-
data_1:该section内容和.data section内容一致
此时,就要用到objcopy工具,对于gcc工具链,都会有一个objcopy工具。该工具,可以拷贝或者修改一个目标文件的内容到另一个目标文件中。
关于该工具的介绍,可以参考手册:
https://sourceware.org/binutils/docs/binutils/objcopy.html
此时,我们要用到该工具的如下选项:
-
--add-section:增加一个section
-
--set-section-flags:修改section的属性标志
-
--set-section-vma:修改section的vma
-
--change-section-lma:修改section的lma
二、--add-section
官方解释:
--add-section sectionname=filename Add a new section named sectionname while copying the file. The contents of the new section are taken from the file filename. The size of the section will be the size of the file. This option only works on file formats which can support sections with arbitrary names. Note - it may be necessary to use the --set-section-flags option to set the attributes of the newly created section. |
向elf文件中,增加一个section,sectionname指定加入section的名字,filename,指定该section内容的文件
三、--set-section-flags
官方解释:
--set-section-flags sectionpattern=flags Set the flags for any sections matching sectionpattern. The flags argument is a comma separated string of flag names. The recognized names are 'alloc', 'contents', 'load', 'noload', 'readonly', 'code', 'data', 'rom', 'share', and 'debug'. You can set the 'contents' flag for a section which does not have contents, but it is not meaningful to clear the 'contents' flag of a section which does have contents–just remove the section instead. Not all flags are meaningful for all object file formats. |
设置section的属性标志,sectionpattern是section名字的模式匹配,flags是属性标志,可以设置多个属性标志,之间使用逗号分隔。
四、--change-section-vma
官方解释:
更改一个section的vma,可以设置vma绝对值,也可以修改偏移。
五、--change-section-lma
官方解释
更改一个section的lma,可以设置lma绝对值,也可以修改偏移。
六、elf中增加section
首先,我们先提取源elf文件,.text段和.data段的内容,得到bin文件。
使用objcopy的-j选项,可以从elf文件中,提取指定section的内容。
riscv-nuclei-elf-objcopy -O binary -j .text a.elf text.bin riscv-nuclei-elf-objcopy -O binary -j .data a.elf data.bin
然后使用objcopy命令,将提取得到的bin文件,给加入到elf文件中。
riscv-nuclei-elf-objcopy -O elf32-littleriscv --add-section text_1=text.bin --set-section-flags text_1=alloc,code --change-section-vma text_1=0xa0000000 --change-section-lma text_1=0xb0000000 --add-section data_1=data.bin --set-section-flags data_1=alloc,data --change-section-vma data_1=0xb0000000 --change-section-lma data_1=0xc0000000 a.elf b.elf
执行,会得到如下warning
riscv-nuclei-elf-objcopy: b.elf: warning: allocated section `data_1' not in segment riscv-nuclei-elf-objcopy: b.elf: warning: allocated section `text_1' not in segment |
提示,新增加的section data_1和text_1,并没有加入到segment中。
此时,我们使用readelf -S,查看b.elf的section内容:
There are 9 section headers, starting at offset 0x40dc: 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 80000000 001000 00001c 00 AX 0 0 2 [ 2] .data PROGBITS 90000000 002000 000030 00 WA 0 0 1 [ 3] .riscv.attributes LOPROC+0x3 00000000 002030 000033 00 0 0 1 [ 4] data_1 PROGBITS b0000000 003000 000030 00 WA 0 0 1 [ 5] text_1 PROGBITS a0000000 004000 00001c 00 WAX 0 0 1 [ 6] .symtab SYMTAB 00000000 00401c 000070 10 7 6 4 [ 7] .strtab STRTAB 00000000 00408c 000008 00 0 0 1 [ 8] .shstrtab STRTAB 00000000 004094 000047 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) |
发现section加入到elf文件中了。
此时再查看segement。得到如下信息。
Elf file type is EXEC (Executable file) Entry point 0x80000000 There are 2 program headers, starting at offset 52
Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x001000 0x80000000 0x80000000 0x0001c 0x0001c R E 0x1000 LOAD 0x002000 0x90000000 0x90000000 0x00030 0x00030 RW 0x1000
Section to Segment mapping: Segment Sections... 00 .text 01 .data |
可以看出,新增加的section,并没有加入到segment中。
使用-add-section的方式,可以给elf增加section,但是该section,不能自动加入到segment中。这个是objcopy工具的局限。