How to calculate the virtual address for an ELF program header?

1

I've wrote to file some assembly instructions and I would like to make them executable. However, I'm messing up something with the program headers. I've read the whole man page about the ELF header, but I didn't understand much.

#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);
}

When I execute the ex.out It gives a segmentation fault and a core dump. This is what the core dump looks like.

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 ...

It really did allocate a 4096 bytes page for me, so what could be the problem here? This is the 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 

Also when I try to run gdb with it, It also gives a segmentation fault: "Program received signal SIGSEGV, Segmentation fault. 0x00007fffeffae040 in ??"

EDIT

Moreover, if I set p_vaddr to 0 no segmentation fault occurs, however the code doesn't behave like expected. For example, if I put an print instruction on the code, nothing gets printed on the command line when the file is executed.

c++
elf
coredump
asked on Stack Overflow Apr 1, 2020 by Marco Vinicio • edited Apr 3, 2020 by vtronko

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0