mirror of
https://github.com/samsonjs/compiler.git
synced 2026-03-25 08:45:52 +00:00
288 lines
8.5 KiB
C
288 lines
8.5 KiB
C
#include <libelf.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
/* _exit(0) */
|
|
/* uint8_t shell_code[] = { */
|
|
/* 0xbb, 0, 0, 0, 0, /\* mov ebx, 0 *\/ */
|
|
/* 0xb8, 1, 0, 0, 0, /\* mov eax, 1 *\/ */
|
|
/* 0xcd, 0x80 /\* int 0x80 *\/ */
|
|
/* }; */
|
|
|
|
/* uint32_t hash_words[] = { */
|
|
/* 0x12345678, */
|
|
/* 0xdeadc0de, */
|
|
/* 0x1234abcd */
|
|
/* }; */
|
|
|
|
#define header_size 0x100
|
|
#define text_addr 0x8048000 + header_size
|
|
#define text_size 0x02be00
|
|
#define data_addr text_addr + text_size
|
|
#define data_size 0x4e00
|
|
#define bss_addr data_addr + data_size
|
|
size_t bss_size = 0;
|
|
|
|
char string_table[] = {
|
|
/* Offset 0 */ '\0',
|
|
/* Offset 1 */ '.', 't', 'e', 'x', 't', '\0' ,
|
|
/* Offset 7 */ '.', 'b', 's', 's', '\0',
|
|
/* Offset 12 */ '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0'
|
|
};
|
|
|
|
|
|
/* Write a static 32-bit x86 ELF binary to filename. The file is
|
|
* clobbered without confirmation!
|
|
*/
|
|
int
|
|
elf_write(const char *filename, uint8_t *code, size_t code_size)
|
|
{
|
|
int fd;
|
|
size_t shstrndx;
|
|
Elf *elf;
|
|
Elf_Scn *scn;
|
|
Elf_Data *data;
|
|
Elf32_Ehdr *ehdr;
|
|
Elf32_Phdr *phdr;
|
|
Elf32_Shdr *shdr;
|
|
|
|
if (elf_version(EV_CURRENT) == EV_NONE) {
|
|
printf("Failed to initialize ELF library!\n");
|
|
return -1;
|
|
}
|
|
if ((fd = open(filename, O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) {
|
|
printf("Can't open %s for writing.\n", filename);
|
|
perror("[elf_write]");
|
|
return -2;
|
|
}
|
|
if ((elf = elf_begin(fd, ELF_C_WRITE, (Elf *)0)) == 0) {
|
|
printf("elf_begin failed!\n");
|
|
return -3;
|
|
}
|
|
|
|
|
|
/**************
|
|
* ELF Header *
|
|
**************/
|
|
|
|
if ((ehdr = elf32_newehdr(elf)) == NULL) {
|
|
printf("elf32_newehdr failed!\n");
|
|
return -4;
|
|
}
|
|
ehdr->e_ident[EI_DATA] = ELFDATA2LSB; /* 2's complement, little endian */
|
|
ehdr->e_type = ET_EXEC;
|
|
ehdr->e_machine = EM_386; /* x86 */
|
|
|
|
/* Image starts at 0x8048000, x86 32-bit abi. We need a bit
|
|
* of room for headers and such. TODO figure out how much
|
|
* room is needed!
|
|
*
|
|
* Current entry point is .text section.
|
|
*/
|
|
ehdr->e_entry = text_addr;
|
|
|
|
|
|
/*******************
|
|
* Program Headers *
|
|
*******************/
|
|
|
|
/* 3 segments => 3 program headers (text, data, bss) */
|
|
if ((phdr = elf32_newphdr(elf, 3)) == NULL) {
|
|
printf("elf32_newphdr failed!\n");
|
|
return -5;
|
|
}
|
|
|
|
|
|
/*****************
|
|
* .text section *
|
|
*****************/
|
|
|
|
if ((scn = elf_newscn(elf)) == NULL) {
|
|
printf("elf_newscn failed!\n");
|
|
return -6;
|
|
}
|
|
if ((data = elf_newdata(scn)) == NULL) {
|
|
printf("elf_newdata failed!\n");
|
|
return -7;
|
|
}
|
|
data->d_align = 16;
|
|
data->d_buf = code;
|
|
data->d_off = 0LL;
|
|
data->d_type = ELF_T_BYTE;
|
|
data->d_size = code_size;
|
|
data->d_version = EV_CURRENT;
|
|
|
|
if ((shdr = elf32_getshdr(scn)) == NULL) {
|
|
printf("elf32_getshdr failed!\n");
|
|
return -8;
|
|
}
|
|
shdr->sh_name = 1;
|
|
shdr->sh_type = SHT_PROGBITS;
|
|
shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
|
shdr->sh_addr = text_addr;
|
|
|
|
|
|
/****************
|
|
* .bss section *
|
|
****************/
|
|
|
|
if ((scn = elf_newscn(elf)) == NULL) {
|
|
printf("elf_newscn failed!\n");
|
|
return -6;
|
|
}
|
|
if ((data = elf_newdata(scn)) == NULL) {
|
|
printf("elf_newdata failed!\n");
|
|
return -7;
|
|
}
|
|
data->d_align = 4;
|
|
data->d_off = 0LL;
|
|
data->d_type = ELF_T_BYTE;
|
|
data->d_size = bss_size;
|
|
data->d_version = EV_CURRENT;
|
|
|
|
if ((shdr = elf32_getshdr(scn)) == NULL) {
|
|
printf("elf32_getshdr failed!\n");
|
|
return -8;
|
|
}
|
|
shdr->sh_name = 7;
|
|
shdr->sh_type = SHT_NOBITS;
|
|
shdr->sh_flags = SHF_WRITE | SHF_ALLOC;
|
|
shdr->sh_addr = bss_addr;
|
|
|
|
|
|
/*******************************
|
|
* section header string table *
|
|
*******************************/
|
|
|
|
if ((scn = elf_newscn(elf)) == NULL) {
|
|
printf("elf_newscn failed!\n");
|
|
return -9;
|
|
}
|
|
if ((data = elf_newdata(scn)) == NULL) {
|
|
printf("elf_newdata failed!\n");
|
|
return -10;
|
|
}
|
|
data->d_align = 1;
|
|
data->d_buf = string_table;
|
|
data->d_off = 0LL;
|
|
data->d_type = ELF_T_BYTE;
|
|
data->d_size = sizeof(string_table);
|
|
data->d_version = EV_CURRENT;
|
|
|
|
if ((shdr = elf32_getshdr(scn)) == NULL) {
|
|
printf("elf32_getshdr failed!\n");
|
|
return -11;
|
|
}
|
|
shdr->sh_name = 12;
|
|
shdr->sh_type = SHT_STRTAB;
|
|
shdr->sh_flags = SHF_STRINGS | SHF_ALLOC;
|
|
shdr->sh_entsize = 0;
|
|
|
|
|
|
/* int elf_setshstrndx(Elf *e, Elf32_Ehdr *eh, size_t shstrndx) */
|
|
shstrndx = elf_ndxscn(scn);
|
|
if (shstrndx >= SHN_LORESERVE) {
|
|
if ((scn = elf_getscn(elf, 0)) == NULL) {
|
|
printf("elf_getscn failed!\n");
|
|
return -12;
|
|
}
|
|
/* assert(scn->s_ndx == SHN_UNDEF); */
|
|
/* scn->s_shdr.s_shdr32.sh_link = shstrndx; */
|
|
elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
|
|
shstrndx = SHN_XINDEX;
|
|
}
|
|
ehdr->e_shstrndx = shstrndx;
|
|
|
|
if (elf_update(elf, ELF_C_NULL) < 0) {
|
|
printf("elf_update failed!\n");
|
|
return -12;
|
|
}
|
|
|
|
/* phdr->p_vaddr = phdr->p_paddr = 0x8048000 + ehdr->e_phoff; */
|
|
/* phdr->p_type = PT_PHDR; */
|
|
/* phdr->p_offset = ehdr->e_phoff; */
|
|
/* phdr->p_filesz = elf32_fsize(ELF_T_PHDR, 1, EV_CURRENT); */
|
|
|
|
/* text segment */
|
|
phdr->p_vaddr = text_addr;
|
|
phdr->p_type = PT_LOAD;
|
|
phdr->p_offset = header_size;
|
|
phdr->p_filesz = text_size;
|
|
phdr->p_memsz = text_size;
|
|
phdr->p_flags = PF_R | PF_X;
|
|
phdr->p_align = 0x1000;
|
|
|
|
/* data segment */
|
|
phdr++;
|
|
phdr->p_vaddr = data_addr;
|
|
phdr->p_type = PT_LOAD;
|
|
phdr->p_offset = header_size + text_size;
|
|
phdr->p_filesz = data_size;
|
|
phdr->p_memsz = data_size + 0x1024; /* XXX unsure why the abi specifies + 0x1024 */
|
|
phdr->p_flags = PF_R | PF_W | PF_X;
|
|
phdr->p_align = 0x1000;
|
|
|
|
/* bss segment */
|
|
phdr++;
|
|
phdr->p_vaddr = bss_addr;
|
|
phdr->p_type = PT_LOAD;
|
|
phdr->p_offset = header_size + text_size + data_size;
|
|
phdr->p_filesz = bss_size;
|
|
phdr->p_memsz = bss_size;
|
|
phdr->p_flags = PF_R | PF_W;
|
|
phdr->p_align = 0x1000;
|
|
|
|
elf_flagphdr(elf, ELF_C_SET, ELF_F_DIRTY);
|
|
|
|
if (elf_update(elf, ELF_C_WRITE) < 0) {
|
|
printf("elf_update failed!\n");
|
|
return -13;
|
|
}
|
|
|
|
elf_end(elf);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
main(int argc, const char *argv[])
|
|
{
|
|
int result;
|
|
pid_t pid;
|
|
FILE *fd;
|
|
uint8_t *code = NULL;
|
|
size_t code_size = 0, chunk_size = 1024, bytes_read;
|
|
|
|
if (argc < 4) {
|
|
printf("usage: %s <input> <bss_size> <output>\n", argv[0]);
|
|
printf(" Wraps the input file in an ELF binary.\n");
|
|
return 1;
|
|
}
|
|
|
|
bss_size = strtoul(argv[2], 0, 10);
|
|
|
|
if ((fd = fopen(argv[1], "r")) < 0) {
|
|
printf("[error] can't open %s for reading.\n", argv[1]);
|
|
perror("[main]");
|
|
return 2;
|
|
}
|
|
while (!feof(fd) && !ferror(fd)) {
|
|
code = realloc(code, code_size + chunk_size);
|
|
bytes_read = fread(code+code_size, 1, chunk_size, fd);
|
|
code_size += bytes_read;
|
|
}
|
|
fclose(fd);
|
|
|
|
printf("Writing x86 ELF binary to %s...\n", argv[3]);
|
|
result = elf_write(argv[3], code, code_size);
|
|
if (result < 0) {
|
|
printf("[error] elf_write failed.\n");
|
|
return 3;
|
|
}
|
|
|
|
return 0;
|
|
}
|