2014-02-26 28 views
2

移植可執行和Windows產品,我想創建一個小ELF可執行NASM的Linux(Ubuntu的AMD64)。我的一小段代碼看起來是這樣的:微小的「手工」創建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加載器方面有更多經驗的人會給我一點點推動力,因爲我真的被困住了。

+0

你看過[Linux的裝配方法文檔(HTTP:// TLDP。組織/ HOWTO /裝配-HOWTO /)?一般來說,避免在手寫彙編器中編碼。編譯器優化比你我更好。 –

+0

我知道,但這僅僅是爲了教育目的。如果我要構建一些嚴肅的應用程序,我當然會使用C++(或其他一些高級語言) – ali

回答

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 
+0

是的。它看起來像我不明白動態鏈接/靜態二進制之間的區別。你是一個Linux大師,男人。謝謝 – ali