diff --git a/Makefile b/Makefile index 73f2bc0d..4fa98b11 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)) @@ -111,9 +120,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 @@ -128,12 +137,12 @@ $(OUT)/$(STAGE0): $(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..14065685 --- /dev/null +++ b/lib/c.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/* 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 ebfb5801..6fb1079a 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 = 44; /* offset of start + exit in codegen */ + func_t *func; + + if (dynlink) + elf_offset = 108; /* offset of start + exit in codegen */ + else { + func = find_func("__syscall"); + func->bbs->elf_offset = 44; /* offset of start + exit in codegen */ + elf_offset = 80; /* offset of start + exit + syscall in codegen */ + } - elf_offset = 80; /* offset of start + 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)); @@ -466,16 +515,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; @@ -483,11 +534,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 */ @@ -499,3 +555,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 3b6f4438..7e0affe1 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 @@ -516,6 +526,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; }; @@ -578,3 +593,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 243d8816..f4d6a5ae 100644 --- a/src/elf.c +++ b/src/elf.c @@ -47,9 +47,25 @@ 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) { 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. @@ -119,25 +135,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. * @@ -161,44 +179,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) { - /* 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 @@ -228,7 +270,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; @@ -238,24 +280,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; @@ -265,25 +309,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; @@ -293,33 +447,213 @@ 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) { - while (elf_data->size & 3) - elf_write_byte(elf_data, 0); + while (elf_array->size & 3) + elf_write_byte(elf_array, 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; - while (elf_symtab->size & 3) - elf_write_byte(elf_symtab, 0); + 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; - while (elf_strtab->size & 3) - elf_write_byte(elf_strtab, 0); + /* 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)); + } + + /* 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) @@ -334,23 +668,63 @@ 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"; FILE *fp = fopen(outfile, "wb"); 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 df8abefe..279cec7a 100644 --- a/src/globals.c +++ b/src/globals.c @@ -86,14 +86,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. @@ -1100,8 +1120,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 */ @@ -1125,9 +1143,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 */ @@ -1144,19 +1171,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 */ @@ -1210,6 +1245,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) { @@ -1427,7 +1464,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); } @@ -1461,6 +1498,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 e59de5a7..aaef5b4f 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; } @@ -116,9 +118,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 0471ab3a..6e4a89d6 100644 --- a/src/parser.c +++ b/src/parser.c @@ -3824,12 +3824,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_alloc(BB_ARENA, 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 fd025b48..c66a061d 100644 --- a/src/reg-alloc.c +++ b/src/reg-alloc.c @@ -309,6 +309,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")) @@ -480,6 +482,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. @@ -528,6 +534,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 b2262afe..5949bbdf 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -106,6 +106,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; @@ -149,6 +151,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; @@ -222,6 +226,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; @@ -256,6 +262,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; @@ -280,6 +288,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; @@ -340,6 +350,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; @@ -350,6 +362,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; @@ -394,6 +408,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; @@ -435,6 +452,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) @@ -541,6 +560,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; @@ -602,6 +623,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; @@ -786,6 +809,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); @@ -859,6 +884,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; @@ -1161,6 +1188,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); @@ -1190,6 +1219,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); @@ -1540,7 +1571,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) { @@ -1557,6 +1589,8 @@ void optimize(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) { dce_insn(bb); } @@ -1599,6 +1633,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; @@ -1748,6 +1784,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; @@ -1764,6 +1803,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 {