Как рассчитать виртуальный адрес для заголовка программы ELF? - PullRequest
1 голос
/ 01 апреля 2020

Я написал в файл некоторые инструкции по сборке и хотел бы сделать их исполняемыми. Однако я что-то путаю с заголовками программы. Я прочитал всю справочную страницу о заголовке ELF, но мало что понял.

#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>


void MakeExecutable(char *codeBuffer, char *startAddr, unsigned int codeSize){
    char *fileBuffer = (char*) malloc(2058);
    memset(fileBuffer, 0, 2058);

    //I've omitted the sections declaration

    unsigned int codeOffset = sizeof(Elf64_Ehdr) + (unsigned int ) (startAddr - codeBuffer);


    Elf64_Ehdr *h = (Elf64_Ehdr*) &fileBuffer[0];
    h->e_ident[0] = 0x7f;
    h->e_ident[1] = 0x45;
    h->e_ident[2] = 0x4c;
    h->e_ident[3] = 0x46;
    h->e_ident[EI_CLASS] = ELFCLASS64;
    h->e_ident[EI_DATA]  = ELFDATA2LSB;  
    h->e_ident[EI_VERSION]  = EV_CURRENT; 
    h->e_ident[EI_OSABI]  = ELFOSABI_SYSV;
    h->e_type    = ET_DYN;
    h->e_machine = EM_X86_64;
    h->e_version = EV_CURRENT;
    h->e_entry   = 64;
    h->e_phentsize = sizeof(Elf64_Phdr);
    h->e_shentsize = sizeof(Elf64_Shdr);
    h->e_shoff   = 0;
    h->e_phoff   = 800;
    h->e_shnum   = 0;
    h->e_phnum   = 1;
    h->e_shstrndx= 0;

    h->e_ehsize     = sizeof(Elf64_Ehdr);

    Elf64_Phdr *ph = (Elf64_Phdr*) &fileBuffer[800];
    ph->p_type = PT_LOAD;
    ph->p_vaddr = 0x8050000;
    ph->p_paddr = 0;
    ph->p_offset = 0x4000;
    ph->p_memsz  = 2058;
    ph->p_flags  = PF_X | PF_R | PF_W;
    ph->p_filesz = 2058;
    ph->p_align = 0x100000;

    int file = open("ex.out", O_TRUNC | O_RDWR, S_IRWXO | S_IRWXU | S_IRWXG );
    int error = write(file, fileBuffer, 2058);
    close(file);
}

Когда я выполняю ex.out, он дает ошибку сегментации и дамп ядра. Вот как выглядит дамп ядра.

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  NOTE           0x0000000000000158 0x0000000000000000 0x0000000000000000
                 0x0000000000000aac 0x0000000000000000         0x0
  LOAD           0x0000000000001000 0x00007f1a823b2000 0x0000000000000000
                 0x0000000000000000 0x0000000000001000  RWE    0x1000
  LOAD           0x0000000000001000 0x00007fff4a1d0000 0x0000000000000000
                 0x0000000000021000 0x0000000000021000  RWE    0x1000
  LOAD           0x0000000000022000 0x00007fff4a1f1000 0x0000000000000000
                 0x0000000000003000 0x0000000000003000  R      0x1000
  LOAD           0x0000000000025000 0x00007fff4a1f4000 0x0000000000000000
                 0x0000000000002000 0x0000000000002000  R E    0x1000


Displaying notes found at file offset 0x00000158 with length 0x00000aac:
  Owner                 Data size       Description
  CORE                 0x00000150       NT_PRSTATUS (prstatus structure)
  CORE                 0x00000088       NT_PRPSINFO (prpsinfo structure)
  CORE                 0x00000080       NT_SIGINFO (siginfo_t data)
  CORE                 0x00000140       NT_AUXV (auxiliary vector)
  CORE                 0x00000048       NT_FILE (mapped files)
    Page size: 4096
                 Start                 End         Page Offset
    0x00007f1a823b2000  0x00007f1a823b3000  0x0000000000000004
        /home/sudo_user/Compiler/ex.out
  CORE                 0x00000200       NT_FPREGSET (floating point registers)
  LINUX                0x00000440       NT_X86_XSTATE (x86 XSAVE extended state)
   description data: ffffffdf 66 f ...

Он действительно выделил мне страницу в 4096 байт, так что может быть проблема здесь? Это objdump

ex.out:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 81 ec 01 00 00 00    sub    $0x1,%rsp
   b:   8a 85 10 00 00 00       mov    0x10(%rbp),%al
  11:   88 85 ff ff ff ff       mov    %al,-0x1(%rbp)
  17:   49 c7 c1 00 00 00 00    mov    $0x0,%r9
  1e:   49 c7 c0 00 00 00 00    mov    $0x0,%r8
  25:   49 c7 c2 00 00 00 00    mov    $0x0,%r10
  2c:   48 c7 c2 00 00 00 00    mov    $0x0,%rdx
  33:   48 c7 c6 00 00 00 00    mov    $0x0,%rsi
  3a:   48 c7 c7 00 00 00 00    mov    $0x0,%rdi
  41:   48 c7 c0 3c 00 00 00    mov    $0x3c,%rax
  48:   0f 05                   syscall 
  4a:   48 89 ec                mov    %rbp,%rsp
  4d:   5d                      pop    %rbp
  4e:   c3                      retq 

Также, когда я пытаюсь запустить с ним gdb, он также выдает ошибку сегментации: «Программа получила сигнал SIGSEGV, Ошибка сегментации. 0x00007fffeffae040 in ??»

РЕДАКТИРОВАТЬ

Более того, если я установлю p_vaddr в 0, ошибки сегментации не произойдет, однако код не будет работать так, как ожидалось. Например, если я добавлю инструкцию печати в код, при выполнении файла ничего не будет напечатано в командной строке.

...