微小的“手动”创建的ELF给出了分段错误

时间:2014-02-26 11:23:54

标签: linux debugging build segmentation-fault elf

来自可移植可执行文件和Windows我试图在 Linux(Ubuntu AMD64)中使用 NASM 创建一个小的 ELF 可执行文件。我的一小段代码看起来像这样:

BITS 64
; The default virtual address where the executable is linked
_START_VAD                  equ     0x400000

; Here I write the header byte by byte
ELF_HEADER:
    .ident_magic            db      0x7f, "ELF"
    .ident_class            db      2
    .ident_data             db      1
    .ident_version          db      1
    .ident_osabi            db      0
    .ident_abiversion       db      0
    ; Pad with zeros until we have 16 bytes for the identifier
    times 16-$+ELF_HEADER   db      0
    .object_type            dw      2
    .machine                dw      0x3e
    .version                dd      1
    .entry_point            dq      _START_VAD + START
    .progr_header           dq      PROGRAM_HEADER
    .sect_header            dq      SECTIONS_HEADER
    .proc_flags             dd      0
    .header_size            dw      ELF_HEADER_END - ELF_HEADER
    .progr_header_size      dw      56
    .progr_header_entries   dw      3
    .sect_header_size       dw      64
    .sect_header_entries    dw      4
    .sect_header_index      dw      3
ELF_HEADER_END:

PROGRAM_HEADER:
    HEADER_SEGMENT_HEADER:
    HEADER_SEGMENT_SIZE     equ     PROGRAM_HEADER_END - PROGRAM_HEADER
    .header_segment_type    dd      6
    .header_segment_flag    dd      0x1 | 0x4
    .header_segment_offs    dq      PROGRAM_HEADER
    .header_segment_vadr    dq      _START_VAD + PROGRAM_HEADER
    .header_segment_padr    dq      _START_VAD + PROGRAM_HEADER
    .header_segment_file    dq      HEADER_SEGMENT_SIZE
    .header_segment_mems    dq      HEADER_SEGMENT_SIZE
    .header_segment_alig    dq      8

    INTEPRETER_SEGMENT_HEADER:
    INTERP_SEGMENT_SIZE     equ     INTERPRETER_SEGMENT_END - INTERPRETER_SEGMENT
    .interp_segment_type    dd      3
    .interp_segment_flag    dd      0x4
    .interp_segment_offs    dq      INTERPRETER_SEGMENT
    .interp_segment_vadr    dq      _START_VAD + INTERPRETER_SEGMENT
    .interp_segment_padr    dq      _START_VAD + INTERPRETER_SEGMENT
    .interp_segment_file    dq      INTERP_SEGMENT_SIZE
    .interp_segment_mems    dq      INTERP_SEGMENT_SIZE
    .interp_segment_alig    dq      1

    CODE_SEGMENT_HEADER:
    CODE_SEGMENT_SIZE       equ     START_END - ELF_HEADER
    .code_segment_type      dd      1
    .code_segment_flag      dd      0x1 | 0x4
    .code_segment_offs      dq      0
    .code_segment_vadr      dq      _START_VAD
    .code_segment_padr      dq      _START_VAD
    .code_segment_file      dq      CODE_SEGMENT_SIZE
    .code_segment_mems      dq      CODE_SEGMENT_SIZE
    .code_segment_alig      dq      0x200000
PROGRAM_HEADER_END:

INTERPRETER_SEGMENT:
    .intepreter_path        db      "/lib64/ld-linux-x86-64.so.2", 0
INTERPRETER_SEGMENT_END:

START:
    mov    rax, 1           ; sys_write
    mov    rdi, 1           ; stdout
    mov    rsi, _START_VAD + message     ; message address
    mov    rdx, length      ; message string length
    syscall

    mov    rax, 60          ; sys_exit
    mov    rdi, 0           ; return 0 (success)
    syscall

    message:
        db 'Hello, world!',0x0A         ; message and newline
    length: equ    $-message            ; message length calculation
START_END:

SECTIONS_STRING_TABLE:
    NULL_SECTION_NAME:      db      0
    STR_TABLE_SECTION_NAME: db      ".shstrtab", 0
    INTERP_SECTION_NAME:    db      ".interp", 0
    TEXT_SECTION_NAME:      db      ".text", 0
SECTIONS_STRING_TABLE_END:

SECTIONS_HEADER:
    RESERVED_SECTION:
    .reserved_sh_name       dd      0
    .reserved_type          dd      0
    .reserved_flags         dq      0
    .reserved_vaddr         dq      0
    .reserved_offs          dq      0
    .reserved_size          dq      0
    .reserved_link          dd      0
    .reserved_info          dd      0
    .reserved_alig          dq      0
    .reserved_ents          dq      0

INTERPRETER_SECTION:
    .reserved_sh_name       dd      INTERP_SECTION_NAME - SECTIONS_STRING_TABLE
    .reserved_type          dd      1
    .reserved_flags         dq      0x2
    .reserved_vaddr         dq      _START_VAD + INTERPRETER_SEGMENT
    .reserved_offs          dq      INTERPRETER_SEGMENT
    .reserved_size          dq      INTERPRETER_SEGMENT_END - INTERPRETER_SEGMENT
    .reserved_link          dd      0
    .reserved_info          dd      0
    .reserved_alig          dq      1
    .reserved_ents          dq      0

TEXT_SECTION:
    .reserved_sh_name       dd      TEXT_SECTION_NAME - SECTIONS_STRING_TABLE
    .reserved_type          dd      1
    .reserved_flags         dq      0x2 | 0x4
    .reserved_vaddr         dq      _START_VAD + START
    .reserved_offs          dq      START
    .reserved_size          dq      START_END - START
    .reserved_link          dd      0
    .reserved_info          dd      0
    .reserved_alig          dq      16
    .reserved_ents          dq      0

    STRINGTABLE_SECTION:
    .reserved_sh_name       dd      STR_TABLE_SECTION_NAME - SECTIONS_STRING_TABLE
    .reserved_type          dd      3
    .reserved_flags         dq      0
    .reserved_vaddr         dq      0
    .reserved_offs          dq      SECTIONS_STRING_TABLE
    .reserved_size          dq      SECTIONS_STRING_TABLE_END - SECTIONS_STRING_TABLE
    .reserved_link          dd      0
    .reserved_info          dd      0
    .reserved_alig          dq      1
    .reserved_ents          dq      0
SECTIONS_HEADER_END:

我将此转换为带有NASM的ELF文件,并使用 READELF 获取此信息:

Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
Class:                             ELF64
Data:                              2's complement, little endian
Version:                           1 (current)
OS/ABI:                            UNIX - System V
ABI Version:                       0
Type:                              EXEC (Executable file)
Machine:                           Advanced Micro Devices X86-64
Version:                           0x1
Entry point address:               0x400104
Start of program headers:          64 (bytes into file)
Start of section headers:          363 (bytes into file)
Flags:                             0x0
Size of this header:               64 (bytes)
Size of program headers:           56 (bytes)
Number of program headers:         3
Size of section headers:           64 (bytes)
Number of section headers:         4
Section header string table index: 3

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         00000000004000e8  000000e8
      000000000000001c  0000000000000000   A       0     0     1
  [ 2] .text             PROGBITS         0000000000400104  00000104
       000000000000004e  0000000000000000  AX       0     0     16
  [ 3] .shstrtab         STRTAB           0000000000000000  00000152
       0000000000000019  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000000a8 0x00000000000000a8  R E    8
  INTERP         0x00000000000000e8 0x00000000004000e8 0x00000000004000e8
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000152 0x0000000000000152  R E    200000

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .text 

There is no dynamic section in this file.

There are no relocations in this file.

There are no unwind sections in this file.

No version information found in this file.

我不确定是否正确,特别是LOAD段及其大小。 当我运行这个时,我得到Segmentation Fault (core dumped)。调试器会告诉我更多信息:

warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7de5be2 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) 

我不知道哪些段或部分丢失或哪些偏移/地址错误。也许在ELF和Linux加载器方面有更多经验的人会给我一点推动因为我真的被卡住了。

1 个答案:

答案 0 :(得分:2)

  

我不知道哪些段或部分缺失或哪些偏移/地址错误。

您的二进制文件具有PT_INTERP段,这使得Linux内核认为它是动态链接的二进制文件。但它没有PT_DYNAMIC段,ld-linux期望。

删除对INTERPRETER_{SEGMENT,SECTION}的所有引用并调整程序头和节的数量会将其转换为完全静态的二进制文件,它可以工作:

nasm t.s
./t
Hello, world!

readelf -l t

Elf file type is EXEC (Executable file)
Entry point 0x4000b0
There are 2 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x0000000000000070 0x0000000000000070  R E    8
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000000fe 0x00000000000000fe  R E    200000

 Section to Segment mapping:
  Segment Sections...
   00
   01     .text