我正在用 Rust 编写一个编译器,现在正在尝试生成一个 elf。 我有
0x400000
处的 .text 部分和文件偏移量 elf_header_size + elf_program_header_size + 3 * elf_section_header_size
,0x400000 + text_size
和文件偏移量 elf_header_size + elf_program_header_size + 3 * elf_section_header_size + text_size
我的程序头将 p_vaddr 和 p_paddr 设置为
0x400000
,将 p_filesz 和 p_memsz 设置为 text_len + data_len
。
readelf 打印:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] .text PROGBITS 0000000000400000 00000138
0000000000000053 0000000000000000 AX 0 0 16
[ 1] .data PROGBITS 0000000000400053 0000018b
0000000000000004 0000000000000000 WA 0 0 16
[ 2] .shstrtab STRTAB 0000000000000000 0000018f
0000000000000016 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),
R (retain), D (mbind), l (large), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000138 0x0000000000400000 0x0000000000400000
0x0000000000000057 0x0000000000000057 R E 0x1000
但是然后:
Section to Segment mapping:
Segment Sections...
00 .data
为什么段 00 只包含 .data? objdump 也不会生成任何东西:
main: file format elf64-x86-64
这是我的代码:
impl Program {
fn generate_elf(mut self) -> Vec<u8> {
let mut vec = Vec::new();
let bin = |slice: &[&str]| {
slice
.iter()
.map(|x| x.as_bytes().to_vec())
.flatten()
.collect::<Vec<u8>>()
};
let sections = [".text\0", ".data\0", ".shstrtab\0"];
let mut sections_bin = bin(§ions);
let mut n = 0;
let mut next_section = || {
let res = bin(§ions[0..n as usize]).len() as u32;
n += 1;
res
};
let text_len = self.text.len() as u64;
let data_len = self.data.len() as u64;
let elf_header_size = size_of::<Elf64Header>() as u64;
let elf_program_header_size = size_of::<Elf64ProgramHeader>() as u64;
let elf_section_header_size = size_of::<Elf64SectionHeader>() as u64;
let mut head = elf_header_size + elf_program_header_size + 3 * elf_section_header_size;
let elf_header = Elf64Header {
e_ident: [0x7F, b'E', b'L', b'F', 2, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0],
e_type: 2,
e_machine: 0x3E,
e_version: 1,
e_entry: 0x400000,
e_phoff: elf_header_size,
e_shoff: elf_header_size + elf_program_header_size,
e_flags: 0,
e_ehsize: elf_header_size as u16,
e_phentsize: elf_program_header_size as u16,
e_phnum: 1,
e_shentsize: elf_section_header_size as u16,
e_shnum: 3,
e_shstrndx: 2,
};
let program_header = Elf64ProgramHeader {
p_type: 1,
p_flags: 1 | 4,
p_offset: head,
p_vaddr: 0x400000,
p_paddr: 0x400000,
p_filesz: text_len + data_len,
p_memsz: text_len + data_len,
p_align: 0x1000,
};
let text_section_header = Elf64SectionHeader {
sh_name: next_section(),
sh_type: 1,
sh_flags: 2 | 4,
sh_addr: 0x400000,
sh_offset: head,
sh_size: text_len,
sh_link: 0,
sh_info: 0,
sh_addralign: 0x10,
sh_entsize: 0,
};
head += text_section_header.sh_size;
let data_section_header = Elf64SectionHeader {
sh_name: next_section(),
sh_type: 1,
sh_flags: 1 | 2,
sh_addr: 0x400000 + text_section_header.sh_size,
sh_offset: head,
sh_size: data_len,
sh_link: 0,
sh_info: 0,
sh_addralign: 0x10,
sh_entsize: 0,
};
head += data_section_header.sh_size;
let strings_section_header = Elf64SectionHeader {
sh_name: next_section(),
sh_type: 3,
sh_flags: 0,
sh_addr: 0,
sh_offset: head,
sh_size: sections_bin.len() as u64,
sh_link: 0,
sh_info: 0,
sh_addralign: 1,
sh_entsize: 0,
};
extend(&mut vec, elf_header);
extend(&mut vec, program_header);
extend(&mut vec, text_section_header);
extend(&mut vec, data_section_header);
extend(&mut vec, strings_section_header);
vec.append(&mut self.text);
vec.append(&mut self.data);
vec.append(&mut sections_bin);
vec
}
}
这是整个 readelf 输出:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - GNU
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400000
Start of program headers: 64 (bytes into file)
Start of section headers: 120 (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: 3
Section header string table index: 2
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] .text PROGBITS 0000000000400000 00000138
0000000000000053 0000000000000000 AX 0 0 16
[ 1] .data PROGBITS 0000000000400053 0000018b
0000000000000004 0000000000000000 WA 0 0 16
[ 2] .shstrtab STRTAB 0000000000000000 0000018f
0000000000000016 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),
R (retain), D (mbind), l (large), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000138 0x0000000000400000 0x0000000000400000
0x0000000000000057 0x0000000000000057 R E 0x1000
Section to Segment mapping:
Segment Sections...
00 .data
There is no dynamic section in this file.
There are no relocations in this file.
No processor specific unwind information to decode
No version information found in this file.
我还尝试创建两个程序头,一个用于 .text,一个用于 .data。 .data 将 .data 显示为一个部分,但 .text 则没有。
编辑: 感谢@Employed Russian 的评论,我更改了代码以使段通过
const PAGE_SIZE: u64 = 0x1000;
impl Elf64ProgramHeader {
fn assert_valid(&self) {
assert_eq!((self.p_vaddr - self.p_offset) % PAGE_SIZE, 0);
assert_eq!((self.p_paddr - self.p_offset) % PAGE_SIZE, 0);
}
}
遗憾的是这并没有解决问题。我还尝试再次使用不同的段,一个用于 .text,一个用于 .data,这也没有改变任何内容。然后我将所有部分对齐到 0x10 - 没有改变任何内容 - 然后甚至对齐到 PAGE_SIZE,仍然没有成功。
ELF Header:
Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - GNU
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400000
Start of program headers: 64 (bytes into file)
Start of section headers: 176 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 2
Size of section headers: 64 (bytes)
Number of section headers: 3
Section header string table index: 2
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] .text PROGBITS 0000000000400000 00001000
0000000000001000 0000000000000000 AX 0 0 4096
[ 1] .data PROGBITS 0000000000401000 00002000
0000000000001000 0000000000000000 WA 0 0 4096
[ 2] .shstrtab STRTAB 0000000000000000 00003000
0000000000001000 0000000000000000 0 0 4096
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),
R (retain), D (mbind), l (large), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000001000 0x0000000000400000 0x0000000000400000
0x0000000000001000 0x0000000000001000 R E 0x1000
LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000
0x0000000000001000 0x0000000000001000 RW 0x1000
Section to Segment mapping:
Segment Sections...
00
01
There is no dynamic section in this file.
There are no relocations in this file.
No processor specific unwind information to decode
No version information found in this file.
main: file format elf64-x86-64
编辑2: 我在第一个版本中遇到了一些愚蠢的错误,例如 LOAD 2 的偏移量错误。我解决了这个问题:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] .text PROGBITS 0000000000400000 00001000
0000000000001000 0000000000000000 AX 0 0 4096
[ 1] .data PROGBITS 0000000000401000 00002000
0000000000001000 0000000000000000 WA 0 0 4096
[ 2] .shstrtab STRTAB 0000000000000000 00003000
0000000000000016 0000000000000000 0 0 0
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),
R (retain), D (mbind), l (large), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000001000 0x0000000000400000 0x0000000000400000
0x0000000000001000 0x0000000000001000 R E 0x1000
LOAD 0x0000000000002000 0x0000000000401000 0x0000000000401000
0x0000000000001000 0x0000000000001000 RW 0x1000
Section to Segment mapping:
Segment Sections...
00
01 .data
现在 .data 甚至出现在分段映射部分中。 当尝试启动 elf 时,我仍然遇到分段错误,并且 gdb 报告:
#0 0x0000000000000001 in ?? ()
>>> info files
Symbols from "/home/[name]/dev/rust/toylang/main".
Local core dump file:
`/home/[name]/dev/rust/toylang/core', file type elf64-x86-64.
0x0000000000400000 - 0x0000000000401000 is load1
0x0000000000401000 - 0x0000000000402000 is load2
0x00007f1a35b8e000 - 0x00007f1a35b92000 is load3
0x00007f1a35b92000 - 0x00007f1a35b94000 is load4
0x00007ffcda9ac000 - 0x00007ffcda9ce000 is load5
0xffffffffff600000 - 0xffffffffff601000 is load6
While running this, GDB does not access memory from...
Local exec file:
`/home/[name]/dev/rust/toylang/main', file type elf64-x86-64.
warning: Cannot find section for the entry point of /home/[name]/dev/rust/toylang/main.
Entry point: 0x400000
0x0000000000401000 - 0x0000000000402000 is .data
0x00007f1a35b92120 - 0x00007f1a35b92170 is .hash in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92170 - 0x00007f1a35b921d4 is .gnu.hash in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b921d8 - 0x00007f1a35b92340 is .dynsym in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92340 - 0x00007f1a35b923dc is .dynstr in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b923dc - 0x00007f1a35b923fa is .gnu.version in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92400 - 0x00007f1a35b92438 is .gnu.version_d in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92438 - 0x00007f1a35b92558 is .dynamic in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92560 - 0x00007f1a35b92570 is .rodata in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92570 - 0x00007f1a35b92580 is .vvar__vdso_rng_data in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92580 - 0x00007f1a35b92770 is .vvar__vdso_data in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92770 - 0x00007f1a35b927c4 is .note in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b927c4 - 0x00007f1a35b92818 is .eh_frame_hdr in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92818 - 0x00007f1a35b92978 is .eh_frame in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b92980 - 0x00007f1a35b93791 is .text in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b93791 - 0x00007f1a35b93863 is .altinstructions in system-supplied DSO at 0x7f1a35b92000
0x00007f1a35b93863 - 0x00007f1a35b9389f is .altinstr_replacement in system-supplied DSO at 0x7f1a35b92000
但似乎它加载了一些东西到 0x400000:
>>> x/16x 0x400000
0x400000: 0x48f78b48 0x000001b8 0x00000000 0x01bf4800
0x400010: 0x00000000 0x48000000 0x000001ba 0x00000000
0x400020: 0xc3050f00 0x003cb848 0x00000000 0xbf480000
0x400030: 0x00000000 0x00000000 0x48c3050f 0x000041bf
这有点像我的装配:
│* │ ┊ │ ┊ │
│00001000│ 48 8b f7 48 b8 01 00 00 ┊ 00 00 00 00 00 48 bf 01 │H××Hו⋄⋄┊⋄⋄⋄⋄⋄Hו│
│00001010│ 00 00 00 00 00 00 00 48 ┊ ba 01 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄H┊ו⋄⋄⋄⋄⋄⋄│
│00001020│ 00 0f 05 c3 48 b8 3c 00 ┊ 00 00 00 00 00 00 48 bf │⋄••×H×<⋄┊⋄⋄⋄⋄⋄⋄H×│
│00001030│ 00 00 00 00 00 00 00 00 ┊ 0f 05 c3 48 bf 41 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊••×H×A⋄⋄│
│00001040│ 00 00 00 00 00 50 e8 40 ┊ 00 00 00 58 50 e8 2d 00 │⋄⋄⋄⋄⋄P×@┊⋄⋄⋄XP×-⋄│
│00001050│ 00 00 58 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄X⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│00001060│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ ┊ │ ┊ │
编辑3: 代码位于 https://github.com/Einfachirgendwa1/toylang/blob/c1d67f285fe82e4483a97be7fc955012fada4d54/src/elf.rs
readelf -Wl 的输出是:
Elf file type is EXEC (Executable file)
Entry point 0x400000
There are 2 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x0000000000400000 0x0000000000400000 0x001000 0x001000 R E 0x1000
LOAD 0x002000 0x0000000000401000 0x0000000000401000 0x001000 0x001000 RW 0x1000
Section to Segment mapping:
Segment Sections...
00
01 .data
感谢您的宝贵时间!
编辑4: 我更改了代码以使其也可以在稳定版上运行。 这是一个独立的 elf.rs,它将一个简单的二进制文件保存到 output.rs:
use std::{fs::File, io::Write, slice};
const PAGE_SIZE: u64 = 0x1000;
const SECTION_ALIGNMENT: u64 = PAGE_SIZE;
fn main() {
// Tries to generate an elf out of:
// .text:
// b8 3c 00 00 00 mov $0x3c,%eax
// bf 00 00 00 00 mov $0x0,%edi
// 0f 05 syscall
//
// .data:
// "test"
let elf = generate_elf(
vec![
0xb8, 0x3c, 0x0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0f, 0x05,
],
vec![b'T', b'E', b'S', b'T'],
);
File::create("output").unwrap().write_all(&elf).unwrap();
}
struct Aligned {
required_padding: u64,
padding: Vec<u8>,
}
fn align(number: u64, alignment: u64) -> Aligned {
let required_padding = alignment - number % alignment;
Aligned {
required_padding,
padding: vec![0; required_padding as usize],
}
}
fn align_vector(vec: &mut Vec<u8>, alignment: u64) -> u64 {
vec.append(&mut align(vec.len() as u64, alignment).padding);
vec.len() as u64
}
fn growing_subslice<'a, T, A, F>(vec: &'a [T], f: F) -> impl FnMut() -> A + 'a
where
T: 'a,
F: Fn(&'a [T]) -> A + 'a,
{
let mut n = 0;
move || {
let res = f(&vec[0..n]);
n += 1;
res
}
}
pub fn extend<A: Clone, B>(vec: &mut Vec<A>, b: B) {
unsafe {
vec.extend_from_slice(slice::from_raw_parts(
&b as *const B as *const A,
size_of::<B>(),
))
}
}
pub fn generate_elf(mut text: Vec<u8>, mut data: Vec<u8>) -> Vec<u8> {
let mut p_vaddr = 0x400000;
let mut vec = Vec::new();
let as_vec_u8 = |slice: &[&str]| {
slice
.iter()
.flat_map(|x| x.as_bytes().to_vec())
.collect::<Vec<u8>>()
};
let sections = [".text\0", ".data\0", ".shstrtab\0"];
let mut sections_bin = as_vec_u8(§ions);
let mut next_section = growing_subslice(§ions, |slice| as_vec_u8(slice).len() as u32);
let text_len = align_vector(&mut text, SECTION_ALIGNMENT);
let data_len = align_vector(&mut data, SECTION_ALIGNMENT);
let elf_header_size = size_of::<Elf64Header>() as u64;
let elf_program_header_size = size_of::<Elf64ProgramHeader>() as u64;
let elf_section_header_size = size_of::<Elf64SectionHeader>() as u64;
let headers = elf_header_size + 2 * elf_program_header_size + 3 * elf_section_header_size;
let mut header_padding = align(headers, PAGE_SIZE);
let header_len = headers + header_padding.required_padding;
let elf_header = Elf64Header {
e_ident: [0x7F, b'E', b'L', b'F', 2, 1, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0],
e_type: 2,
e_machine: 0x3E,
e_version: 1,
e_entry: p_vaddr,
e_phoff: elf_header_size,
e_shoff: elf_header_size + 2 * elf_program_header_size,
e_flags: 0,
e_ehsize: elf_header_size as u16,
e_phentsize: elf_program_header_size as u16,
e_phnum: 2,
e_shentsize: elf_section_header_size as u16,
e_shnum: 3,
e_shstrndx: 2,
};
let text_program_header = Elf64ProgramHeader {
p_type: 1,
p_flags: 1 | 4,
p_offset: header_len,
p_vaddr,
p_paddr: p_vaddr,
p_filesz: text_len,
p_memsz: text_len,
p_align: PAGE_SIZE,
};
text_program_header.assert_valid();
p_vaddr += text_len;
let data_program_header = Elf64ProgramHeader {
p_type: 1,
p_flags: 2 | 4,
p_offset: header_len + text_len,
p_vaddr,
p_paddr: p_vaddr,
p_filesz: data_len,
p_memsz: data_len,
p_align: PAGE_SIZE,
};
data_program_header.assert_valid();
let text_section_header = Elf64SectionHeader {
sh_name: next_section(),
sh_type: 1,
sh_flags: 2 | 4,
sh_addr: 0x400000,
sh_offset: header_len,
sh_size: text_len,
sh_link: 0,
sh_info: 0,
sh_addralign: SECTION_ALIGNMENT,
sh_entsize: 0,
};
let data_section_header = Elf64SectionHeader {
sh_name: next_section(),
sh_type: 1,
sh_flags: 1 | 2,
sh_addr: 0x400000 + text_section_header.sh_size,
sh_offset: header_len + text_len,
sh_size: data_len,
sh_link: 0,
sh_info: 0,
sh_addralign: SECTION_ALIGNMENT,
sh_entsize: 0,
};
let strings_section_header = Elf64SectionHeader {
sh_name: next_section(),
sh_type: 3,
sh_flags: 0,
sh_addr: 0,
sh_offset: header_len + text_len + data_len,
sh_size: sections_bin.len() as u64,
sh_link: 0,
sh_info: 0,
sh_addralign: 0x0,
sh_entsize: 0,
};
extend(&mut vec, elf_header);
extend(&mut vec, text_program_header);
extend(&mut vec, data_program_header);
extend(&mut vec, text_section_header);
extend(&mut vec, data_section_header);
extend(&mut vec, strings_section_header);
vec.append(&mut header_padding.padding);
vec.append(&mut text);
vec.append(&mut data);
vec.append(&mut sections_bin);
vec
}
#[repr(C)]
struct Elf64Header {
e_ident: [u8; 16],
e_type: u16,
e_machine: u16,
e_version: u32,
e_entry: u64,
e_phoff: u64,
e_shoff: u64,
e_flags: u32,
e_ehsize: u16,
e_phentsize: u16,
e_phnum: u16,
e_shentsize: u16,
e_shnum: u16,
e_shstrndx: u16,
}
#[derive(Debug)]
#[repr(C)]
struct Elf64ProgramHeader {
p_type: u32,
p_flags: u32,
p_offset: u64,
p_vaddr: u64,
p_paddr: u64,
p_filesz: u64,
p_memsz: u64,
p_align: u64,
}
impl Elf64ProgramHeader {
fn assert_valid(&self) {
assert_eq!((self.p_vaddr - self.p_offset) % PAGE_SIZE, 0);
assert_eq!((self.p_paddr - self.p_offset) % PAGE_SIZE, 0);
}
}
#[repr(C)]
struct Elf64SectionHeader {
sh_name: u32,
sh_type: u32,
sh_flags: u64,
sh_addr: u64,
sh_offset: u64,
sh_size: u64,
sh_link: u32,
sh_info: u32,
sh_addralign: u64,
sh_entsize: u64,
}
二进制文件本身可以工作,但使用 objdump -d 时 objdump 仍然不显示源代码,并且 .text 也不会显示在 readelf 的段映射部分中。
问题是索引 0 处的部分被保留,并且应该是
SHT_NULL
类型。
将此差异应用到您的编辑#4之后:
$ diff -u elf.rs.orig elf.rs
--- elf.rs.orig 2024-11-29 22:09:07.785140746 +0000
+++ elf.rs 2024-11-29 22:06:47.622954606 +0000
@@ -1,4 +1,5 @@
use std::{fs::File, io::Write, slice};
+use std::mem::size_of;
const PAGE_SIZE: u64 = 0x1000;
const SECTION_ALIGNMENT: u64 = PAGE_SIZE;
@@ -75,7 +76,7 @@
.collect::<Vec<u8>>()
};
- let sections = [".text\0", ".data\0", ".shstrtab\0"];
+ let sections = ["\0", ".text\0", ".data\0", ".shstrtab\0"];
let mut sections_bin = as_vec_u8(§ions);
let mut next_section = growing_subslice(§ions, |slice| as_vec_u8(slice).len() as u32);
@@ -86,7 +87,7 @@
let elf_program_header_size = size_of::<Elf64ProgramHeader>() as u64;
let elf_section_header_size = size_of::<Elf64SectionHeader>() as u64;
- let headers = elf_header_size + 2 * elf_program_header_size + 3 * elf_section_header_size;
+ let headers = elf_header_size + 2 * elf_program_header_size + 4 * elf_section_header_size;
let mut header_padding = align(headers, PAGE_SIZE);
let header_len = headers + header_padding.required_padding;
@@ -103,8 +104,8 @@
e_phentsize: elf_program_header_size as u16,
e_phnum: 2,
e_shentsize: elf_section_header_size as u16,
- e_shnum: 3,
- e_shstrndx: 2,
+ e_shnum: 4,
+ e_shstrndx: 3,
};
let text_program_header = Elf64ProgramHeader {
@@ -132,6 +133,18 @@
};
data_program_header.assert_valid();
+ let null_section_header = Elf64SectionHeader {
+ sh_name: next_section(),
+ sh_type: 0,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: 0,
+ sh_size: 0,
+ sh_link: 0,
+ sh_info: 0,
+ sh_addralign: 0,
+ sh_entsize: 0,
+ };
let text_section_header = Elf64SectionHeader {
sh_name: next_section(),
sh_type: 1,
@@ -172,6 +185,8 @@
extend(&mut vec, elf_header);
extend(&mut vec, text_program_header);
extend(&mut vec, data_program_header);
+
+ extend(&mut vec, null_section_header);
extend(&mut vec, text_section_header);
extend(&mut vec, data_section_header);
extend(&mut vec, strings_section_header);
使用
rustc elf.rs && ./elf && readelf -WSl output
:
There are 4 section headers, starting at offset 0xb0:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000400000 001000 001000 00 AX 0 0 4096
[ 2] .data PROGBITS 0000000000401000 002000 001000 00 WA 0 0 4096
[ 3] .shstrtab STRTAB 0000000000000000 003000 000017 00 0 0 0
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),
R (retain), D (mbind), l (large), p (processor specific)
Elf file type is EXEC (Executable file)
Entry point 0x400000
There are 2 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x0000000000400000 0x0000000000400000 0x001000 0x001000 R E 0x1000
LOAD 0x002000 0x0000000000401000 0x0000000000401000 0x001000 0x001000 RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .text
01 .data
$ objdump -d output
output: file format elf64-x86-64
Disassembly of section .text:
0000000000400000 <.text>:
400000: b8 3c 00 00 00 mov $0x3c,%eax
400005: bf 00 00 00 00 mov $0x0,%edi
40000a: 0f 05 syscall
...