From 6357fdedd45737c28ddafdcb85590ced267af226 Mon Sep 17 00:00:00 2001 From: Yu-En Hsiao Date: Tue, 13 May 2025 21:14:46 +0800 Subject: [PATCH 1/3] Support dynamic linking --- Makefile | 17 +- lib/c.h | 46 ++++ mk/arm.mk | 6 + mk/common.mk | 3 + mk/riscv.mk | 8 + src/arm-codegen.c | 119 ++++++++-- src/arm.c | 10 + src/defs.h | 38 ++++ src/elf.c | 512 +++++++++++++++++++++++++++++++++++++------- src/globals.c | 63 ++++-- src/main.c | 14 +- src/parser.c | 14 +- src/reg-alloc.c | 10 + src/riscv-codegen.c | 3 - src/ssa.c | 43 +++- 15 files changed, 784 insertions(+), 122 deletions(-) create mode 100644 lib/c.h diff --git a/Makefile b/Makefile index 98f28818..369175ab 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,15 @@ STAGE0 := shecc STAGE1 := shecc-stage1.elf STAGE2 := shecc-stage2.elf +BUILTIN_LIBC ?= c.c +STAGE0_FLAGS ?= --dump-ir +STAGE1_FLAGS ?= +ifeq ($(DYNLINK),1) +BUILTIN_LIBC := c.h +STAGE0_FLAGS += --dynlink +STAGE1_FLAGS += --dynlink +endif + OUT ?= out ARCHS = arm riscv ARCH ?= $(firstword $(ARCHS)) @@ -122,9 +131,9 @@ $(OUT)/norm-lf: tools/norm-lf.c $(VECHO) " CC+LD\t$@\n" $(Q)$(CC) $(CFLAGS) -o $@ $^ -$(OUT)/libc.inc: $(OUT)/inliner $(OUT)/norm-lf $(LIBDIR)/c.c +$(OUT)/libc.inc: $(OUT)/inliner $(OUT)/norm-lf $(LIBDIR)/$(BUILTIN_LIBC) $(VECHO) " GEN\t$@\n" - $(Q)$(OUT)/norm-lf $(LIBDIR)/c.c $(OUT)/c.normalized.c + $(Q)$(OUT)/norm-lf $(LIBDIR)/$(BUILTIN_LIBC) $(OUT)/c.normalized.c $(Q)$(OUT)/inliner $(OUT)/c.normalized.c $@ $(Q)$(RM) $(OUT)/c.normalized.c @@ -143,12 +152,12 @@ $(OUT)/$(STAGE0)-sanitizer: $(OUT)/libc.inc $(OBJS) $(OUT)/$(STAGE1): $(OUT)/$(STAGE0) $(Q)$(STAGE1_CHECK_CMD) $(VECHO) " SHECC\t$@\n" - $(Q)$(OUT)/$(STAGE0) --dump-ir -o $@ $(SRCDIR)/main.c > $(OUT)/shecc-stage1.log + $(Q)$(OUT)/$(STAGE0) $(STAGE0_FLAGS) -o $@ $(SRCDIR)/main.c > $(OUT)/shecc-stage1.log $(Q)chmod a+x $@ $(OUT)/$(STAGE2): $(OUT)/$(STAGE1) $(VECHO) " SHECC\t$@\n" - $(Q)$(TARGET_EXEC) $(OUT)/$(STAGE1) -o $@ $(SRCDIR)/main.c + $(Q)$(TARGET_EXEC) $(OUT)/$(STAGE1) $(STAGE1_FLAGS) -o $@ $(SRCDIR)/main.c bootstrap: $(OUT)/$(STAGE2) $(Q)chmod 775 $(OUT)/$(STAGE2) diff --git a/lib/c.h b/lib/c.h new file mode 100644 index 00000000..0a99f2e5 --- /dev/null +++ b/lib/c.h @@ -0,0 +1,46 @@ +/* + * shecc - Self-Hosting and Educational C Compiler. + * + * shecc is freely redistributable under the BSD 2 clause license. See the + * file "LICENSE" for information on usage and redistribution of this file. + */ + +#pragma once +/* Declaractions of C Standard library functions */ + +#define NULL 0 + +#define bool _Bool +#define true 1 +#define false 0 + +/* File I/O */ +typedef int FILE; +FILE *fopen(char *filename, char *mode); +int fclose(FILE *stream); +int fgetc(FILE *stream); +char *fgets(char *str, int n, FILE *stream); +int fputc(int c, FILE *stream); + +/* string-related functions */ +int strlen(char *str); +int strcmp(char *s1, char *s2); +int strncmp(char *s1, char *s2, int len); +char *strcpy(char *dest, char *src); +char *strncpy(char *dest, char *src, int len); +char *memcpy(char *dest, char *src, int count); +void *memset(void *s, int c, int n); + +/* formatted output string */ +int printf(char *str, ...); +int sprintf(char *buffer, char *str, ...); +int snprintf(char *buffer, int n, char *str, ...); + +/* Terminating program */ +void exit(int exit_code); +void abort(void); + +/* Dynamic memory allocation/deallocation functions */ +void *malloc(int size); +void *calloc(int n, int size); +void free(void *ptr); diff --git a/mk/arm.mk b/mk/arm.mk index 57bbebd4..e6e1590f 100644 --- a/mk/arm.mk +++ b/mk/arm.mk @@ -6,4 +6,10 @@ ARCH_DEFS = \ \#define ARCH_PREDEFINED \"__arm__\" /* defined by GNU C and RealView */\n$\ \#define ELF_MACHINE 0x28 /* up to ARMv7/Aarch32 */\n$\ \#define ELF_FLAGS 0x5000200\n$\ + \#define DYN_LINKER \"/lib/ld-linux.so.3\"\n$\ + \#define LIBC_SO \"libc.so.6\"\n$\ + \#define PLT_FIXUP_SIZE 20\n$\ + \#define PLT_ENT_SIZE 12\n$\ + \#define R_ARCH_JUMP_SLOT 0x16\n$\ " +RUNNER_LD_PREFIX=-L /usr/arm-linux-gnueabi/ diff --git a/mk/common.mk b/mk/common.mk index 95380cba..2410fab6 100644 --- a/mk/common.mk +++ b/mk/common.mk @@ -36,6 +36,9 @@ ifneq ($(HOST_ARCH),$(ARCH_NAME)) # Generate the path to the architecture-specific qemu TARGET_EXEC = $(shell which $(ARCH_RUNNER)) + ifeq ($(DYNLINK),1) + TARGET_EXEC += $(RUNNER_LD_PREFIX) + endif endif export TARGET_EXEC diff --git a/mk/riscv.mk b/mk/riscv.mk index 89e33341..fe3ce7e5 100644 --- a/mk/riscv.mk +++ b/mk/riscv.mk @@ -7,4 +7,12 @@ ARCH_DEFS = \ \#define ARCH_PREDEFINED \"__riscv\" /* Older versions of the GCC toolchain defined __riscv__ */\n$\ \#define ELF_MACHINE 0xf3\n$\ \#define ELF_FLAGS 0\n$\ + \#define DYN_LINKER \"/lib/ld-linux.so.3\"\n$\ + \#define LIBC_SO \"libc.so.6\"\n$\ + \#define PLT_FIXUP_SIZE 20\n$\ + \#define PLT_ENT_SIZE 12\n$\ + \#define R_ARCH_JUMP_SLOT 0x5\n$\ " + +# TODO: Set this variable for RISC-V architecture +RUNNER_LD_PREFIX= diff --git a/src/arm-codegen.c b/src/arm-codegen.c index 3d7dc184..c4313ffe 100644 --- a/src/arm-codegen.c +++ b/src/arm-codegen.c @@ -135,10 +135,16 @@ void update_elf_offset(ph2_ir_t *ph2_ir) void cfg_flatten(void) { - func_t *func = find_func("__syscall"); - func->bbs->elf_offset = 48; /* offset of start + branch + exit in codegen */ + func_t *func; + + if (dynlink) + elf_offset = 112; /* offset of start + branch + exit in codegen */ + else { + func = find_func("__syscall"); + func->bbs->elf_offset = 48; /* offset of start + exit in codegen */ + elf_offset = 84; /* offset of start + branch + exit + syscall in codegen */ + } - elf_offset = 84; /* offset of start + branch + exit + syscall in codegen */ GLOBAL_FUNC->bbs->elf_offset = elf_offset; for (ph2_ir_t *ph2_ir = GLOBAL_FUNC->bbs->ph2_ir_list.head; ph2_ir; @@ -147,9 +153,15 @@ void cfg_flatten(void) } /* prepare 'argc' and 'argv', then proceed to 'main' function */ - elf_offset += 32; /* 6 insns for main call + 2 for exit */ + if (dynlink) + elf_offset += 20; + else + elf_offset += 32; /* 6 insns for main call + 2 for exit */ for (func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; + /* reserve stack */ ph2_ir_t *flatten_ir = add_ph2_ir(OP_define); flatten_ir->src0 = func->stack_size; @@ -282,7 +294,12 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) return; case OP_call: func = find_func(ph2_ir->func_name); - emit(__bl(__AL, func->bbs->elf_offset - elf_code->size)); + if (func->bbs) + ofs = func->bbs->elf_offset - elf_code->size; + else + ofs = (elf_plt_start + func->plt_offset) - + (elf_code_start + elf_code->size); + emit(__bl(__AL, ofs)); return; case OP_load_data_address: emit(__movw(__AL, rd, ph2_ir->src0 + elf_data_start)); @@ -290,7 +307,10 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) return; case OP_address_of_func: func = find_func(ph2_ir->func_name); - ofs = elf_code_start + func->bbs->elf_offset; + if (func->bbs) + ofs = elf_code_start + func->bbs->elf_offset; + else + ofs = elf_plt_start + func->plt_offset; emit(__movw(__AL, __r8, ofs)); emit(__movt(__AL, __r8, ofs)); emit(__sw(__AL, __r8, rn, 0)); @@ -447,11 +467,40 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) } } +void plt_generate(void); void code_generate(void) { - elf_data_start = elf_code_start + elf_offset; + if (dynlink) { + plt_generate(); + /* Call __libc_start_main() */ + emit(__mov_i(__AL, __r11, 0)); + emit(__mov_i(__AL, __lr, 0)); + emit(__pop_word(__AL, __r1)); + emit(__mov_r(__AL, __r2, __sp)); + emit(__push_reg(__AL, __r2)); + emit(__push_reg(__AL, __r0)); + emit(__mov_i(__AL, __r12, 0)); + emit(__push_reg(__AL, __r12)); + emit(__movw(__AL, __r0, elf_code_start + 56)); + emit(__movt(__AL, __r0, elf_code_start + 56)); + emit(__mov_i(__AL, __r3, 0)); + emit(__bl(__AL, (elf_plt_start + PLT_FIXUP_SIZE) - + (elf_code_start + elf_code->size))); + /* Goto the 'exit' code snippet if __libc_start_main returns */ + emit(__mov_i(__AL, __r0, 127)); + emit(__bl(__AL, 28)); - /* start */ + /* If the compiled program is dynamic linking, the starting + * point of 'start' is located here. + * + * Preserve the 'argc' and 'argv' for the 'main' function. + * */ + emit(__mov_r(__AL, __r9, __r0)); + emit(__mov_r(__AL, __r10, __r1)); + } + /* If the compiled program is static linking, the starting point + * of 'start' is here. + * */ emit(__movw(__AL, __r8, GLOBAL_FUNC->stack_size)); emit(__movt(__AL, __r8, GLOBAL_FUNC->stack_size)); emit(__sub_r(__AL, __sp, __sp, __r8)); @@ -468,16 +517,18 @@ void code_generate(void) emit(__mov_i(__AL, __r7, 1)); emit(__svc()); - /* syscall */ - emit(__mov_r(__AL, __r7, __r0)); - emit(__mov_r(__AL, __r0, __r1)); - emit(__mov_r(__AL, __r1, __r2)); - emit(__mov_r(__AL, __r2, __r3)); - emit(__mov_r(__AL, __r3, __r4)); - emit(__mov_r(__AL, __r4, __r5)); - emit(__mov_r(__AL, __r5, __r6)); - emit(__svc()); - emit(__mov_r(__AL, __pc, __lr)); + if (!dynlink) { + /* syscall */ + emit(__mov_r(__AL, __r7, __r0)); + emit(__mov_r(__AL, __r0, __r1)); + emit(__mov_r(__AL, __r1, __r2)); + emit(__mov_r(__AL, __r2, __r3)); + emit(__mov_r(__AL, __r3, __r4)); + emit(__mov_r(__AL, __r4, __r5)); + emit(__mov_r(__AL, __r5, __r6)); + emit(__svc()); + emit(__mov_r(__AL, __pc, __lr)); + } ph2_ir_t *ph2_ir; for (ph2_ir = GLOBAL_FUNC->bbs->ph2_ir_list.head; ph2_ir; @@ -485,11 +536,16 @@ void code_generate(void) emit_ph2_ir(ph2_ir); /* prepare 'argc' and 'argv', then proceed to 'main' function */ - emit(__movw(__AL, __r8, GLOBAL_FUNC->stack_size)); - emit(__movt(__AL, __r8, GLOBAL_FUNC->stack_size)); - emit(__add_r(__AL, __r8, __r12, __r8)); - emit(__lw(__AL, __r0, __r8, 0)); - emit(__add_i(__AL, __r1, __r8, 4)); + if (dynlink) { + emit(__mov_r(__AL, __r0, __r9)); + emit(__mov_r(__AL, __r1, __r10)); + } else { + emit(__movw(__AL, __r8, GLOBAL_FUNC->stack_size)); + emit(__movt(__AL, __r8, GLOBAL_FUNC->stack_size)); + emit(__add_r(__AL, __r8, __r12, __r8)); + emit(__lw(__AL, __r0, __r8, 0)); + emit(__add_i(__AL, __r1, __r8, 4)); + } emit(__bl(__AL, MAIN_BB->elf_offset - elf_code->size)); /* exit with main's return value - r0 already has the return value */ @@ -501,3 +557,20 @@ void code_generate(void) emit_ph2_ir(ph2_ir); } } + +void plt_generate(void) +{ + int addr_of_got = elf_got_start + PTR_SIZE * 2; + int end = plt_sz - PLT_FIXUP_SIZE; + elf_write_int(elf_plt, __push_reg(__AL, __lr)); + elf_write_int(elf_plt, __movw(__AL, __r10, addr_of_got)); + elf_write_int(elf_plt, __movt(__AL, __r10, addr_of_got)); + elf_write_int(elf_plt, __mov_r(__AL, __lr, __r10)); + elf_write_int(elf_plt, __lw(__AL, __pc, __lr, 0)); + for (int i = 0; i * PLT_ENT_SIZE < end; i++) { + addr_of_got = elf_got_start + PTR_SIZE * (i + 3); + elf_write_int(elf_plt, __movw(__AL, __r12, addr_of_got)); + elf_write_int(elf_plt, __movt(__AL, __r12, addr_of_got)); + elf_write_int(elf_plt, __lw(__AL, __pc, __r12, 0)); + } +} diff --git a/src/arm.c b/src/arm.c index 3fae60b7..a91a3211 100644 --- a/src/arm.c +++ b/src/arm.c @@ -308,6 +308,16 @@ int __ldm(arm_cond_t cond, int w, arm_reg rn, int reg_list) return arm_encode(cond, arm_ldm + (0x2 << 6) + (w << 1), rn, 0, reg_list); } +int __push_reg(arm_cond_t cond, arm_reg rt) +{ + return arm_encode(cond, (0x5 << 4) | 0x2, 0xd, rt, 0x4); +} + +int __pop_word(arm_cond_t cond, arm_reg rt) +{ + return arm_encode(cond, (0x4 << 4) | 0x9, 0xd, rt, 0x4); +} + int __b(arm_cond_t cond, int ofs) { int o = (ofs - 8) >> 2; diff --git a/src/defs.h b/src/defs.h index 51c3ae69..20e31310 100644 --- a/src/defs.h +++ b/src/defs.h @@ -31,8 +31,18 @@ #define MAX_SYMTAB 65536 #define MAX_STRTAB 65536 #define MAX_HEADER 1024 +#define MAX_PROGRAM_HEADER 1024 #define MAX_SECTION 1024 #define MAX_ALIASES 128 +#define MAX_SECTION_HEADER 1024 +#define MAX_SHSTR 1024 +#define MAX_INTERP 1024 +#define MAX_DYNAMIC 1024 +#define MAX_DYNSYM 1024 +#define MAX_DYNSTR 1024 +#define MAX_RELPLT 1024 +#define MAX_PLT 1024 +#define MAX_GOTPLT 1024 #define MAX_CONSTANTS 1024 #define MAX_CASES 128 #define MAX_NESTING 128 @@ -570,6 +580,11 @@ struct func { int bb_cnt; int visited; + /* Information used for dynamic linking */ + bool is_used; + int plt_offset; + int got_offset; + struct func *next; }; @@ -632,3 +647,26 @@ typedef struct { int sh_addralign; int sh_entsize; } elf32_shdr_t; + +/* Structures for dynamic linked program */ +/* For .dynsym section. */ +typedef struct { + int st_name; + int st_value; + int st_size; + char st_info; + char st_other; + char st_shndx[2]; +} elf32_sym_t; + +/* For .rel.plt section */ +typedef struct { + int r_offset; + int r_info; +} elf32_rel_t; + +/* For .dynamic section */ +typedef struct { + int d_tag; + int d_un; +} elf32_dyn_t; diff --git a/src/elf.c b/src/elf.c index f58f65de..4022183a 100644 --- a/src/elf.c +++ b/src/elf.c @@ -55,6 +55,11 @@ void elf_write_blk(strbuf_t *elf_array, void *blk, int sz) strbuf_putc(elf_array, ptr[i]); } +int ELF32_ST_INFO(int b, int t) +{ + return (b << 4) + (t & 0xf); +} + void elf_generate_header(void) { /* Check for null pointers to prevent crashes */ @@ -64,6 +69,17 @@ void elf_generate_header(void) } elf32_hdr_t hdr; + int phnum = 1, shnum = 6, shstrndx = 5; + int shoff = elf_header_len + elf_code->size + elf_data->size + + elf_symtab->size + elf_strtab->size + elf_shstr->size; + if (dynlink) { + phnum += 3; + shnum += 7; + shstrndx += 7; + shoff += elf_interp->size + elf_relplt->size + elf_plt->size + + elf_got->size + elf_dynstr->size + elf_dynsym->size + + elf_dynamic->size; + } /* * The following table explains the meaning of each field in the * ELF32 file header. @@ -133,25 +149,27 @@ void elf_generate_header(void) hdr.e_machine[1] = 0; hdr.e_version = 1; /* ELF version */ hdr.e_entry = ELF_START + elf_header_len; /* entry point */ - hdr.e_phoff = 0x34; /* program header offset */ - hdr.e_shoff = elf_header_len + elf_code->size + elf_data->size + 39 + - elf_symtab->size + - elf_strtab->size; /* section header offset */ - hdr.e_flags = ELF_FLAGS; /* flags */ - hdr.e_ehsize[0] = (char) 0x34; /* header size */ + hdr.e_phoff = sizeof(elf32_hdr_t); /* program header offset */ + hdr.e_shoff = shoff; /* section header offset */ + hdr.e_flags = ELF_FLAGS; /* flags */ + hdr.e_ehsize[0] = sizeof(elf32_hdr_t); /* header size */ hdr.e_ehsize[1] = 0; - hdr.e_phentsize[0] = (char) 0x20; /* program header size */ + hdr.e_phentsize[0] = sizeof(elf32_phdr_t); /* program header size */ hdr.e_phentsize[1] = 0; - hdr.e_phnum[0] = 1; /* number of program headers */ + hdr.e_phnum[0] = phnum; /* number of program headers */ hdr.e_phnum[1] = 0; - hdr.e_shentsize[0] = (char) 0x28; /* section header size */ + hdr.e_shentsize[0] = sizeof(elf32_shdr_t); /* section header size */ hdr.e_shentsize[1] = 0; - hdr.e_shnum[0] = 6; /* number of section headers */ + hdr.e_shnum[0] = shnum; /* number of section headers */ hdr.e_shnum[1] = 0; - hdr.e_shstrndx[0] = 5; /* section index with names */ + hdr.e_shstrndx[0] = shstrndx; /* section index with names */ hdr.e_shstrndx[1] = 0; elf_write_blk(elf_header, &hdr, sizeof(elf32_hdr_t)); +} +void elf_generate_program_headers(void) +{ + elf32_phdr_t phdr; /* * Explain the meaning of each field in the ELF32 program header. * @@ -175,50 +193,68 @@ void elf_generate_header(void) * 54 | | | */ /* program header - code and data combined */ - elf32_phdr_t phdr; phdr.p_type = 1; /* PT_LOAD */ phdr.p_offset = elf_header_len; /* offset of segment */ - phdr.p_vaddr = ELF_START + elf_header_len; /* virtual address */ - phdr.p_paddr = ELF_START + elf_header_len; /* physical address */ + phdr.p_vaddr = elf_code_start; /* virtual address */ + phdr.p_paddr = elf_code_start; /* physical address */ phdr.p_filesz = elf_code->size + elf_data->size; /* size in file */ phdr.p_memsz = elf_code->size + elf_data->size; /* size in memory */ phdr.p_flags = 7; /* flags */ phdr.p_align = 4; /* alignment */ - elf_write_blk(elf_header, &phdr, sizeof(elf32_phdr_t)); + elf_write_blk(elf_program_header, &phdr, sizeof(elf32_phdr_t)); + if (dynlink) { + /* program header - .rel.plt .plt .got .dynstr .dynsym and .dynamic + * sections combined */ + phdr.p_type = 1; /* PT_LOAD */ + phdr.p_offset = elf_header_len + elf_code->size + elf_data->size + + elf_interp->size; /* offset of segment */ + phdr.p_vaddr = elf_relplt_start; /* virtual address */ + phdr.p_paddr = elf_relplt_start; /* physical address */ + phdr.p_filesz = elf_relplt->size + elf_plt->size + elf_got->size + + elf_dynstr->size + elf_dynsym->size + + elf_dynamic->size; /* size in file */ + phdr.p_memsz = elf_relplt->size + elf_plt->size + elf_got->size + + elf_dynstr->size + elf_dynsym->size + + elf_dynamic->size; /* size in memory */ + phdr.p_flags = 7; /* flags */ + phdr.p_align = 4; /* alignment */ + elf_write_blk(elf_program_header, &phdr, sizeof(elf32_phdr_t)); + + /* program header - program interpreter (.interp section) */ + phdr.p_type = 3; /* PT_INTERP */ + phdr.p_offset = elf_header_len + elf_code->size + + elf_data->size; /* offset of segment */ + phdr.p_vaddr = elf_data_start + elf_data->size; /* virtual address */ + phdr.p_paddr = elf_data_start + elf_data->size; /* physical address */ + phdr.p_filesz = strlen(DYN_LINKER) + 1; /* size in file */ + phdr.p_memsz = strlen(DYN_LINKER) + 1; /* size in memory */ + phdr.p_flags = 4; /* flags */ + phdr.p_align = 1; /* alignment */ + elf_write_blk(elf_program_header, &phdr, sizeof(elf32_phdr_t)); + + /* program header - .dynamic section */ + phdr.p_type = 2; /* PT_DYNAMIC */ + phdr.p_offset = elf_header_len + elf_code->size + elf_data->size + + elf_interp->size + elf_relplt->size + elf_plt->size + + elf_got->size + elf_dynstr->size + + elf_dynsym->size; /* offset of segment */ + phdr.p_vaddr = elf_got_start + elf_got->size + elf_dynstr->size + + elf_dynsym->size; /* virtual address */ + phdr.p_paddr = elf_got_start + elf_got->size + elf_dynstr->size + + elf_dynsym->size; /* physical address */ + phdr.p_filesz = elf_dynamic->size; /* size in file */ + phdr.p_memsz = elf_dynamic->size; /* size in memory */ + phdr.p_flags = 6; /* flags */ + phdr.p_align = 4; /* alignment */ + elf_write_blk(elf_program_header, &phdr, sizeof(elf32_phdr_t)); + } } -void elf_generate_sections(void) +void elf_generate_section_headers(void) { - /* Check for null pointers to prevent crashes */ - if (!elf_symtab || !elf_strtab || !elf_section) { - error("ELF section buffers not initialized"); - return; - } - - /* symtab section */ - for (int b = 0; b < elf_symtab->size; b++) - elf_write_byte(elf_section, elf_symtab->elements[b]); - - /* strtab section */ - for (int b = 0; b < elf_strtab->size; b++) - elf_write_byte(elf_section, elf_strtab->elements[b]); - - /* shstr section; len = 39 */ - elf_write_byte(elf_section, 0); - elf_write_str(elf_section, ".shstrtab"); - elf_write_byte(elf_section, 0); - elf_write_str(elf_section, ".text"); - elf_write_byte(elf_section, 0); - elf_write_str(elf_section, ".data"); - elf_write_byte(elf_section, 0); - elf_write_str(elf_section, ".symtab"); - elf_write_byte(elf_section, 0); - elf_write_str(elf_section, ".strtab"); - elf_write_byte(elf_section, 0); - /* section header table */ elf32_shdr_t shdr; - int ofs = elf_header_len; + int ofs = elf_header_len, sh_name = 0; /* * The following table uses the text section header as an example @@ -248,7 +284,7 @@ void elf_generate_sections(void) * | | | */ /* NULL section */ - shdr.sh_name = 0; + shdr.sh_name = sh_name; shdr.sh_type = 0; shdr.sh_flags = 0; shdr.sh_addr = 0; @@ -258,24 +294,26 @@ void elf_generate_sections(void) shdr.sh_info = 0; shdr.sh_addralign = 0; shdr.sh_entsize = 0; - elf_write_blk(elf_section, &shdr, sizeof(elf32_shdr_t)); + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); + sh_name += 1; /* .text */ - shdr.sh_name = 0xb; + shdr.sh_name = sh_name; shdr.sh_type = 1; shdr.sh_flags = 7; - shdr.sh_addr = ELF_START + elf_header_len; + shdr.sh_addr = elf_code_start; shdr.sh_offset = ofs; shdr.sh_size = elf_code->size; shdr.sh_link = 0; shdr.sh_info = 0; shdr.sh_addralign = 4; shdr.sh_entsize = 0; - elf_write_blk(elf_section, &shdr, sizeof(elf32_shdr_t)); + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); ofs += elf_code->size; + sh_name += strlen(".text") + 1; /* .data */ - shdr.sh_name = 0x11; + shdr.sh_name = sh_name; shdr.sh_type = 1; shdr.sh_flags = 3; shdr.sh_addr = elf_code_start + elf_code->size; @@ -285,25 +323,135 @@ void elf_generate_sections(void) shdr.sh_info = 0; shdr.sh_addralign = 4; shdr.sh_entsize = 0; - elf_write_blk(elf_section, &shdr, sizeof(elf32_shdr_t)); + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); ofs += elf_data->size; + sh_name += strlen(".data") + 1; + + if (dynlink) { + /* .interp */ + shdr.sh_name = sh_name; + shdr.sh_type = 1; + shdr.sh_flags = 0x2; + shdr.sh_addr = elf_data_start + elf_data->size; + shdr.sh_offset = ofs; + shdr.sh_size = strlen(DYN_LINKER) + 1; + shdr.sh_link = 0; + shdr.sh_info = 0; + shdr.sh_addralign = 1; + shdr.sh_entsize = 0; + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); + ofs += elf_interp->size; + sh_name += strlen(".interp") + 1; + + /* .rel.plt */ + shdr.sh_name = sh_name; + shdr.sh_type = 9; /* SHT_REL */ + shdr.sh_flags = 0x42; /* 0x40 | SHF_ALLOC */ + shdr.sh_addr = elf_relplt_start; + shdr.sh_offset = ofs; + shdr.sh_size = elf_relplt->size; + shdr.sh_link = 8; /* The section header index of .dynsym. */ + shdr.sh_info = 6; /* The section header index of .got. */ + shdr.sh_addralign = 4; + shdr.sh_entsize = sizeof(elf32_rel_t); + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); + ofs += elf_relplt->size; + sh_name += strlen(".rel.plt") + 1; + + /* .plt */ + shdr.sh_name = sh_name; + shdr.sh_type = 1; + shdr.sh_flags = 0x6; + shdr.sh_addr = elf_plt_start; + shdr.sh_offset = ofs; + shdr.sh_size = elf_plt->size; + shdr.sh_link = 0; + shdr.sh_info = 0; + shdr.sh_addralign = 4; + shdr.sh_entsize = PTR_SIZE; + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); + ofs += elf_plt->size; + sh_name += strlen(".plt") + 1; + + /* .got */ + shdr.sh_name = sh_name; + shdr.sh_type = 1; + shdr.sh_flags = 0x3; + shdr.sh_addr = elf_got_start; + shdr.sh_offset = ofs; + shdr.sh_size = elf_got->size; + shdr.sh_link = 0; + shdr.sh_info = 0; + shdr.sh_addralign = 4; + shdr.sh_entsize = PTR_SIZE; + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); + ofs += elf_got->size; + sh_name += strlen(".got") + 1; + + /* .dynstr */ + shdr.sh_name = sh_name; + shdr.sh_type = 3; + shdr.sh_flags = 0x2; + shdr.sh_addr = elf_got_start + elf_got->size; + shdr.sh_offset = ofs; + shdr.sh_size = elf_dynstr->size; + shdr.sh_link = 0; + shdr.sh_info = 0; + shdr.sh_addralign = 1; + shdr.sh_entsize = 0; + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); + ofs += elf_dynstr->size; + sh_name += strlen(".dynsym") + 1; + + /* .dynsym */ + shdr.sh_name = sh_name; + shdr.sh_type = 11; + shdr.sh_flags = 0x2; + shdr.sh_addr = elf_got_start + elf_got->size + elf_dynstr->size; + shdr.sh_offset = ofs; + shdr.sh_size = elf_dynsym->size; + shdr.sh_link = 7; + shdr.sh_info = 1; + shdr.sh_addralign = 4; + shdr.sh_entsize = sizeof(elf32_sym_t); + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); + ofs += elf_dynsym->size; + sh_name += strlen(".dynsym") + 1; + + /* .dynamic */ + shdr.sh_name = sh_name; + shdr.sh_type = 6; + shdr.sh_flags = 0x3; + shdr.sh_addr = + elf_got_start + elf_got->size + elf_dynstr->size + elf_dynsym->size; + shdr.sh_offset = ofs; + shdr.sh_size = elf_dynamic->size; + shdr.sh_link = 7; /* The section header index of .dynstr. */ + shdr.sh_info = 0; + shdr.sh_addralign = 4; + shdr.sh_entsize = 0; + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); + ofs += elf_dynamic->size; + sh_name += strlen(".dynamic") + 1; + } /* .symtab */ - shdr.sh_name = 0x17; + shdr.sh_name = sh_name; shdr.sh_type = 2; shdr.sh_flags = 0; shdr.sh_addr = 0; shdr.sh_offset = ofs; shdr.sh_size = elf_symtab->size; - shdr.sh_link = 4; + shdr.sh_link = dynlink ? 11 : 4; shdr.sh_info = elf_symbol_index; shdr.sh_addralign = 4; shdr.sh_entsize = 16; - elf_write_blk(elf_section, &shdr, sizeof(elf32_shdr_t)); + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); ofs += elf_symtab->size; + sh_name += strlen(".symtab") + 1; /* .strtab */ - shdr.sh_name = 0x1f; + shdr.sh_name = sh_name; shdr.sh_type = 3; shdr.sh_flags = 0; shdr.sh_addr = 0; @@ -313,39 +461,219 @@ void elf_generate_sections(void) shdr.sh_info = 0; shdr.sh_addralign = 1; shdr.sh_entsize = 0; - elf_write_blk(elf_section, &shdr, sizeof(elf32_shdr_t)); + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); ofs += elf_strtab->size; + sh_name += strlen(".strtab") + 1; /* .shstr */ - shdr.sh_name = 1; + shdr.sh_name = sh_name; shdr.sh_type = 3; shdr.sh_flags = 0; shdr.sh_addr = 0; shdr.sh_offset = ofs; - shdr.sh_size = 39; + shdr.sh_size = elf_shstr->size; shdr.sh_link = 0; shdr.sh_info = 0; shdr.sh_addralign = 1; shdr.sh_entsize = 0; - elf_write_blk(elf_section, &shdr, sizeof(elf32_shdr_t)); + elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); + sh_name += strlen(".shstrtab") + 1; } -void elf_align(void) +void elf_align(strbuf_t *elf_array) { /* Check for null pointers to prevent crashes */ - if (!elf_data || !elf_symtab || !elf_strtab) { + if (!elf_array) { error("ELF buffers not initialized for alignment"); return; } - while (elf_data->size & 3) - elf_write_byte(elf_data, 0); + while (elf_array->size & 3) + elf_write_byte(elf_array, 0); +} - while (elf_symtab->size & 3) - elf_write_byte(elf_symtab, 0); +void elf_generate_sections(void) +{ + if (dynlink) { + elf32_sym_t sym; + elf32_dyn_t dyn; + elf32_rel_t rel; + int dymsym_idx = 1, func_plt_ofs, func_got_ofs, st_name = 0; + relplt_sz = 0; + plt_sz = PLT_FIXUP_SIZE; + /* Add three elements to got: + * + * The first element will point to the .dynamic section later. + * The second and third elements are respectively reserved + * for link_map and resolver. + * */ + got_sz = PTR_SIZE * 3; + memset(&sym, 0, sizeof(elf32_sym_t)); + memset(&dyn, 0, sizeof(elf32_dyn_t)); + + /* interp section */ + elf_write_str(elf_interp, DYN_LINKER); + elf_write_byte(elf_interp, 0); + elf_align(elf_interp); + + /* Precalculate the size of rel.plt, plt, got sections. */ + relplt_sz += sizeof(elf32_rel_t); /* For __libc_start_main */ + plt_sz += PLT_ENT_SIZE; + got_sz += PTR_SIZE; + for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (func->is_used && !func->bbs) { + relplt_sz += sizeof(elf32_rel_t); + plt_sz += PLT_ENT_SIZE; + got_sz += PTR_SIZE; + } + } + /* Add an entry, which is set to 0x0, to the end of got. */ + got_sz += PTR_SIZE; + + /* Get the starting points of the sections. */ + elf_relplt_start = elf_data_start + elf_data->size + elf_interp->size; + elf_plt_start = elf_relplt_start + relplt_sz; + elf_got_start = elf_plt_start + plt_sz; + + /* dynstr, dynsym and relplt sections */ + elf_write_byte(elf_dynstr, 0); + elf_write_blk(elf_dynsym, &sym, sizeof(elf32_sym_t)); + st_name += 1; + + elf_write_str(elf_dynstr, LIBC_SO); /* Add "libc.so.6" to .dynstr. */ + elf_write_byte(elf_dynstr, 0); + st_name += strlen(LIBC_SO) + 1; + + /* Add __libc_start_main explicitly. */ + elf_write_str(elf_dynstr, "__libc_start_main"); + elf_write_byte(elf_dynstr, 0); + sym.st_name = st_name; + sym.st_info = ELF32_ST_INFO(1, 2); /* STB_GLOBAL = 1, STT_FUNC = 2 */ + elf_write_blk(elf_dynsym, &sym, sizeof(elf32_sym_t)); + st_name += strlen("__libc_start_main") + 1; + rel.r_offset = elf_got_start + PTR_SIZE * 3; + rel.r_info = (dymsym_idx << 8) | R_ARCH_JUMP_SLOT; + elf_write_blk(elf_relplt, &rel, sizeof(elf32_rel_t)); + dymsym_idx += 1; + func_plt_ofs = PLT_FIXUP_SIZE + PLT_ENT_SIZE; + func_got_ofs = PTR_SIZE << 2; + for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (func->is_used && !func->bbs) { + /* Handle all functions that need relocation */ + elf_write_str(elf_dynstr, func->return_def.var_name); + elf_write_byte(elf_dynstr, 0); + sym.st_name = st_name; + sym.st_info = ELF32_ST_INFO(1, 2); + elf_write_blk(elf_dynsym, &sym, sizeof(elf32_sym_t)); + st_name += strlen(func->return_def.var_name) + 1; + rel.r_offset += PTR_SIZE; + rel.r_info = (dymsym_idx << 8) | R_ARCH_JUMP_SLOT; + elf_write_blk(elf_relplt, &rel, sizeof(elf32_rel_t)); + dymsym_idx += 1; + func->plt_offset = func_plt_ofs; + func->got_offset = func_got_ofs; + func_plt_ofs += PLT_ENT_SIZE; + func_got_ofs += PTR_SIZE; + } + } + elf_align(elf_dynstr); + + /* got section */ + elf_write_int( + elf_got, + elf_got_start + got_sz + elf_dynstr->size + + elf_dynsym->size); /* The virtual address of .dynamic. */ + elf_write_int(elf_got, 0); /* Set got[1] to 0 for link_map. */ + elf_write_int(elf_got, 0); /* Set got[2] to 0 for resolver. */ + for (int i = PTR_SIZE * 3; i < got_sz - PTR_SIZE; i += PTR_SIZE) + elf_write_int(elf_got, elf_plt_start); + elf_write_int(elf_got, 0); /* End with 0x0 */ + + /* dynamic section */ + dyn.d_tag = 0x5; /* STRTAB */ + dyn.d_un = elf_got_start + got_sz; /* The virtual address of .dynstr. */ + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0xa; /* STRSZ */ + dyn.d_un = elf_dynstr->size; + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x6; /* SYMTAB */ + dyn.d_un = elf_got_start + got_sz + + elf_dynstr->size; /* The virtual address of .dynsym. */ + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0xb; /* SYMENT */ + dyn.d_un = sizeof(elf32_sym_t); /* Size of an entry. */ + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x11; /* REL */ + dyn.d_un = elf_relplt_start; /* The virtual address of .rel.plt. */ + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x12; /* RELSZ */ + dyn.d_un = relplt_sz; + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x13; /* RELENT */ + dyn.d_un = sizeof(elf32_rel_t); + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x3; /* PLTGOT */ + dyn.d_un = elf_got_start; /* The virtual address of .got.*/ + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x2; /* PLTRELSZ */ + dyn.d_un = relplt_sz; + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x14; /* PLTREL */ + dyn.d_un = 0x11; + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x17; /* JMPREL */ + dyn.d_un = elf_relplt_start; + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x1; /* NEEDED */ + dyn.d_un = 0x1; /* The index of "libc.so.6" in .dynstr. */ + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x0; /* NULL */ + dyn.d_un = 0x0; + elf_write_blk(elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + } - while (elf_strtab->size & 3) - elf_write_byte(elf_strtab, 0); + /* shstr section; len = 39 + * If using dynamic linking, len = 91. + */ + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".text"); + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".data"); + elf_write_byte(elf_shstr, 0); + if (dynlink) { + elf_write_str(elf_shstr, ".interp"); + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".rel.plt"); + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".plt"); + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".got"); + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".dynstr"); + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".dynsym"); + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".dynamic"); + elf_write_byte(elf_shstr, 0); + } + elf_write_str(elf_shstr, ".symtab"); + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".strtab"); + elf_write_byte(elf_shstr, 0); + elf_write_str(elf_shstr, ".shstrtab"); + elf_write_byte(elf_shstr, 0); } void elf_add_symbol(char *symbol, int pc) @@ -366,12 +694,28 @@ void elf_add_symbol(char *symbol, int pc) elf_symbol_index++; } -void elf_generate(char *outfile) +void elf_preprocess(void) { - elf_align(); - elf_generate_header(); + elf_header_len = sizeof(elf32_hdr_t) + sizeof(elf32_phdr_t); + if (dynlink) + elf_header_len += (sizeof(elf32_phdr_t) * 3); + elf_code_start = ELF_START + elf_header_len; + elf_data_start = elf_code_start + elf_offset; + elf_align(elf_data); elf_generate_sections(); + elf_align(elf_symtab); + elf_align(elf_strtab); +} + +void elf_postprocess(void) +{ + elf_generate_header(); + elf_generate_program_headers(); + elf_generate_section_headers(); +} +void elf_generate(char *outfile) +{ if (!outfile) outfile = "a.out"; @@ -383,11 +727,35 @@ void elf_generate(char *outfile) for (int i = 0; i < elf_header->size; i++) fputc(elf_header->elements[i], fp); + for (int i = 0; i < elf_program_header->size; i++) + fputc(elf_program_header->elements[i], fp); for (int i = 0; i < elf_code->size; i++) fputc(elf_code->elements[i], fp); for (int i = 0; i < elf_data->size; i++) fputc(elf_data->elements[i], fp); - for (int i = 0; i < elf_section->size; i++) - fputc(elf_section->elements[i], fp); + if (dynlink) { + for (int i = 0; i < elf_interp->size; i++) + fputc(elf_interp->elements[i], fp); + for (int i = 0; i < elf_relplt->size; i++) + fputc(elf_relplt->elements[i], fp); + for (int i = 0; i < elf_plt->size; i++) + fputc(elf_plt->elements[i], fp); + for (int i = 0; i < elf_got->size; i++) + fputc(elf_got->elements[i], fp); + for (int i = 0; i < elf_dynstr->size; i++) + fputc(elf_dynstr->elements[i], fp); + for (int i = 0; i < elf_dynsym->size; i++) + fputc(elf_dynsym->elements[i], fp); + for (int i = 0; i < elf_dynamic->size; i++) + fputc(elf_dynamic->elements[i], fp); + } + for (int i = 0; i < elf_symtab->size; i++) + fputc(elf_symtab->elements[i], fp); + for (int i = 0; i < elf_strtab->size; i++) + fputc(elf_strtab->elements[i], fp); + for (int i = 0; i < elf_shstr->size; i++) + fputc(elf_shstr->elements[i], fp); + for (int i = 0; i < elf_section_header->size; i++) + fputc(elf_section_header->elements[i], fp); fclose(fp); } diff --git a/src/globals.c b/src/globals.c index 23bbb8e3..172d7a88 100644 --- a/src/globals.c +++ b/src/globals.c @@ -94,14 +94,34 @@ hashmap_t *INCLUSION_MAP; strbuf_t *elf_code; strbuf_t *elf_data; strbuf_t *elf_header; +strbuf_t *elf_program_header; strbuf_t *elf_symtab; strbuf_t *elf_strtab; -strbuf_t *elf_section; -int elf_header_len = 0x54; /* ELF fixed: 0x34 + 1 * 0x20 */ +strbuf_t *elf_section_header; +strbuf_t *elf_shstr; +strbuf_t *elf_interp; +strbuf_t *elf_dynamic; +strbuf_t *elf_dynsym; +strbuf_t *elf_dynstr; +strbuf_t *elf_relplt; +strbuf_t *elf_plt; +strbuf_t *elf_got; +int elf_header_len; int elf_code_start; int elf_data_start; +int elf_relplt_start; +int elf_plt_start; +int elf_got_start; +int relplt_sz; +int plt_sz; +int got_sz; + +/* Dynamic linking flag */ +bool dynlink = false; /* Create a new arena block with given capacity. + * arena_block_create() - Creates a new arena block with given capacity. + * The created arena block is guaranteed to be zero-initialized. * @capacity: The capacity of the arena block. Must be positive. * * Return: The pointer of created arena block. NULL if failed to allocate. @@ -1178,8 +1198,6 @@ void strbuf_free(strbuf_t *src) */ void global_init(void) { - elf_code_start = ELF_START + elf_header_len; - MACROS_MAP = hashmap_create(MAX_ALIASES); /* Initialize arenas first so we can use them for allocation */ @@ -1220,9 +1238,18 @@ void global_init(void) elf_code = strbuf_create(MAX_CODE); elf_data = strbuf_create(MAX_DATA); elf_header = strbuf_create(MAX_HEADER); + elf_program_header = strbuf_create(MAX_PROGRAM_HEADER); elf_symtab = strbuf_create(MAX_SYMTAB); elf_strtab = strbuf_create(MAX_STRTAB); - elf_section = strbuf_create(MAX_SECTION); + elf_shstr = strbuf_create(MAX_SHSTR); + elf_section_header = strbuf_create(MAX_SECTION_HEADER); + elf_interp = strbuf_create(MAX_INTERP); + elf_dynamic = strbuf_create(MAX_DYNAMIC); + elf_dynsym = strbuf_create(MAX_DYNSYM); + elf_dynstr = strbuf_create(MAX_DYNSTR); + elf_relplt = strbuf_create(MAX_RELPLT); + elf_plt = strbuf_create(MAX_PLT); + elf_got = strbuf_create(MAX_GOTPLT); } /* Forward declaration for lexer cleanup */ @@ -1338,19 +1365,27 @@ void global_release(void) arena_free(BB_ARENA); arena_free(HASHMAP_ARENA); arena_free(GENERAL_ARENA); /* free TYPES and PH2_IR_FLATTEN */ + hashmap_free(FUNC_MAP); + hashmap_free(INCLUSION_MAP); + hashmap_free(ALIASES_MAP); + hashmap_free(CONSTANTS_MAP); strbuf_free(SOURCE); strbuf_free(elf_code); strbuf_free(elf_data); strbuf_free(elf_header); + strbuf_free(elf_program_header); strbuf_free(elf_symtab); strbuf_free(elf_strtab); - strbuf_free(elf_section); - - hashmap_free(FUNC_MAP); - hashmap_free(INCLUSION_MAP); - hashmap_free(ALIASES_MAP); - hashmap_free(CONSTANTS_MAP); + strbuf_free(elf_shstr); + strbuf_free(elf_section_header); + strbuf_free(elf_interp); + strbuf_free(elf_dynamic); + strbuf_free(elf_dynsym); + strbuf_free(elf_dynstr); + strbuf_free(elf_relplt); + strbuf_free(elf_plt); + strbuf_free(elf_got); } /* Reports an error without specifying a position */ @@ -1404,6 +1439,8 @@ void print_indent(int indent) void dump_bb_insn(func_t *func, basic_block_t *bb, bool *at_func_start) { + if (!bb) + return; var_t *rd, *rs1, *rs2; if (bb != func->bbs && bb->insn_list.head) { @@ -1621,7 +1658,7 @@ void dump_bb_insn_by_dom(func_t *func, basic_block_t *bb, bool *at_func_start) { dump_bb_insn(func, bb, at_func_start); for (int i = 0; i < MAX_BB_DOM_SUCC; i++) { - if (!bb->dom_next[i]) + if (!bb || !bb->dom_next[i]) break; dump_bb_insn_by_dom(func, bb->dom_next[i], at_func_start); } @@ -1655,6 +1692,8 @@ void dump_insn(void) /* Handle implicit return */ for (int i = 0; i < MAX_BB_PRED; i++) { + if (!func->exit) + break; basic_block_t *bb = func->exit->prev[i].bb; if (!bb) continue; diff --git a/src/main.c b/src/main.c index aa72d453..793aff9a 100644 --- a/src/main.c +++ b/src/main.c @@ -58,6 +58,8 @@ int main(int argc, char *argv[]) hard_mul_div = 1; else if (!strcmp(argv[i], "--no-libc")) libc = 0; + else if (!strcmp(argv[i], "--dynlink")) + dynlink = true; else if (!strcmp(argv[i], "-o")) { if (i + 1 < argc) { out = argv[i + 1]; @@ -74,7 +76,7 @@ int main(int argc, char *argv[]) if (!in) { printf("Missing source file!\n"); printf( - "Usage: shecc [-o output] [+m] [--dump-ir] [--no-libc] " + "Usage: shecc [-o output] [+m] [--dump-ir] [--no-libc] [--dynlink]" "\n"); return -1; } @@ -132,9 +134,19 @@ int main(int argc, char *argv[]) if (dump_ir) dump_ph2_ir(); + /* + * ELF preprocess: + * 1. generate all sections except for .text section. + * 2. calculate the starting addresses of certain sections. + */ + elf_preprocess(); + /* generate code from IR */ code_generate(); + /* ELF postprocess: generate all ELF headers */ + elf_postprocess(); + /* output code in ELF */ elf_generate(out); diff --git a/src/parser.c b/src/parser.c index e043c586..7cd478a1 100644 --- a/src/parser.c +++ b/src/parser.c @@ -4719,12 +4719,14 @@ void parse_internal(void) /* shecc run-time defines */ add_alias("__SHECC__", "1"); - /* Linux syscall */ - func_t *func = add_func("__syscall", true); - func->return_def.type = TY_int; - func->num_params = 0; - func->va_args = 1; - func->bbs = arena_calloc(BB_ARENA, 1, sizeof(basic_block_t)); + if (!dynlink) { + /* Linux syscall */ + func_t *func = add_func("__syscall", true); + func->return_def.type = TY_int; + func->num_params = 0; + func->va_args = 1; + func->bbs = arena_alloc(BB_ARENA, sizeof(basic_block_t)); + } /* lexer initialization */ SOURCE->size = 0; diff --git a/src/reg-alloc.c b/src/reg-alloc.c index 30ba71e3..6c982d4e 100644 --- a/src/reg-alloc.c +++ b/src/reg-alloc.c @@ -378,6 +378,8 @@ void reg_alloc(void) } for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; func->visited++; if (!strcmp(func->return_def.var_name, "main")) @@ -549,6 +551,10 @@ void reg_alloc(void) ir = bb_add_ph2_ir(bb, OP_address_of_func); ir->src0 = src0; strcpy(ir->func_name, insn->rs2->var_name); + if (dynlink) { + func_t *target_func = find_func(ir->func_name); + target_func->is_used = true; + } } else { /* FIXME: Avoid outdated content in register after * storing, but causing some redundant spilling. @@ -597,6 +603,10 @@ void reg_alloc(void) ir = bb_add_ph2_ir(bb, OP_call); strcpy(ir->func_name, insn->str); + if (dynlink) { + func_t *target_func = find_func(ir->func_name); + target_func->is_used = true; + } is_pushing_args = 0; args = 0; diff --git a/src/riscv-codegen.c b/src/riscv-codegen.c index 3b3019cb..a8c10a28 100644 --- a/src/riscv-codegen.c +++ b/src/riscv-codegen.c @@ -438,9 +438,6 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) void code_generate(void) { - elf_data_start = elf_code_start + elf_offset; - func_t *func; - /* start: save original sp in s0; allocate global stack; run init */ emit(__addi(__s0, __sp, 0)); emit(__lui(__t0, rv_hi(GLOBAL_FUNC->stack_size))); diff --git a/src/ssa.c b/src/ssa.c index b9f7bedf..93bf534a 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -113,6 +113,8 @@ void build_rpo(void) { bb_traversal_args_t *args = arena_alloc_traversal_args(); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; args->func = func; args->bb = func->bbs; @@ -156,6 +158,8 @@ void build_idom(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { bool changed; + if (!func->bbs) + continue; func->bbs->idom = func->bbs; @@ -227,6 +231,8 @@ void build_dom(void) { bb_traversal_args_t *args = arena_alloc_traversal_args(); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; args->func = func; args->bb = func->bbs; @@ -261,6 +267,8 @@ void build_df(void) { bb_traversal_args_t *args = arena_alloc_traversal_args(); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; args->func = func; args->bb = func->bbs; @@ -285,6 +293,8 @@ void build_r_idom(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { bool changed; + if (!func->bbs) + continue; func->exit->r_idom = func->exit; @@ -341,6 +351,8 @@ bool rdom_connect(basic_block_t *pred, basic_block_t *succ) void bb_build_rdom(func_t *func, basic_block_t *bb) { + if (!func->bbs) + return; for (basic_block_t *curr = bb; curr != func->exit; curr = curr->r_idom) { if (!rdom_connect(curr->r_idom, curr)) break; @@ -351,6 +363,8 @@ void build_rdom(void) { bb_traversal_args_t *args = arena_alloc_traversal_args(); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; args->func = func; args->bb = func->exit; @@ -395,6 +409,9 @@ void build_rdf(void) { bb_traversal_args_t *args = arena_alloc_traversal_args(); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; + args->func = func; args->bb = func->exit; @@ -436,6 +453,8 @@ void use_chain_delete(use_chain_t *u, var_t *var) void use_chain_build(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) { for (insn_t *i = bb->insn_list.head; i; i = i->next) { if (i->rs1) @@ -542,6 +561,8 @@ void solve_globals(void) { bb_traversal_args_t *args = arena_alloc_traversal_args(); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; args->func = func; args->bb = func->bbs; @@ -603,6 +624,8 @@ bool insert_phi_insn(basic_block_t *bb, var_t *var) void solve_phi_insertion(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; for (symbol_t *sym = func->global_sym_list.head; sym; sym = sym->next) { var_t *var = sym->var; @@ -795,6 +818,8 @@ void bb_solve_phi_params(basic_block_t *bb) void solve_phi_params(void) { for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; for (int i = 0; i < func->num_params; i++) { /* FIXME: Rename arguments directly, might be not good here. */ var_t *var = require_var(func->bbs->scope); @@ -868,6 +893,8 @@ void unwind_phi(void) { bb_traversal_args_t *args = arena_alloc_traversal_args(); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; args->func = func; args->bb = func->bbs; @@ -1169,6 +1196,8 @@ void dump_cfg(char name[]) fprintf(fd, "strict digraph CFG {\n"); fprintf(fd, "node [shape=box]\n"); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; func->visited++; fprintf(fd, "subgraph cluster_%p {\n", func); fprintf(fd, "label=\"%p (%s)\"\n", func, func->return_def.var_name); @@ -1198,6 +1227,8 @@ void dump_dom(char name[]) fprintf(fd, "node [shape=box]\n"); fprintf(fd, "splines=polyline\n"); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; fprintf(fd, "subgraph cluster_%p {\n", func); fprintf(fd, "label=\"%p\"\n", func); dom_dump(fd, func->bbs); @@ -1813,7 +1844,8 @@ void optimize(void) for (func_t *func = FUNC_LIST.head; func; func = func->next) { /* basic block level (control flow) optimizations */ - + if (!func->bbs) + continue; for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) { /* instruction level optimizations */ for (insn_t *insn = bb->insn_list.head; insn; insn = insn->next) { @@ -1869,6 +1901,8 @@ void optimize(void) /* Mark useful instructions */ for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) { dce_insn(bb); } @@ -1913,6 +1947,8 @@ void build_reversed_rpo(void) { bb_traversal_args_t *args = arena_alloc_traversal_args(); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; func->bb_cnt = 0; args->func = func; args->bb = func->exit; @@ -2062,6 +2098,9 @@ void liveness_analysis(void) { bb_traversal_args_t *args = arena_alloc_traversal_args(); for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; + args->func = func; args->bb = func->bbs; @@ -2078,6 +2117,8 @@ void liveness_analysis(void) } for (func_t *func = FUNC_LIST.head; func; func = func->next) { + if (!func->bbs) + continue; basic_block_t *bb = func->exit; bool changed; do { From 197ac2313c519215f822dc971d6cf9662b74c4f9 Mon Sep 17 00:00:00 2001 From: Yu-En Hsiao Date: Tue, 26 Aug 2025 22:53:34 +0800 Subject: [PATCH 2/3] Add memcmp to lib/c.h --- lib/c.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/c.h b/lib/c.h index 0a99f2e5..3646b7af 100644 --- a/lib/c.h +++ b/lib/c.h @@ -29,6 +29,7 @@ int strncmp(char *s1, char *s2, int len); char *strcpy(char *dest, char *src); char *strncpy(char *dest, char *src, int len); char *memcpy(char *dest, char *src, int count); +int memcmp(void *s1, void *s2, int n); void *memset(void *s, int c, int n); /* formatted output string */ From 1aceea3be0ae75a905b5f8486d61a20eb62ff20a Mon Sep 17 00:00:00 2001 From: Yu-En Hsiao Date: Tue, 26 Aug 2025 22:54:04 +0800 Subject: [PATCH 3/3] Refine codegen and ELF handling --- src/arm-codegen.c | 53 +++++++++++++++++---------- src/elf.c | 92 ++++++++++++++++++++++++++--------------------- src/globals.c | 1 + src/parser.c | 14 +++++--- src/reg-alloc.c | 6 ++-- 5 files changed, 99 insertions(+), 67 deletions(-) diff --git a/src/arm-codegen.c b/src/arm-codegen.c index c4313ffe..0ef32102 100644 --- a/src/arm-codegen.c +++ b/src/arm-codegen.c @@ -138,11 +138,13 @@ void cfg_flatten(void) func_t *func; if (dynlink) - elf_offset = 112; /* offset of start + branch + exit in codegen */ + elf_offset = + 88; /* offset of dynamic linking setup + global init call */ else { func = find_func("__syscall"); func->bbs->elf_offset = 48; /* offset of start + exit in codegen */ - elf_offset = 84; /* offset of start + branch + exit + syscall in codegen */ + elf_offset = + 84; /* offset of start + branch + exit + syscall in codegen */ } GLOBAL_FUNC->bbs->elf_offset = elf_offset; @@ -154,7 +156,7 @@ void cfg_flatten(void) /* prepare 'argc' and 'argv', then proceed to 'main' function */ if (dynlink) - elf_offset += 20; + elf_offset += 20; /* 5 insns: restore r0/r1 from r9/r10, bl to main */ else elf_offset += 32; /* 6 insns for main call + 2 for exit */ @@ -481,8 +483,22 @@ void code_generate(void) emit(__push_reg(__AL, __r0)); emit(__mov_i(__AL, __r12, 0)); emit(__push_reg(__AL, __r12)); - emit(__movw(__AL, __r0, elf_code_start + 56)); - emit(__movt(__AL, __r0, elf_code_start + 56)); + /* Pass the address of our main wrapper function; + * After these two mov movw/movt, we have: + * - mov r3, #0 + * - bl to __libc_start_main@plt + * - mov r0, #127 + * - bl +28 + * - (main wrapper starts here) + * + * Total offset = current + 8 + 16 = current + 24 + * + * That is, the current code size + 24 is the starting address + * of main wrapper. + * */ + int main_wrapper_offset = elf_code->size + 24; + emit(__movw(__AL, __r0, elf_code_start + main_wrapper_offset)); + emit(__movt(__AL, __r0, elf_code_start + main_wrapper_offset)); emit(__mov_i(__AL, __r3, 0)); emit(__bl(__AL, (elf_plt_start + PLT_FIXUP_SIZE) - (elf_code_start + elf_code->size))); @@ -490,34 +506,33 @@ void code_generate(void) emit(__mov_i(__AL, __r0, 127)); emit(__bl(__AL, 28)); - /* If the compiled program is dynamic linking, the starting - * point of 'start' is located here. - * - * Preserve the 'argc' and 'argv' for the 'main' function. + /* If the compiled program is dynamic linking, it needs to + * preserve the 'argc' and 'argv' for the 'main' function. * */ emit(__mov_r(__AL, __r9, __r0)); emit(__mov_r(__AL, __r10, __r1)); } - /* If the compiled program is static linking, the starting point - * of 'start' is here. + /* For both static and dynamic linking, we need to set up the stack + * and call the main function. * */ emit(__movw(__AL, __r8, GLOBAL_FUNC->stack_size)); emit(__movt(__AL, __r8, GLOBAL_FUNC->stack_size)); emit(__sub_r(__AL, __sp, __sp, __r8)); emit(__mov_r(__AL, __r12, __sp)); + /* Calculate the branch offset to the global initialization code */ emit(__bl(__AL, GLOBAL_FUNC->bbs->elf_offset - elf_code->size)); /* After global init, jump to main preparation */ emit(__b(__AL, 56)); /* PC+8: skip exit (24) + syscall (36) + ret (4) - 8 */ - /* exit */ - emit(__movw(__AL, __r8, GLOBAL_FUNC->stack_size)); - emit(__movt(__AL, __r8, GLOBAL_FUNC->stack_size)); - emit(__add_r(__AL, __sp, __sp, __r8)); - emit(__mov_r(__AL, __r0, __r0)); - emit(__mov_i(__AL, __r7, 1)); - emit(__svc()); - if (!dynlink) { + /* exit - only for statck linking */ + emit(__movw(__AL, __r8, GLOBAL_FUNC->stack_size)); + emit(__movt(__AL, __r8, GLOBAL_FUNC->stack_size)); + emit(__add_r(__AL, __sp, __sp, __r8)); + emit(__mov_r(__AL, __r0, __r0)); + emit(__mov_i(__AL, __r7, 1)); + emit(__svc()); + /* syscall */ emit(__mov_r(__AL, __r7, __r0)); emit(__mov_r(__AL, __r0, __r1)); diff --git a/src/elf.c b/src/elf.c index 4022183a..b216bde5 100644 --- a/src/elf.c +++ b/src/elf.c @@ -193,28 +193,29 @@ void elf_generate_program_headers(void) * 54 | | | */ /* program header - code and data combined */ - phdr.p_type = 1; /* PT_LOAD */ - phdr.p_offset = elf_header_len; /* offset of segment */ - phdr.p_vaddr = elf_code_start; /* virtual address */ - phdr.p_paddr = elf_code_start; /* physical address */ + phdr.p_type = 1; /* PT_LOAD */ + phdr.p_offset = elf_header_len; /* offset of segment */ + phdr.p_vaddr = elf_code_start; /* virtual address */ + phdr.p_paddr = elf_code_start; /* physical address */ + /* Don't include interp in the first LOAD segment for dynlink */ phdr.p_filesz = elf_code->size + elf_data->size; /* size in file */ phdr.p_memsz = elf_code->size + elf_data->size; /* size in memory */ phdr.p_flags = 7; /* flags */ phdr.p_align = 4; /* alignment */ elf_write_blk(elf_program_header, &phdr, sizeof(elf32_phdr_t)); if (dynlink) { - /* program header - .rel.plt .plt .got .dynstr .dynsym and .dynamic - * sections combined */ + /* program header - interp + dynamic sections combined in second LOAD */ phdr.p_type = 1; /* PT_LOAD */ - phdr.p_offset = elf_header_len + elf_code->size + elf_data->size + - elf_interp->size; /* offset of segment */ - phdr.p_vaddr = elf_relplt_start; /* virtual address */ - phdr.p_paddr = elf_relplt_start; /* physical address */ - phdr.p_filesz = elf_relplt->size + elf_plt->size + elf_got->size + - elf_dynstr->size + elf_dynsym->size + + phdr.p_offset = elf_header_len + elf_code->size + + elf_data->size; /* offset of segment */ + /* Virtual address must map correctly: VA = ELF_START + file_offset */ + phdr.p_vaddr = ELF_START + phdr.p_offset; /* virtual address */ + phdr.p_paddr = ELF_START + phdr.p_offset; /* physical address */ + phdr.p_filesz = elf_interp->size + elf_relplt->size + elf_plt->size + + elf_got->size + elf_dynstr->size + elf_dynsym->size + elf_dynamic->size; /* size in file */ - phdr.p_memsz = elf_relplt->size + elf_plt->size + elf_got->size + - elf_dynstr->size + elf_dynsym->size + + phdr.p_memsz = elf_interp->size + elf_relplt->size + elf_plt->size + + elf_got->size + elf_dynstr->size + elf_dynsym->size + elf_dynamic->size; /* size in memory */ phdr.p_flags = 7; /* flags */ phdr.p_align = 4; /* alignment */ @@ -223,13 +224,14 @@ void elf_generate_program_headers(void) /* program header - program interpreter (.interp section) */ phdr.p_type = 3; /* PT_INTERP */ phdr.p_offset = elf_header_len + elf_code->size + - elf_data->size; /* offset of segment */ - phdr.p_vaddr = elf_data_start + elf_data->size; /* virtual address */ - phdr.p_paddr = elf_data_start + elf_data->size; /* physical address */ - phdr.p_filesz = strlen(DYN_LINKER) + 1; /* size in file */ - phdr.p_memsz = strlen(DYN_LINKER) + 1; /* size in memory */ - phdr.p_flags = 4; /* flags */ - phdr.p_align = 1; /* alignment */ + elf_data->size; /* offset of segment */ + /* Virtual address must map correctly: VA = ELF_START + file_offset */ + phdr.p_vaddr = ELF_START + phdr.p_offset; /* virtual address */ + phdr.p_paddr = ELF_START + phdr.p_offset; /* physical address */ + phdr.p_filesz = elf_interp->size; /* size in file */ + phdr.p_memsz = elf_interp->size; /* size in memory */ + phdr.p_flags = 4; /* flags */ + phdr.p_align = 1; /* alignment */ elf_write_blk(elf_program_header, &phdr, sizeof(elf32_phdr_t)); /* program header - .dynamic section */ @@ -237,15 +239,13 @@ void elf_generate_program_headers(void) phdr.p_offset = elf_header_len + elf_code->size + elf_data->size + elf_interp->size + elf_relplt->size + elf_plt->size + elf_got->size + elf_dynstr->size + - elf_dynsym->size; /* offset of segment */ - phdr.p_vaddr = elf_got_start + elf_got->size + elf_dynstr->size + - elf_dynsym->size; /* virtual address */ - phdr.p_paddr = elf_got_start + elf_got->size + elf_dynstr->size + - elf_dynsym->size; /* physical address */ - phdr.p_filesz = elf_dynamic->size; /* size in file */ - phdr.p_memsz = elf_dynamic->size; /* size in memory */ - phdr.p_flags = 6; /* flags */ - phdr.p_align = 4; /* alignment */ + elf_dynsym->size; /* offset of segment */ + phdr.p_vaddr = ELF_START + phdr.p_offset; /* virtual address */ + phdr.p_paddr = ELF_START + phdr.p_offset; /* physical address */ + phdr.p_filesz = elf_dynamic->size; /* size in file */ + phdr.p_memsz = elf_dynamic->size; /* size in memory */ + phdr.p_flags = 6; /* flags */ + phdr.p_align = 4; /* alignment */ elf_write_blk(elf_program_header, &phdr, sizeof(elf32_phdr_t)); } } @@ -332,7 +332,7 @@ void elf_generate_section_headers(void) shdr.sh_name = sh_name; shdr.sh_type = 1; shdr.sh_flags = 0x2; - shdr.sh_addr = elf_data_start + elf_data->size; + shdr.sh_addr = ELF_START + ofs; /* Use consistent VA calculation */ shdr.sh_offset = ofs; shdr.sh_size = strlen(DYN_LINKER) + 1; shdr.sh_link = 0; @@ -345,9 +345,9 @@ void elf_generate_section_headers(void) /* .rel.plt */ shdr.sh_name = sh_name; - shdr.sh_type = 9; /* SHT_REL */ - shdr.sh_flags = 0x42; /* 0x40 | SHF_ALLOC */ - shdr.sh_addr = elf_relplt_start; + shdr.sh_type = 9; /* SHT_REL */ + shdr.sh_flags = 0x42; /* 0x40 | SHF_ALLOC */ + shdr.sh_addr = ELF_START + ofs; /* Use consistent VA calculation */ shdr.sh_offset = ofs; shdr.sh_size = elf_relplt->size; shdr.sh_link = 8; /* The section header index of .dynsym. */ @@ -362,7 +362,7 @@ void elf_generate_section_headers(void) shdr.sh_name = sh_name; shdr.sh_type = 1; shdr.sh_flags = 0x6; - shdr.sh_addr = elf_plt_start; + shdr.sh_addr = ELF_START + ofs; /* Use consistent VA calculation */ shdr.sh_offset = ofs; shdr.sh_size = elf_plt->size; shdr.sh_link = 0; @@ -377,7 +377,7 @@ void elf_generate_section_headers(void) shdr.sh_name = sh_name; shdr.sh_type = 1; shdr.sh_flags = 0x3; - shdr.sh_addr = elf_got_start; + shdr.sh_addr = ELF_START + ofs; /* Use consistent VA calculation */ shdr.sh_offset = ofs; shdr.sh_size = elf_got->size; shdr.sh_link = 0; @@ -392,7 +392,7 @@ void elf_generate_section_headers(void) shdr.sh_name = sh_name; shdr.sh_type = 3; shdr.sh_flags = 0x2; - shdr.sh_addr = elf_got_start + elf_got->size; + shdr.sh_addr = ELF_START + ofs; /* Use consistent VA calculation */ shdr.sh_offset = ofs; shdr.sh_size = elf_dynstr->size; shdr.sh_link = 0; @@ -407,7 +407,7 @@ void elf_generate_section_headers(void) shdr.sh_name = sh_name; shdr.sh_type = 11; shdr.sh_flags = 0x2; - shdr.sh_addr = elf_got_start + elf_got->size + elf_dynstr->size; + shdr.sh_addr = ELF_START + ofs; /* Use consistent VA calculation */ shdr.sh_offset = ofs; shdr.sh_size = elf_dynsym->size; shdr.sh_link = 7; @@ -422,8 +422,7 @@ void elf_generate_section_headers(void) shdr.sh_name = sh_name; shdr.sh_type = 6; shdr.sh_flags = 0x3; - shdr.sh_addr = - elf_got_start + elf_got->size + elf_dynstr->size + elf_dynsym->size; + shdr.sh_addr = ELF_START + ofs; /* Use consistent VA calculation */ shdr.sh_offset = ofs; shdr.sh_size = elf_dynamic->size; shdr.sh_link = 7; /* The section header index of .dynstr. */ @@ -531,7 +530,14 @@ void elf_generate_sections(void) got_sz += PTR_SIZE; /* Get the starting points of the sections. */ - elf_relplt_start = elf_data_start + elf_data->size + elf_interp->size; + int code_size_estimate = elf_offset; + int data_size_adjusted = elf_data->size; + + /* Now calculate the virtual addresses */ + int file_offset_after_data = + elf_header_len + code_size_estimate + data_size_adjusted; + elf_interp_start = ELF_START + file_offset_after_data; + elf_relplt_start = elf_interp_start + elf_interp->size; elf_plt_start = elf_relplt_start + relplt_sz; elf_got_start = elf_plt_start + plt_sz; @@ -701,8 +707,12 @@ void elf_preprocess(void) elf_header_len += (sizeof(elf32_phdr_t) * 3); elf_code_start = ELF_START + elf_header_len; elf_data_start = elf_code_start + elf_offset; + /* Align elf_data BEFORE generate_sections so the size is correct */ elf_align(elf_data); + + /* Now generate sections with the correct aligned sizes */ elf_generate_sections(); + elf_align(elf_symtab); elf_align(elf_strtab); } diff --git a/src/globals.c b/src/globals.c index 172d7a88..6e1be4cd 100644 --- a/src/globals.c +++ b/src/globals.c @@ -109,6 +109,7 @@ strbuf_t *elf_got; int elf_header_len; int elf_code_start; int elf_data_start; +int elf_interp_start; int elf_relplt_start; int elf_plt_start; int elf_got_start; diff --git a/src/parser.c b/src/parser.c index 7cd478a1..7fc793ff 100644 --- a/src/parser.c +++ b/src/parser.c @@ -4719,13 +4719,17 @@ void parse_internal(void) /* shecc run-time defines */ add_alias("__SHECC__", "1"); + /* Linux syscall */ + func_t *func = add_func("__syscall", true); + func->return_def.type = TY_int; + func->num_params = 0; + func->va_args = 1; if (!dynlink) { - /* Linux syscall */ - func_t *func = add_func("__syscall", true); - func->return_def.type = TY_int; - func->num_params = 0; - func->va_args = 1; func->bbs = arena_alloc(BB_ARENA, sizeof(basic_block_t)); + } else { + /* In dynlink mode. __syscall won't be implemented but needs to exist + * for parsing the built-in libc. It will be treated as external */ + func->bbs = NULL; } /* lexer initialization */ diff --git a/src/reg-alloc.c b/src/reg-alloc.c index 6c982d4e..2195491d 100644 --- a/src/reg-alloc.c +++ b/src/reg-alloc.c @@ -553,7 +553,8 @@ void reg_alloc(void) strcpy(ir->func_name, insn->rs2->var_name); if (dynlink) { func_t *target_func = find_func(ir->func_name); - target_func->is_used = true; + if (target_func) + target_func->is_used = true; } } else { /* FIXME: Avoid outdated content in register after @@ -605,7 +606,8 @@ void reg_alloc(void) strcpy(ir->func_name, insn->str); if (dynlink) { func_t *target_func = find_func(ir->func_name); - target_func->is_used = true; + if (target_func) + target_func->is_used = true; } is_pushing_args = 0;