Я написал в файл некоторые инструкции по сборке и хотел бы сделать их исполняемыми. Однако я что-то путаю с заголовками программы. Я прочитал всю справочную страницу о заголовке 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, ошибки сегментации не произойдет, однако код не будет работать так, как ожидалось. Например, если я добавлю инструкцию печати в код, при выполнении файла ничего не будет напечатано в командной строке.