.文本节不是段的一部分,即使大小、偏移量和物理地址匹配

问题描述 投票:0回答:1

我正在用 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
  • 处的 .data 部分
  • 和 .shstrtab 部分。

我的程序头将 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(&sections);
        let mut n = 0;
        let mut next_section = || {
            let res = bin(&sections[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(&sections);
    let mut next_section = growing_subslice(&sections, |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 的段映射部分中。

elf
1个回答
0
投票

问题是索引 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(&sections);
     let mut next_section = growing_subslice(&sections, |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
        ...
© www.soinside.com 2019 - 2024. All rights reserved.