summaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/.envrc1
-rw-r--r--elf/.gitignore7
-rw-r--r--elf/Makefile55
-rw-r--r--elf/elf.pdfbin0 -> 4584428 bytes
-rw-r--r--elf/include/lcq/elf.h239
-rw-r--r--elf/include/lcq/elf/platform/amd64.h26
-rw-r--r--elf/include/lcq/elf/platform/x86.h22
-rw-r--r--elf/packages.nix14
-rw-r--r--elf/src/elf.c490
-rw-r--r--elf/src/main.c204
10 files changed, 1058 insertions, 0 deletions
diff --git a/elf/.envrc b/elf/.envrc
new file mode 100644
index 0000000..c4b17d7
--- /dev/null
+++ b/elf/.envrc
@@ -0,0 +1 @@
+use_flake
diff --git a/elf/.gitignore b/elf/.gitignore
new file mode 100644
index 0000000..e65382e
--- /dev/null
+++ b/elf/.gitignore
@@ -0,0 +1,7 @@
+./6502
+build_*/
+.direnv/
+TAGS
+*.o
+*.a
+*.so \ No newline at end of file
diff --git a/elf/Makefile b/elf/Makefile
new file mode 100644
index 0000000..0d5db59
--- /dev/null
+++ b/elf/Makefile
@@ -0,0 +1,55 @@
+CC ?= gcc
+AR ?= ar
+override CPPFLAGS += -MMD -MP
+override CFLAGS += -march=native --std=c89 -g -Ideps/ -Isrc/ -Iinclude/ -Wall -Wextra -Wpedantic -Wconversion -Wformat-security -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wnull-dereference -Wfloat-equal -Wundef -Wpointer-arith -Wbad-function-cast -Wlogical-op -Wmissing-braces -Wcast-align -Wstrict-overflow=5 -ftrapv
+override += -g -static
+
+BUILD = build_$(CC)
+
+SRCS := src/elf.c
+CHK_SOURCES ?= src/main.c $(SRCS)
+OBJECTS := $(SRCS:src/%.c=$(BUILD)/%.o)
+EXE := elf
+LIB := libcolonq-elf.a
+
+prefix ?= /usr/local
+exec_prefix ?= $(prefix)
+bindir ?= $(exec_prefix)/bin
+includedir ?= $(prefix)/include
+libdir ?= $(exec_prefix)/lib
+
+.PHONY: all clean install check-syntax
+
+all: $(EXE) $(LIB)
+
+$(EXE): $(BUILD)/main.o $(LIB)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(LIB): $(OBJECTS)
+ ar rcs $@ $^
+
+$(BUILD):
+ mkdir $(BUILD)/
+
+$(BUILD)/%.o: src/%.c | $(BUILD)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
+
+clean:
+ -rm $(EXE)
+ -rm $(LIB)
+ -rm -r $(BUILD)/
+
+TAGS: $(SRCS)
+ ctags --output-format=etags $^
+
+install: $(EXE) $(LIB)
+ mkdir -p $(DESTDIR)$(bindir) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir)
+ install $(EXE) $(DESTDIR)$(bindir)/$(EXE)
+ install $(LIB) $(DESTDIR)$(libdir)/$(LIB)
+ cp -r include/* $(DESTDIR)$(includedir)
+
+check-syntax: TAGS
+ gcc $(CFLAGS) -fsyntax-only $(CHK_SOURCES)
+
+-include $(BUILD)/main.d
+-include $(OBJECTS:.o=.d)
diff --git a/elf/elf.pdf b/elf/elf.pdf
new file mode 100644
index 0000000..f193f57
--- /dev/null
+++ b/elf/elf.pdf
Binary files differ
diff --git a/elf/include/lcq/elf.h b/elf/include/lcq/elf.h
new file mode 100644
index 0000000..57a1d3f
--- /dev/null
+++ b/elf/include/lcq/elf.h
@@ -0,0 +1,239 @@
+#ifndef LCOLONQ_ELF_H
+#define LCOLONQ_ELF_H
+
+#include <lcq/prelude.h>
+#include <lcq/elf/platform/x86.h>
+#include <lcq/elf/platform/amd64.h>
+
+/* context */
+typedef enum elf_class {
+ ELF_CLASS_INVALID = 0,
+ ELF_CLASS_32 = 1,
+ ELF_CLASS_64 = 2
+} elf_class;
+typedef enum elf_endianness {
+ ELF_ENDIANNESS_INVALID = 0,
+ ELF_ENDIANNESS_LITTLE = 1,
+ ELF_ENDIANNESS_BIG = 2
+} elf_endianness;
+#define ELF_HEADER_IDENT_SIZE 16
+typedef struct elf_header_ident {
+ elf_class file_class;
+ elf_endianness endianness;
+ u8 version;
+ u8 abi;
+ u8 abi_version;
+} elf_header_ident;
+typedef struct elf_ctx {
+ u8 *buf; i64 len;
+ elf_header_ident ident;
+} elf_ctx;
+i64 elf_read_header_ident(elf_header_ident *i, u8 *buf, i64 len);
+i64 elf_write_header_ident(elf_header_ident *i, u8 *buf, i64 len);
+elf_ctx elf_load_from_path(char *p);
+elf_ctx elf_ctx_new(u8 *buf, i64 len, elf_class cl, elf_endianness end);
+
+/* header */
+typedef enum elf_type {
+ ELF_TYPE_NONE = 0,
+ ELF_TYPE_REL = 1,
+ ELF_TYPE_EXEC = 2,
+ ELF_TYPE_DYN = 3,
+ ELF_TYPE_CORE = 4,
+ ELF_TYPE_LO_OS = 0xfe00, ELF_TYPE_HI_OS = 0xfeff,
+ ELF_TYPE_LO_PROC = 0xff00, ELF_TYPE_HI_PROC = 0xffff
+} elf_type;
+typedef enum elf_machine {
+ ELF_MACHINE_NONE = 0,
+ ELF_MACHINE_X86 = 3,
+ ELF_MACHINE_AMD64 = 62
+} elf_machine;
+#define ELF32_HEADER_SIZE 52
+#define ELF64_HEADER_SIZE 64
+i64 elf_header_size(elf_ctx *ctx);
+typedef struct elf_header {
+ elf_type type;
+ elf_machine machine;
+ u32 version;
+ u64 entry;
+ u64 program_header_offset;
+ u64 section_header_offset;
+ u32 flags;
+ u16 elf_header_size;
+ u16 program_header_entry_size;
+ u16 program_header_entries;
+ u16 section_header_entry_size;
+ u16 section_header_entries;
+ u16 section_name_table_index;
+} elf_header;
+i64 elf_read_header(elf_header *ret, elf_ctx *ctx);
+i64 elf_write_header(elf_header *h, elf_ctx *ctx);
+u64 elf_program_header_offset(elf_header *h, u64 idx);
+u64 elf_section_header_offset(elf_header *h, u64 idx);
+
+/* section header */
+typedef enum elf_section_type {
+ ELF_SECTION_TYPE_NULL = 0,
+ ELF_SECTION_TYPE_PROGBITS = 1,
+ ELF_SECTION_TYPE_SYMTAB = 2,
+ ELF_SECTION_TYPE_STRTAB = 3,
+ ELF_SECTION_TYPE_RELA = 4,
+ ELF_SECTION_TYPE_HASH = 5,
+ ELF_SECTION_TYPE_DYNAMIC = 6,
+ ELF_SECTION_TYPE_NOTE = 7,
+ ELF_SECTION_TYPE_NOBITS = 8,
+ ELF_SECTION_TYPE_REL = 9,
+ ELF_SECTION_TYPE_SHLIB = 10,
+ ELF_SECTION_TYPE_DYNSYM = 11,
+ ELF_SECTION_TYPE_INIT_ARRAY = 14,
+ ELF_SECTION_TYPE_FINI_ARRAY = 15,
+ ELF_SECTION_TYPE_PREINIT_ARRAY = 16,
+ ELF_SECTION_TYPE_GROUP = 17,
+ ELF_SECTION_TYPE_SYMTAB_SHNDX = 18
+} elf_section_type;
+/* enums are only guaranteed to represent signed int in c89 */
+#define ELF_SECTION_TYPE_LO_OS 0x60000000
+#define ELF_SECTION_TYPE_HI_OS 0x6fffffff
+#define ELF_SECTION_TYPE_LO_PROC 0x70000000
+#define ELF_SECTION_TYPE_HI_PROC 0x7fffffff
+#define ELF_SECTION_TYPE_LO_USER 0x80000000
+#define ELF_SECTION_TYPE_HI_USER 0x8fffffff
+typedef enum elf_section_flag {
+ ELF_SECTION_FLAG_WRITE = 0x1,
+ ELF_SECTION_FLAG_ALLOC = 0x2,
+ ELF_SECTION_FLAG_EXECINSTR = 0x4,
+ ELF_SECTION_FLAG_MERGE = 0x10,
+ ELF_SECTION_FLAG_STRINGS = 0x20,
+ ELF_SECTION_FLAG_INFO_LINK = 0x40,
+ ELF_SECTION_FLAG_LINK_ORDER = 0x80,
+ ELF_SECTION_FLAG_OS_NONCOMFORMING = 0x100,
+ ELF_SECTION_FLAG_GROUP = 0x200,
+ ELF_SECTION_FLAG_TLS = 0x400,
+ ELF_SECTION_FLAG_COMPRESSED = 0x800
+} elf_section_flag;
+#define ELF_SECTION_FLAG_MASKOS 0x0ff00000
+#define ELF_SECTION_FLAG_MASKPROC 0xf0000000
+#define ELF32_SECTION_HEADER_SIZE 40
+#define ELF64_SECTION_HEADER_SIZE 64
+i64 elf_section_header_size(elf_ctx *ctx);
+typedef struct elf_section_header {
+ u32 name_index;
+ u32 /* elf_section_type */ type;
+ u64 /* elf_section_flag */ flags;
+ u64 addr;
+ u64 offset;
+ u64 size;
+ u32 link;
+ u32 info;
+ u64 addr_alignment;
+ u64 entry_size;
+} elf_section_header;
+i64 elf_read_section_header(elf_section_header *ret, elf_ctx *ctx, u64 off);
+i64 elf_write_section_header(elf_section_header *sh, elf_ctx *ctx, u64 off);
+char *elf_read_section_name(elf_ctx *ctx, elf_header *h, elf_section_header *sh);
+
+/* symbols */
+typedef enum elf_symbol_binding {
+ ELF_SYMBOL_BINDING_LOCAL = 0,
+ ELF_SYMBOL_BINDING_GLOBAL = 1,
+ ELF_SYMBOL_BINDING_WEAK = 2,
+ ELF_SYMBOL_BINDING_LO_OS = 10,
+ ELF_SYMBOL_BINDING_HI_OS = 12,
+ ELF_SYMBOL_BINDING_LO_PROC = 13,
+ ELF_SYMBOL_BINDING_HI_PROC = 15
+} elf_symbol_binding;
+typedef enum elf_symbol_type {
+ ELF_SYMBOL_TYPE_NOTYPE = 0,
+ ELF_SYMBOL_TYPE_OBJECT = 1,
+ ELF_SYMBOL_TYPE_FUNC = 2,
+ ELF_SYMBOL_TYPE_SECTION = 3,
+ ELF_SYMBOL_TYPE_FILE = 4,
+ ELF_SYMBOL_TYPE_COMMON = 5,
+ ELF_SYMBOL_TYPE_TLS = 6,
+ ELF_SYMBOL_TYPE_LO_OS = 10,
+ ELF_SYMBOL_TYPE_HI_OS = 12,
+ ELF_SYMBOL_TYPE_LO_PROC = 13,
+ ELF_SYMBOL_TYPE_HI_PROC = 15
+} elf_symbol_type;
+typedef enum elf_symbol_visibility {
+ ELF_SYMBOL_VISIBILITY_DEFAULT = 0,
+ ELF_SYMBOL_VISIBILITY_INTERNAL = 1,
+ ELF_SYMBOL_VISIBILITY_HIDDEN = 2,
+ ELF_SYMBOL_VISIBILITY_PROTECTED = 3
+} elf_symbol_visibility;
+#define ELF32_SYMBOL_SIZE 16
+#define ELF64_SYMBOL_SIZE 24
+i64 elf_symbol_size(elf_ctx *ctx);
+typedef struct elf_symbol {
+ u64 size;
+ u64 value;
+ u32 name_index;
+ elf_symbol_binding bind; elf_symbol_type type; /* info */
+ elf_symbol_visibility visibility; /* other */
+ u16 section_header_index;
+} elf_symbol;
+i64 elf_read_symbol(elf_symbol *ret, elf_ctx *ctx, u64 off);
+i64 elf_write_symbol(elf_symbol *sym, elf_ctx *ctx, u64 off);
+char *elf_read_symbol_name(elf_ctx *ctx, elf_header *h, elf_section_header *sh, elf_symbol *sym);
+
+/* relocations */
+#define ELF32_REL_SIZE 8
+#define ELF64_REL_SIZE 16
+i64 elf_rel_size(elf_ctx *ctx);
+typedef struct elf_rel {
+ u64 offset;
+ u64 symtab_index, type; /* info */
+} elf_rel;
+#define ELF32_RELA_SIZE 12
+#define ELF64_RELA_SIZE 24
+i64 elf_rela_size(elf_ctx *ctx);
+typedef struct elf_rela {
+ u64 offset;
+ u64 symtab_index; u64 type;
+ i64 addend;
+} elf_rela;
+i64 elf_read_rel(elf_rel *ret, elf_ctx *ctx, u64 off);
+i64 elf_read_rela(elf_rela *ret, elf_ctx *ctx, u64 off);
+
+typedef enum elf_program_header_type {
+ ELF_PROGRAM_HEADER_TYPE_NULL = 0,
+ ELF_PROGRAM_HEADER_TYPE_LOAD = 1,
+ ELF_PROGRAM_HEADER_TYPE_DYNAMIC = 2,
+ ELF_PROGRAM_HEADER_TYPE_INTERP = 3,
+ ELF_PROGRAM_HEADER_TYPE_NOTE = 4,
+ ELF_PROGRAM_HEADER_TYPE_SHLIB = 5,
+ ELF_PROGRAM_HEADER_TYPE_PHDR = 6,
+ ELF_PROGRAM_HEADER_TYPE_TLS = 7
+} elf_program_header_type;
+#define ELF_PROGRAM_HEADER_TYPE_LOOS 0x60000000
+#define ELF_PROGRAM_HEADER_TYPE_HIOS 0x6fffffff
+#define ELF_PROGRAM_HEADER_TYPE_LOPROC 0x70000000
+#define ELF_PROGRAM_HEADER_TYPE_HIPROC 0x7fffffff
+typedef enum elf_program_header_flag {
+ ELF_PROGRAM_HEADER_FLAG_X = 0x1,
+ ELF_PROGRAM_HEADER_FLAG_W = 0x2,
+ ELF_PROGRAM_HEADER_FLAG_R = 0x4
+} elf_program_header_flag;
+#define ELF_PROGRAM_HEADER_FLAG_MASKOS 0xff00000
+#define ELF_PROGRAM_HEADER_FLAG_MASKPROC 0xf0000000
+#define ELF32_PROGRAM_HEADER_SIZE 32
+#define ELF64_PROGRAM_HEADER_SIZE 56
+i64 elf_program_header_size(elf_ctx *ctx);
+typedef struct elf_program_header {
+ u32 /* elf_program_header_type */ type;
+ u64 offset;
+ u64 virtual_addr;
+ u64 physical_addr;
+ u64 file_size;
+ u64 mem_size;
+ u32 /* elf_program_header_flag */ flags;
+ u64 align;
+} elf_program_header;
+i64 elf_read_program_header(elf_program_header *ret, elf_ctx *ctx, u64 off);
+i64 elf_write_program_header(elf_program_header *ph, elf_ctx *ctx, u64 off);
+
+/* writing bytes */
+i64 elf_write_bytes(elf_ctx *ctx, u64 *off, u8 *buf, i64 len);
+#define ELF_STRTAB_BYTES_OFF(str) (u8*)str,strlen(str)+1
+
+#endif
diff --git a/elf/include/lcq/elf/platform/amd64.h b/elf/include/lcq/elf/platform/amd64.h
new file mode 100644
index 0000000..19b4ffb
--- /dev/null
+++ b/elf/include/lcq/elf/platform/amd64.h
@@ -0,0 +1,26 @@
+#ifndef LCOLONQ_ELF_PLATFORM_AMD64_H
+#define LCOLONQ_ELF_PLATFORM_AMD64_H
+typedef enum elf_relocation_amd64 {
+ ELF_RELOCATION_AMD64_NONE = 0,
+ ELF_RELOCATION_AMD64_64 = 1,
+ ELF_RELOCATION_AMD64_PC32 = 2,
+ ELF_RELOCATION_AMD64_GOT32 = 3,
+ ELF_RELOCATION_AMD64_PLT32 = 4,
+ ELF_RELOCATION_AMD64_COPY = 5,
+ ELF_RELOCATION_AMD64_GLOB_DAT = 6,
+ ELF_RELOCATION_AMD64_JUMP_SLOT = 7,
+ ELF_RELOCATION_AMD64_RELATIVE = 8,
+ ELF_RELOCATION_AMD64_GOTPCREL = 9,
+ ELF_RELOCATION_AMD64_32 = 10,
+ ELF_RELOCATION_AMD64_32S = 11,
+ ELF_RELOCATION_AMD64_16 = 12,
+ ELF_RELOCATION_AMD64_PC16 = 13,
+ ELF_RELOCATION_AMD64_8 = 14,
+ ELF_RELOCATION_AMD64_PC8 = 15,
+ ELF_RELOCATION_AMD64_PC64 = 24,
+ ELF_RELOCATION_AMD64_GOTOFF64 = 25,
+ ELF_RELOCATION_AMD64_GOTPC32 = 26,
+ ELF_RELOCATION_AMD64_SIZE32 = 32,
+ ELF_RELOCATION_AMD64_SIZE64 = 33
+} elf_relocation_amd64;
+#endif
diff --git a/elf/include/lcq/elf/platform/x86.h b/elf/include/lcq/elf/platform/x86.h
new file mode 100644
index 0000000..37b57a3
--- /dev/null
+++ b/elf/include/lcq/elf/platform/x86.h
@@ -0,0 +1,22 @@
+#ifndef LCOLONQ_ELF_PLATFORM_X86_H
+#define LCOLONQ_ELF_PLATFORM_X86_H
+typedef enum elf_relocation_x86 {
+ ELF_RELOCATION_X86_NONE = 0,
+ ELF_RELOCATION_X86_32 = 1,
+ ELF_RELOCATION_X86_PC32 = 2,
+ ELF_RELOCATION_X86_GOT32 = 3,
+ ELF_RELOCATION_X86_PLT32 = 4,
+ ELF_RELOCATION_X86_COPY = 5,
+ ELF_RELOCATION_X86_GLOB_DAT = 6,
+ ELF_RELOCATION_X86_JMP_SLOT = 7,
+ ELF_RELOCATION_X86_RELATIVE = 8,
+ ELF_RELOCATION_X86_GOTOFF = 9,
+ ELF_RELOCATION_X86_GOTPC = 10,
+ ELF_RELOCATION_X86_32PLT = 11,
+ ELF_RELOCATION_X86_16 = 20,
+ ELF_RELOCATION_X86_PC16 = 21,
+ ELF_RELOCATION_X86_8 = 22,
+ ELF_RELOCATION_X86_PC8 = 23,
+ ELF_RELOCATION_X86_SIZE32 = 38
+} elf_relocation_x86;
+#endif
diff --git a/elf/packages.nix b/elf/packages.nix
new file mode 100644
index 0000000..bce9c82
--- /dev/null
+++ b/elf/packages.nix
@@ -0,0 +1,14 @@
+pkgs: lcq: {
+ native = pkgs.stdenv.mkDerivation {
+ pname = "libcolonq-elf";
+ version = "git";
+ src = ./.;
+ hardeningDisable = ["all"];
+ buildInputs = [
+ lcq.prelude.native
+ ];
+ installPhase = ''
+ make prefix=$out install
+ '';
+ };
+}
diff --git a/elf/src/elf.c b/elf/src/elf.c
new file mode 100644
index 0000000..ed0d145
--- /dev/null
+++ b/elf/src/elf.c
@@ -0,0 +1,490 @@
+#include <lcq/elf.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+i64 elf_read_header_ident(elf_header_ident *ret, u8 *buf, i64 len) {
+ if (len < ELF_HEADER_IDENT_SIZE) return -1;
+ if (buf[0] != 0x7f || buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F') return -1;
+ ret->file_class = buf[4];
+ ret->endianness = buf[5];
+ ret->version = buf[6];
+ ret->abi = buf[7];
+ ret->abi_version = buf[8];
+ return 0;
+}
+
+i64 elf_write_header_ident(elf_header_ident *i, u8 *buf, i64 len) {
+ if (len < ELF_HEADER_IDENT_SIZE) return -1;
+ buf[0] = 0x7f; buf[1] = 'E'; buf[2] = 'L'; buf[3] = 'F';
+ buf[4] = i->file_class;
+ buf[5] = i->endianness;
+ buf[6] = i->version;
+ buf[7] = i->abi;
+ buf[8] = i->abi_version;
+ return 0;
+}
+
+elf_ctx elf_load_from_path(char *p) {
+ FILE *f = NULL;
+ i64 len = 0;
+ u8 *buf = NULL;
+ elf_ctx ret;
+ ret.buf = NULL; ret.len = -1;
+ if (!p) return ret;
+ f = fopen(p, "r");
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ buf = calloc((size_t) len, sizeof(u8));
+ if ((size_t) len != fread(buf, sizeof(u8), (size_t) len, f)
+ || elf_read_header_ident(&ret.ident, buf, len) < 0) {
+ free(buf);
+ } else {
+ ret.buf = buf; ret.len = len;
+ }
+ fclose(f);
+ return ret;
+}
+
+elf_ctx elf_ctx_new(u8 *buf, i64 len, elf_class cl, elf_endianness end) {
+ elf_ctx ret;
+ ret.buf = buf; ret.len = len;
+ ret.ident.file_class = cl;
+ ret.ident.endianness = end;
+ ret.ident.version = 1;
+ ret.ident.abi = 0;
+ ret.ident.abi_version = 0;
+ elf_write_header_ident(&ret.ident, ret.buf, ret.len);
+ return ret;
+}
+
+static u8 read_u8(elf_ctx *ctx, u64 *off) {
+ assert(off != NULL);
+ assert((i64) *off < ctx->len);
+ return ctx->buf[(*off)++];
+}
+static void write_u8(elf_ctx *ctx, u64 *off, u8 x) {
+ assert(off != NULL);
+ assert((i64) *off < ctx->len);
+ ctx->buf[(*off)++] = x;
+}
+static u16 read_u16(elf_ctx *ctx, u64 *off) {
+ u16 b0, b1;
+ assert(off != NULL);
+ assert((i64) *off < ctx->len);
+ assert(ctx->ident.endianness == ELF_ENDIANNESS_LITTLE
+ || ctx->ident.endianness == ELF_ENDIANNESS_BIG);
+ b0 = ctx->buf[(*off)++]; b1 = ctx->buf[(*off)++];
+ if (ctx->ident.endianness == ELF_ENDIANNESS_LITTLE) {
+ return b0 | b1 << 8;
+ } else {
+ return b0 << 8 | b1;
+ }
+}
+static void write_u16(elf_ctx *ctx, u64 *off, u16 x) {
+ u16 b0, b1;
+ assert(off != NULL);
+ assert((i64) *off < ctx->len);
+ assert(ctx->ident.endianness == ELF_ENDIANNESS_LITTLE
+ || ctx->ident.endianness == ELF_ENDIANNESS_BIG);
+ b0 = x; b1 = x >> 8;
+ if (ctx->ident.endianness == ELF_ENDIANNESS_LITTLE) {
+ ctx->buf[(*off)++] = (u8) b0; ctx->buf[(*off)++] = (u8) b1;
+ } else {
+ ctx->buf[(*off)++] = (u8) b1; ctx->buf[(*off)++] = (u8) b0;
+ }
+}
+static u32 read_u32(elf_ctx *ctx, u64 *off) {
+ u32 b0, b1, b2, b3;
+ assert(off != NULL);
+ assert((i64) *off < ctx->len);
+ assert(ctx->ident.endianness == ELF_ENDIANNESS_LITTLE
+ || ctx->ident.endianness == ELF_ENDIANNESS_BIG);
+ b0 = ctx->buf[(*off)++]; b1 = ctx->buf[(*off)++];
+ b2 = ctx->buf[(*off)++]; b3 = ctx->buf[(*off)++];
+ if (ctx->ident.endianness == ELF_ENDIANNESS_LITTLE) {
+ return b0 | b1 << 8 | b2 << 16 | b3 << 24;
+ } else {
+ return b0 << 24 | b1 << 16 | b2 << 8 | b3;
+ }
+}
+static void write_u32(elf_ctx *ctx, u64 *off, u32 x) {
+ u32 b0, b1, b2, b3;
+ assert(off != NULL);
+ assert((i64) *off < ctx->len);
+ assert(ctx->ident.endianness == ELF_ENDIANNESS_LITTLE
+ || ctx->ident.endianness == ELF_ENDIANNESS_BIG);
+ b0 = x; b1 = x >> 8; b2 = x >> 16; b3 = x >> 24;
+ if (ctx->ident.endianness == ELF_ENDIANNESS_LITTLE) {
+ ctx->buf[(*off)++] = (u8) b0; ctx->buf[(*off)++] = (u8) b1;
+ ctx->buf[(*off)++] = (u8) b2; ctx->buf[(*off)++] = (u8) b3;
+ } else {
+ ctx->buf[(*off)++] = (u8) b3; ctx->buf[(*off)++] = (u8) b2;
+ ctx->buf[(*off)++] = (u8) b1; ctx->buf[(*off)++] = (u8) b0;
+ }
+}
+static u64 read_u64(elf_ctx *ctx, u64 *off) {
+ u64 b0, b1, b2, b3, b4, b5, b6, b7;
+ assert(off != NULL);
+ assert((i64) *off < ctx->len);
+ assert(ctx->ident.endianness == ELF_ENDIANNESS_LITTLE
+ || ctx->ident.endianness == ELF_ENDIANNESS_BIG);
+ b0 = ctx->buf[(*off)++]; b1 = ctx->buf[(*off)++];
+ b2 = ctx->buf[(*off)++]; b3 = ctx->buf[(*off)++];
+ b4 = ctx->buf[(*off)++]; b5 = ctx->buf[(*off)++];
+ b6 = ctx->buf[(*off)++]; b7 = ctx->buf[(*off)++];
+ if (ctx->ident.endianness == ELF_ENDIANNESS_LITTLE) {
+ return b0 | b1 << 8 | b2 << 16 | b3 << 24
+ | b4 << 32 | b5 << 40 | b6 << 48 | b7 << 56;
+ } else {
+ return b0 << 56 | b1 << 48 | b2 << 40 | b3 << 32
+ | b4 << 24 | b5 << 16 | b6 << 8 | b7;
+ }
+}
+static void write_u64(elf_ctx *ctx, u64 *off, u64 x) {
+ u64 b0, b1, b2, b3, b4, b5, b6, b7;
+ assert(off != NULL);
+ assert((i64) *off < ctx->len);
+ assert(ctx->ident.endianness == ELF_ENDIANNESS_LITTLE
+ || ctx->ident.endianness == ELF_ENDIANNESS_BIG);
+ b0 = x; b1 = x >> 8; b2 = x >> 16; b3 = x >> 24;
+ b4 = x >> 32; b5 = x >> 40; b6 = x >> 48; b7 = x >> 56;
+ if (ctx->ident.endianness == ELF_ENDIANNESS_LITTLE) {
+ ctx->buf[(*off)++] = (u8) b0; ctx->buf[(*off)++] = (u8) b1;
+ ctx->buf[(*off)++] = (u8) b2; ctx->buf[(*off)++] = (u8) b3;
+ ctx->buf[(*off)++] = (u8) b4; ctx->buf[(*off)++] = (u8) b5;
+ ctx->buf[(*off)++] = (u8) b6; ctx->buf[(*off)++] = (u8) b7;
+ } else {
+ ctx->buf[(*off)++] = (u8) b7; ctx->buf[(*off)++] = (u8) b6;
+ ctx->buf[(*off)++] = (u8) b5; ctx->buf[(*off)++] = (u8) b4;
+ ctx->buf[(*off)++] = (u8) b3; ctx->buf[(*off)++] = (u8) b2;
+ ctx->buf[(*off)++] = (u8) b1; ctx->buf[(*off)++] = (u8) b0;
+ }
+}
+static u64 read_file_class_word(elf_ctx *ctx, u64 *off) {
+ assert(ctx);
+ assert(ctx->ident.file_class == ELF_CLASS_32
+ || ctx->ident.file_class == ELF_CLASS_64);
+ if (ctx->ident.file_class == ELF_CLASS_32) {
+ return (u64) read_u32(ctx, off);
+ } else {
+ return (u64) read_u64(ctx, off);
+ }
+}
+static void write_file_class_word(elf_ctx *ctx, u64 *off, u64 x) {
+ assert(ctx);
+ assert(ctx->ident.file_class == ELF_CLASS_32
+ || ctx->ident.file_class == ELF_CLASS_64);
+ if (ctx->ident.file_class == ELF_CLASS_32) {
+ write_u32(ctx, off, (u32) x);
+ } else {
+ write_u64(ctx, off, x);
+ }
+}
+static i64 read_file_class_signed_word(elf_ctx *ctx, u64 *off) {
+ assert(ctx);
+ assert(ctx->ident.file_class == ELF_CLASS_32
+ || ctx->ident.file_class == ELF_CLASS_64);
+ if (ctx->ident.file_class == ELF_CLASS_32) {
+ return (i64) (i32) read_u32(ctx, off);
+ } else {
+ return (i64) read_u64(ctx, off);
+ }
+}
+static void write_file_class_signed_word(elf_ctx *ctx, u64 *off, i64 x) {
+ assert(ctx);
+ assert(ctx->ident.file_class == ELF_CLASS_32
+ || ctx->ident.file_class == ELF_CLASS_64);
+ if (ctx->ident.file_class == ELF_CLASS_32) {
+ assert(x < UINT32_MAX);
+ write_u32(ctx, off, (u32) (u64) x);
+ } else {
+ write_u64(ctx, off, (u64) x);
+ }
+}
+
+i64 elf_header_size(elf_ctx *ctx) {
+ return ctx->ident.file_class == ELF_CLASS_32
+ ? ELF32_HEADER_SIZE : ELF64_HEADER_SIZE;
+}
+i64 elf_read_header(elf_header *ret, elf_ctx *ctx) {
+ u64 off = ELF_HEADER_IDENT_SIZE;
+ i64 sz = elf_header_size(ctx);
+ if (!ret || !ctx || ctx->len < sz) return -1;
+ ret->type = read_u16(ctx, &off);
+ ret->machine = read_u16(ctx, &off);
+ ret->version = read_u32(ctx, &off);
+ ret->entry = read_file_class_word(ctx, &off);
+ ret->program_header_offset = read_file_class_word(ctx, &off);
+ ret->section_header_offset = read_file_class_word(ctx, &off);
+ ret->flags = read_u32(ctx, &off);
+ ret->elf_header_size = read_u16(ctx, &off);
+ ret->program_header_entry_size = read_u16(ctx, &off);
+ ret->program_header_entries = read_u16(ctx, &off);
+ ret->section_header_entry_size = read_u16(ctx, &off);
+ ret->section_header_entries = read_u16(ctx, &off);
+ ret->section_name_table_index = read_u16(ctx, &off);
+ return 0;
+}
+i64 elf_write_header(elf_header *h, elf_ctx *ctx) {
+ u64 off = ELF_HEADER_IDENT_SIZE;
+ i64 sz = elf_header_size(ctx);
+ if (!h || !ctx || ctx->len < sz) return -1;
+ write_u16(ctx, &off, h->type);
+ write_u16(ctx, &off, h->machine);
+ write_u32(ctx, &off, h->version);
+ printf("entry off: %lu\n", off);
+ write_file_class_word(ctx, &off, h->entry);
+ write_file_class_word(ctx, &off, h->program_header_offset);
+ write_file_class_word(ctx, &off, h->section_header_offset);
+ write_u32(ctx, &off, h->flags);
+ write_u16(ctx, &off, h->elf_header_size);
+ write_u16(ctx, &off, h->program_header_entry_size);
+ write_u16(ctx, &off, h->program_header_entries);
+ write_u16(ctx, &off, h->section_header_entry_size);
+ write_u16(ctx, &off, h->section_header_entries);
+ write_u16(ctx, &off, h->section_name_table_index);
+ return 0;
+}
+
+/* given the index of a program/section header, return its file offset */
+u64 elf_program_header_offset(elf_header *h, u64 idx) {
+ return h->program_header_offset + idx * h->program_header_entry_size;
+}
+u64 elf_section_header_offset(elf_header *h, u64 idx) {
+ return h->section_header_offset + idx * h->section_header_entry_size;
+}
+
+i64 elf_section_header_size(elf_ctx *ctx) {
+ return ctx->ident.file_class == ELF_CLASS_32
+ ? ELF32_SECTION_HEADER_SIZE : ELF64_SECTION_HEADER_SIZE;
+}
+i64 elf_read_section_header(elf_section_header *ret, elf_ctx *ctx, u64 off) {
+ i64 sz = elf_section_header_size(ctx);
+ if (!ret || !ctx || ctx->len < (i64) off + sz) return -1;
+ ret->name_index = read_u32(ctx, &off);
+ ret->type = read_u32(ctx, &off);
+ ret->flags = read_file_class_word(ctx, &off);
+ ret->addr = read_file_class_word(ctx, &off);
+ ret->offset = read_file_class_word(ctx, &off);
+ ret->size = read_file_class_word(ctx, &off);
+ ret->link = read_u32(ctx, &off);
+ ret->info = read_u32(ctx, &off);
+ ret->addr_alignment = read_file_class_word(ctx, &off);
+ ret->entry_size = read_file_class_word(ctx, &off);
+ return 0;
+}
+i64 elf_write_section_header(elf_section_header *sh, elf_ctx *ctx, u64 off) {
+ i64 sz = elf_section_header_size(ctx);
+ if (!sh || !ctx || ctx->len < (i64) off + sz) return -1;
+ printf("section off: %lu\n", off);
+ write_u32(ctx, &off, sh->name_index);
+ write_u32(ctx, &off, sh->type);
+ write_file_class_word(ctx, &off, sh->flags);
+ write_file_class_word(ctx, &off, sh->addr);
+ write_file_class_word(ctx, &off, sh->offset);
+ write_file_class_word(ctx, &off, sh->size);
+ write_u32(ctx, &off, sh->link);
+ write_u32(ctx, &off, sh->info);
+ write_file_class_word(ctx, &off, sh->addr_alignment);
+ write_file_class_word(ctx, &off, sh->entry_size);
+ return 0;
+}
+
+char *elf_read_section_name(elf_ctx *ctx, elf_header *h, elf_section_header *sh) {
+ elf_section_header name_section;
+ if (!ctx || !h || !sh) return NULL;
+ if (h->section_name_table_index >= h->section_header_entries) return NULL;
+ if (elf_read_section_header(&name_section, ctx,
+ elf_section_header_offset(h, h->section_name_table_index)) < 0)
+ return NULL;
+ return (char *) &ctx->buf[name_section.offset + sh->name_index];
+}
+
+i64 elf_symbol_size(elf_ctx *ctx) {
+ return ctx->ident.file_class == ELF_CLASS_32
+ ? ELF32_SYMBOL_SIZE : ELF64_SYMBOL_SIZE;
+}
+i64 elf_read_symbol(elf_symbol *ret, elf_ctx *ctx, u64 off) {
+ i64 sz = elf_symbol_size(ctx);
+ u8 info = 0, other = 0;
+ assert(ctx->ident.file_class == ELF_CLASS_32
+ || ctx->ident.file_class == ELF_CLASS_64);
+ if (!ret || !ctx || ctx->len < (i64) off + sz) return -1;
+ if (ctx->ident.file_class == ELF_CLASS_32) {
+ ret->name_index = read_u32(ctx, &off);
+ ret->value = read_u32(ctx, &off);
+ ret->size = read_u32(ctx, &off);
+ info = read_u8(ctx, &off);
+ ret->bind = info >> 4;
+ ret->type = info & 0xf;
+ other = read_u8(ctx, &off);
+ ret->visibility = other & 0x3;
+ ret->section_header_index = read_u16(ctx, &off);
+ } else {
+ ret->name_index = read_u32(ctx, &off);
+ info = read_u8(ctx, &off);
+ ret->bind = info >> 4;
+ ret->type = info & 0xf;
+ other = read_u8(ctx, &off);
+ ret->visibility = other & 0x3;
+ ret->section_header_index = read_u16(ctx, &off);
+ ret->value = read_u64(ctx, &off);
+ ret->size = read_u64(ctx, &off);
+ }
+ return 0;
+}
+i64 elf_write_symbol(elf_symbol *sym, elf_ctx *ctx, u64 off) {
+ i64 sz = elf_symbol_size(ctx);
+ u8 info, other;
+ assert(ctx->ident.file_class == ELF_CLASS_32
+ || ctx->ident.file_class == ELF_CLASS_64);
+ if (!sym || !ctx || ctx->len < (i64) off + sz) return -1;
+ if (ctx->ident.file_class == ELF_CLASS_32) {
+ write_u32(ctx, &off, sym->name_index);
+ write_u32(ctx, &off, (u32) sym->value);
+ write_u32(ctx, &off, (u32) sym->size);
+ info = (u8) sym->bind << 4 | sym->type;
+ write_u8(ctx, &off, info);
+ other = sym->visibility;
+ write_u8(ctx, &off, other);
+ write_u16(ctx, &off, sym->section_header_index);
+ } else {
+ write_u32(ctx, &off, sym->name_index);
+ info = (u8) sym->bind << 4 | sym->type;
+ write_u8(ctx, &off, info);
+ other = sym->visibility;
+ write_u8(ctx, &off, other);
+ write_u16(ctx, &off, sym->section_header_index);
+ write_u64(ctx, &off, sym->value);
+ write_u64(ctx, &off, sym->size);
+ }
+ return 0;
+}
+
+static void parse_relocation_info(
+ u64 *symtab_index, u64 *type, elf_ctx *ctx, u64 info
+) {
+ assert(symtab_index != NULL && type != NULL);
+ assert(ctx->ident.file_class == ELF_CLASS_32
+ || ctx->ident.file_class == ELF_CLASS_64);
+ if (ctx->ident.file_class == ELF_CLASS_32) {
+ info &= 0xffffffff;
+ *symtab_index = info >> 8;
+ *type = (u8) info;
+ } else {
+ *symtab_index = info > 32;
+ *type = info & 0xffffffff;
+ }
+}
+char *elf_read_symbol_name(
+ elf_ctx *ctx, elf_header *h, elf_section_header *sh, elf_symbol *sym
+) {
+ elf_section_header name_section;
+ if (!ctx || !sh || !sh) return NULL;
+ if (!(sh->type == ELF_SECTION_TYPE_SYMTAB
+ || sh->type == ELF_SECTION_TYPE_DYNSYM))
+ return NULL;
+ if (sh->link >= h->section_header_entries) return NULL;
+ if (elf_read_section_header(&name_section, ctx,
+ elf_section_header_offset(h, sh->link)) < 0)
+ return NULL;
+ return (char *) &ctx->buf[name_section.offset + sym->name_index];
+}
+
+i64 elf_rel_size(elf_ctx *ctx) {
+ return ctx->ident.file_class == ELF_CLASS_32
+ ? ELF32_REL_SIZE : ELF64_REL_SIZE;
+}
+i64 elf_read_rel(elf_rel *ret, elf_ctx *ctx, u64 off) {
+ i64 sz = elf_rel_size(ctx);
+ u64 info;
+ if (!ret || !ctx || ctx->len < (i64) off + sz) return -1;
+ ret->offset = read_file_class_word(ctx, &off);
+ info = read_file_class_word(ctx, &off);
+ parse_relocation_info(&ret->symtab_index, &ret->type, ctx, info);
+ return 0;
+}
+
+i64 elf_rela_size(elf_ctx *ctx) {
+ return ctx->ident.file_class == ELF_CLASS_32
+ ? ELF32_RELA_SIZE : ELF64_RELA_SIZE;
+}
+i64 elf_read_rela(elf_rela *ret, elf_ctx *ctx, u64 off) {
+ i64 sz = elf_rela_size(ctx);
+ u64 info;
+ if (!ret || !ctx || ctx->len < (i64) off + sz) return -1;
+ ret->offset = read_file_class_word(ctx, &off);
+ info = read_file_class_word(ctx, &off);
+ parse_relocation_info(&ret->symtab_index, &ret->type, ctx, info);
+ ret->addend = read_file_class_signed_word(ctx, &off);
+ return 0;
+}
+
+i64 elf_program_header_size(elf_ctx *ctx) {
+ return ctx->ident.file_class == ELF_CLASS_32
+ ? ELF32_PROGRAM_HEADER_SIZE : ELF64_PROGRAM_HEADER_SIZE;
+}
+i64 elf_read_program_header(elf_program_header *ret, elf_ctx *ctx, u64 off) {
+ i64 sz = elf_program_header_size(ctx);
+ if (!ret || !ctx || ctx->len < (i64) off + sz) return -1;
+ if (ctx->ident.file_class == ELF_CLASS_32) {
+ ret->type = read_u32(ctx, &off);
+ ret->offset = read_file_class_word(ctx, &off);
+ ret->virtual_addr = read_file_class_word(ctx, &off);
+ ret->physical_addr = read_file_class_word(ctx, &off);
+ ret->file_size = read_u32(ctx, &off);
+ ret->mem_size = read_u32(ctx, &off);
+ ret->flags = read_u32(ctx, &off);
+ ret->align = read_u32(ctx, &off);
+ } else {
+ ret->type = read_u32(ctx, &off);
+ ret->flags = read_u32(ctx, &off);
+ ret->offset = read_file_class_word(ctx, &off);
+ ret->virtual_addr = read_file_class_word(ctx, &off);
+ ret->physical_addr = read_file_class_word(ctx, &off);
+ ret->file_size = read_u64(ctx, &off);
+ ret->mem_size = read_u64(ctx, &off);
+ ret->align = read_u64(ctx, &off);
+ }
+ return 0;
+}
+i64 elf_write_program_header(elf_program_header *ph, elf_ctx *ctx, u64 off) {
+ i64 sz = elf_program_header_size(ctx);
+ if (!ph || !ctx || ctx->len < (i64) off + sz) return -1;
+ if (ctx->ident.file_class == ELF_CLASS_32) {
+ write_u32(ctx, &off, ph->type);
+ write_file_class_word(ctx, &off, ph->offset);
+ write_file_class_word(ctx, &off, ph->virtual_addr);
+ write_file_class_word(ctx, &off, ph->physical_addr);
+ write_u32(ctx, &off, (u32) ph->file_size);
+ write_u32(ctx, &off, (u32) ph->mem_size);
+ write_u32(ctx, &off, ph->flags);
+ write_u32(ctx, &off, (u32) ph->align);
+ } else {
+ write_u32(ctx, &off, ph->type);
+ write_u32(ctx, &off, ph->flags);
+ write_file_class_word(ctx, &off, ph->offset);
+ write_file_class_word(ctx, &off, ph->virtual_addr);
+ write_file_class_word(ctx, &off, ph->physical_addr);
+ write_u64(ctx, &off, ph->file_size);
+ write_u64(ctx, &off, ph->mem_size);
+ write_u64(ctx, &off, ph->align);
+ }
+ return 0;
+}
+
+i64 elf_write_bytes(elf_ctx *ctx, u64 *off, u8 *buf, i64 len) {
+ i64 i = 0;
+ if (!ctx || !buf || ctx->len < (i64) *off + len) return -1;
+ for (; i < len; ++i) {
+ printf("byte off: %ld\n", (i64) *off + i);
+ ctx->buf[(i64) *off + i] = buf[i];
+ }
+ *off += (u64) len;
+ return 0;
+}
diff --git a/elf/src/main.c b/elf/src/main.c
new file mode 100644
index 0000000..8a79586
--- /dev/null
+++ b/elf/src/main.c
@@ -0,0 +1,204 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lcq/elf.h>
+
+u8 TEST_PROG[] = {
+ 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, /* mov $0x3c,%rax */
+ 0x48, 0xc7, 0xc7, 0x2a, 0x00, 0x00, 0x00, /* mov $0x2a,%rdi */
+ 0x0f, 0x05 /* syscall */
+};
+
+int main(int argc, char **argv) {
+ elf_ctx e = {0};
+ elf_header h = {0};
+ elf_section_header sh = {0};
+ elf_program_header ph = {0};
+ i64 i = 0;
+
+ if (argc < 3) { fprintf(stderr, "usage: %s MODE ELF-PATH\n", argv[0]); return 1; }
+ if (strcmp(argv[1], "read") == 0) {
+ e = elf_load_from_path(argv[2]);
+ elf_read_header(&h, &e);
+ printf("%d %d %d %d %d\n", e.ident.file_class, e.ident.endianness, e.ident.version, e.ident.abi, e.ident.abi_version);
+ printf("type=%u, machine=%u\n", h.type, h.machine);
+ printf("version=%u, entry=0x%lx\n", h.version, h.entry);
+ printf("ph=%lu, sh=%lu\n", h.program_header_offset, h.section_header_offset);
+ printf("flags=%u, eh=%u\n", h.flags, h.elf_header_size);
+ printf("ph_ent_size=%u, ph_ents=%u\n", h.program_header_entry_size, h.program_header_entries);
+ printf("sh_ent_size=%u, sh_ents=%u\n", h.section_header_entry_size, h.section_header_entries);
+ printf("nametable=%u\n", h.section_name_table_index);
+
+ for (i = 0; i < h.section_header_entries; ++i) {
+ char *name = NULL;
+ elf_read_section_header(&sh, &e, elf_section_header_offset(&h, (u64) i));
+ name = elf_read_section_name(&e, &h, &sh);
+ printf("section %ld (%s) type: %u\n", i, name, sh.type);
+ }
+ for (i = 0; i < h.section_header_entries; ++i) {
+ elf_read_section_header(&sh, &e, elf_section_header_offset(&h, (u64) i));
+ if (sh.type == ELF_SECTION_TYPE_SYMTAB) {
+ u64 symoff = 0;
+ for (symoff = 0; symoff < sh.size; symoff += sh.entry_size) {
+ elf_symbol s = {0};
+ elf_read_symbol(&s, &e, sh.offset + symoff);
+ printf("symbol offset %ld (%s) type: %u\n",
+ symoff,
+ elf_read_symbol_name(&e, &h, &sh, &s),
+ s.type
+ );
+ }
+ }
+ }
+ } else {
+ elf_symbol s = {0};
+ i64 len = 1024 * 16;
+ u8 *buf = calloc((size_t) len, sizeof(u8));
+ FILE *f = NULL;
+ u64 sh_off = 0,
+ shstrtab_off = 0,
+ shstrtab_name_off = 0,
+ shstrtab_len = 0,
+ strtab_off = 0,
+ strtab_name_off = 0,
+ strtab_len = 0,
+ symtab_off = 0,
+ symtab_name_off = 0,
+ symtab_len = 0,
+ text_off = 0,
+ text_name_off = 0,
+ text_len = 0,
+ program_header_off = 0,
+ off = 0,
+ symbols = 0,
+ sections = 0;
+ e = elf_ctx_new(buf, len, ELF_CLASS_64, ELF_ENDIANNESS_LITTLE);
+ off = ELF64_HEADER_SIZE;
+
+ /* make space for program header */
+ program_header_off = off;
+ off += ELF64_PROGRAM_HEADER_SIZE;
+
+ /* write shstrtab */
+ shstrtab_off = off;
+ e.buf[off++] = 0;
+ shstrtab_name_off = off - shstrtab_off; elf_write_bytes(&e, &off, ELF_STRTAB_BYTES_OFF(".shstrtab"));
+ strtab_name_off = off - shstrtab_off; elf_write_bytes(&e, &off, ELF_STRTAB_BYTES_OFF(".strtab"));
+ symtab_name_off = off - shstrtab_off; elf_write_bytes(&e, &off, ELF_STRTAB_BYTES_OFF(".symtab"));
+ text_name_off = off - shstrtab_off; elf_write_bytes(&e, &off, ELF_STRTAB_BYTES_OFF(".text"));
+ e.buf[off++] = 0;
+ shstrtab_len = off - shstrtab_off;
+
+ /* write strtab */
+ strtab_off = off;
+ e.buf[off++] = 0;
+ elf_write_bytes(&e, &off, ELF_STRTAB_BYTES_OFF("_start"));
+ e.buf[off++] = 0;
+ strtab_len = off - strtab_off;
+
+ /* write symtab */
+ symtab_off = off;
+ printf("symtab_off: %lu\n", symtab_off);
+ /* null symbol */
+ symbols += 1;
+ s.size = 0;
+ s.value = 0;
+ s.name_index = 0;
+ s.bind = ELF_SYMBOL_BINDING_LOCAL;
+ s.type = ELF_SYMBOL_TYPE_NOTYPE;
+ s.visibility = ELF_SYMBOL_VISIBILITY_DEFAULT;
+ s.section_header_index = 0;
+ elf_write_symbol(&s, &e, off);
+ off += ELF64_SYMBOL_SIZE;
+
+ /* _start */
+ symbols += 1;
+ s.size = 0;
+ s.value = 0x401000;
+ s.name_index = 1;
+ s.bind = ELF_SYMBOL_BINDING_GLOBAL;
+ s.type = ELF_SYMBOL_TYPE_NOTYPE;
+ s.visibility = ELF_SYMBOL_VISIBILITY_DEFAULT;
+ s.section_header_index = 4;
+ elf_write_symbol(&s, &e, off);
+ off += ELF64_SYMBOL_SIZE;
+ symtab_len = off - symtab_off;
+
+ /* write text */
+ /* text_off = off; */
+ text_off = 0x1000;
+ text_len = text_off;
+ elf_write_bytes(&e, &text_len, TEST_PROG, sizeof(TEST_PROG));
+ /* text_len = off - text_off; */
+ text_len -= text_off;
+
+ /* write section headers */
+ sh_off = off;
+
+ /* null section */
+ sections += 1;
+ sh.name_index = 0; sh.type = ELF_SECTION_TYPE_NULL;
+ sh.flags = 0; sh.addr = 0; sh.offset = 0; sh.size = 0;
+ sh.link = 0; sh.info = 0; sh.addr_alignment = 0; sh.entry_size = 0;
+ elf_write_section_header(&sh, &e, off); off += ELF64_SECTION_HEADER_SIZE;
+
+ /* .shstrtab */
+ sections += 1;
+ sh.name_index = (u32) shstrtab_name_off; sh.type = ELF_SECTION_TYPE_STRTAB;
+ sh.flags = 0; sh.addr = 0; sh.offset = shstrtab_off; sh.size = shstrtab_len;
+ sh.link = 0; sh.info = 0; sh.addr_alignment = 0; sh.entry_size = 0;
+ elf_write_section_header(&sh, &e, off); off += ELF64_SECTION_HEADER_SIZE;
+
+ /* .strtab */
+ sections += 1;
+ sh.name_index = (u32) strtab_name_off; sh.type = ELF_SECTION_TYPE_STRTAB;
+ sh.flags = 0; sh.addr = 0; sh.offset = strtab_off; sh.size = strtab_len;
+ sh.link = 0; sh.info = 0; sh.addr_alignment = 0; sh.entry_size = 0;
+ elf_write_section_header(&sh, &e, off); off += ELF64_SECTION_HEADER_SIZE;
+
+ /* .symtab */
+ sections += 1;
+ sh.name_index = (u32) symtab_name_off; sh.type = ELF_SECTION_TYPE_SYMTAB;
+ sh.flags = 0; sh.addr = 0; sh.offset = symtab_off; sh.size = symtab_len;
+ sh.link = 2; sh.info = 1; sh.addr_alignment = 0; sh.entry_size = ELF64_SYMBOL_SIZE;
+ elf_write_section_header(&sh, &e, off); off += ELF64_SECTION_HEADER_SIZE;
+
+ /* .text */
+ sections += 1;
+ sh.name_index = (u32) text_name_off; sh.type = ELF_SECTION_TYPE_PROGBITS;
+ sh.flags = ELF_SECTION_FLAG_ALLOC | ELF_SECTION_FLAG_EXECINSTR;
+ sh.addr = 0x401000; sh.offset = text_off; sh.size = text_len;
+ sh.link = 0; sh.info = 0; sh.addr_alignment = 0; sh.entry_size = 0;
+ elf_write_section_header(&sh, &e, off); off += ELF64_SECTION_HEADER_SIZE;
+
+ /* write program header */
+ ph.type = ELF_PROGRAM_HEADER_TYPE_LOAD;
+ ph.offset = text_off;
+ ph.virtual_addr = 0x401000;
+ ph.physical_addr = 0;
+ ph.file_size = (u32) text_len;
+ ph.mem_size = (u32) text_len;
+ ph.flags = ELF_PROGRAM_HEADER_FLAG_R | ELF_PROGRAM_HEADER_FLAG_X;
+ ph.align = 0;
+ elf_write_program_header(&ph, &e, program_header_off);
+
+ /* write header at the start */
+ h.type = ELF_TYPE_EXEC;
+ h.machine = ELF_MACHINE_AMD64;
+ h.version = 1;
+ h.entry = 0x401000;
+ h.program_header_offset = program_header_off;
+ h.program_header_entry_size = ELF64_PROGRAM_HEADER_SIZE;
+ h.program_header_entries = 1;
+ h.section_header_offset = sh_off;
+ h.section_header_entry_size = ELF64_SECTION_HEADER_SIZE;
+ h.section_header_entries = (u16) sections;
+ h.section_name_table_index = 1;
+ elf_write_header(&h, &e);
+ f = fopen(argv[2], "w+");
+ fwrite(buf, sizeof(u8), (size_t) len, f);
+ fclose(f);
+ }
+ return 0;
+}