diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a8e2ef9d..40d69e9f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,14 +9,7 @@ jobs: matrix: compiler: [gcc, clang] architecture: [arm, riscv] - link_mode: [static] - include: - - compiler: gcc - architecture: arm - link_mode: dynamic - - compiler: clang - architecture: arm - link_mode: dynamic + link_mode: [static, dynamic] steps: - name: Checkout code uses: actions/checkout@v4 @@ -27,6 +20,9 @@ jobs: sudo apt-get install -q -y qemu-user sudo apt-get install -q -y build-essential sudo apt-get install -q -y gcc-arm-linux-gnueabihf + sudo wget -q https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2026.04.05/riscv32-glibc-ubuntu-24.04-gcc.tar.xz + sudo tar Jxf riscv32-glibc-ubuntu-24.04-gcc.tar.xz -C /opt + echo "/opt/riscv/bin" >> "$GITHUB_PATH" - name: Determine static or dynamic linking mode id: determine-mode run: | diff --git a/Makefile b/Makefile index f79d6650..8e2e8ebf 100644 --- a/Makefile +++ b/Makefile @@ -49,10 +49,6 @@ STAGE0_FLAGS ?= --dump-ir STAGE1_FLAGS ?= DYNLINK ?= 0 ifeq ($(DYNLINK),1) - ifeq ($(ARCH),riscv) - # TODO: implement dynamic linking for RISC-V. - $(error "Dynamic linking mode is not implemented for RISC-V") - endif STAGE0_FLAGS += --dynlink STAGE1_FLAGS += --dynlink endif @@ -108,8 +104,10 @@ check-sanitizer: $(OUT)/$(STAGE0)-sanitizer tests/driver.sh $(Q)rm $(OUT)/shecc check-snapshots: $(OUT)/$(STAGE0) $(SNAPSHOTS) tests/check-snapshots.sh + # static linking $(Q)$(foreach SNAPSHOT_ARCH, $(ARCHS), $(MAKE) distclean config check-snapshot ARCH=$(SNAPSHOT_ARCH) DYNLINK=0 --silent;) - $(Q)$(MAKE) distclean config check-snapshot ARCH=arm DYNLINK=1 --silent + # dynamic linking + $(Q)$(foreach SNAPSHOT_ARCH, $(ARCHS), $(MAKE) distclean config check-snapshot ARCH=$(SNAPSHOT_ARCH) DYNLINK=1 --silent;) $(VECHO) "Switching backend back to %s (DYNLINK=0)\n" arm $(Q)$(MAKE) distclean config ARCH=arm DYNLINK=0 --silent @@ -134,8 +132,10 @@ check-abi-stage2: $(OUT)/$(STAGE2) fi update-snapshots: tests/update-snapshots.sh + # static linking $(Q)$(foreach SNAPSHOT_ARCH, $(ARCHS), $(MAKE) distclean config update-snapshot ARCH=$(SNAPSHOT_ARCH) DYNLINK=0 --silent;) - $(Q)$(MAKE) distclean config update-snapshot ARCH=arm DYNLINK=1 --silent + # dynamic linking + $(Q)$(foreach SNAPSHOT_ARCH, $(ARCHS), $(MAKE) distclean config update-snapshot ARCH=$(SNAPSHOT_ARCH) DYNLINK=1 --silent;) $(VECHO) "Switching backend back to %s (DYNLINK=0)\n" arm $(Q)$(MAKE) distclean config ARCH=arm DYNLINK=0 --silent diff --git a/mk/arm.mk b/mk/arm.mk index 53fe0899..1210ce18 100644 --- a/mk/arm.mk +++ b/mk/arm.mk @@ -16,6 +16,7 @@ ARCH_DEFS = \ \#define LIBC_SO \"libc.so.6\"\n$\ \#define PLT_FIXUP_SIZE 20\n$\ \#define PLT_ENT_SIZE 12\n$\ + \#define RESERVED_GOT_NUM 3\n$\ \#define R_ARCH_JUMP_SLOT 0x16\n$\ \#define MAX_ARGS_IN_REG 4\n$\ " diff --git a/mk/riscv.mk b/mk/riscv.mk index 536d2c0e..9dd55907 100644 --- a/mk/riscv.mk +++ b/mk/riscv.mk @@ -7,13 +7,40 @@ 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 DYN_LINKER \"/lib/ld-linux-riscv32-ilp32d.so.1\"\n$\ \#define LIBC_SO \"libc.so.6\"\n$\ - \#define PLT_FIXUP_SIZE 20\n$\ - \#define PLT_ENT_SIZE 12\n$\ + \#define PLT_FIXUP_SIZE 32\n$\ + \#define PLT_ENT_SIZE 16\n$\ + \#define RESERVED_GOT_NUM 2\n$\ \#define R_ARCH_JUMP_SLOT 0x5\n$\ \#define MAX_ARGS_IN_REG 8\n$\ " -# TODO: Set this variable for RISC-V architecture -RUNNER_LD_PREFIX= +ifeq ($(USE_QEMU),1) + ifeq ($(DYNLINK),1) + CROSS_COMPILE = riscv32-unknown-linux-gnu- + RISCV_CC = $(CROSS_COMPILE)gcc + RISCV_CC := $(shell which $(RISCV_CC)) + ifndef RISCV_CC + $(error "Unable to find ARM GNU toolchain.") + endif + + LD_LINUX_PATH := $(shell cd $(shell $(RISCV_CC) --print-sysroot) 2>/dev/null && pwd) + ifeq ("$(LD_LINUX_PATH)","/") + LD_LINUX_PATH := $(shell dirname "$(shell which $(RISCV_CC))")/.. + LD_LINUX_PATH := $(shell cd $(LD_LINUX_PATH) 2>/dev/null && pwd) + LD_LINUX_PATH := $(LD_LINUX_PATH)/$(shell echo $(CROSS_COMPILE) | sed s'/.$$//')/libc + LD_LINUX_PATH := $(shell cd $(LD_LINUX_PATH) 2>/dev/null && pwd) + ifndef LD_LINUX_PATH + LD_LINUX_PATH = /usr/$(shell echo $(CROSS_COMPILE) | sed s'/.$$//') + LD_LINUX_PATH := $(shell cd $(LD_LINUX_PATH) 2>/dev/null && pwd) + endif + endif + + ifndef LD_LINUX_PATH + $(error "Dynamic linking mode requires ld-linux.so") + endif + + RUNNER_LD_PREFIX = -L $(LD_LINUX_PATH) + endif +endif diff --git a/src/arch-lower.c b/src/arch-lower.c index 1c70e7d2..96f7ea85 100644 --- a/src/arch-lower.c +++ b/src/arch-lower.c @@ -59,9 +59,9 @@ void riscv_lower(void) /* Entry point: dispatch to the active architecture. */ void arch_lower(void) { -#if ELF_MACHINE == 0x28 /* ARM */ +#if ELF_MACHINE == ELF_MACHINE_ARM32 arm_lower(); -#elif ELF_MACHINE == 0xf3 /* RISC-V */ +#elif ELF_MACHINE == ELF_MACHINE_RV32 riscv_lower(); #else /* Unknown architecture: keep behavior as-is. */ diff --git a/src/defs.h b/src/defs.h index b0b79340..d43d39c9 100644 --- a/src/defs.h +++ b/src/defs.h @@ -43,6 +43,7 @@ #define MAX_DYNSYM 1024 #define MAX_DYNSTR 1024 #define MAX_RELPLT 1024 +#define MAX_RELAPLT 1024 #define MAX_PLT 1024 #define MAX_GOTPLT 1024 #define MAX_CONSTANTS 1024 @@ -101,6 +102,9 @@ #define ALIGN_UP(val, align) (((val) + (align) - 1) & ~((align) - 1)) #endif +#define ELF_MACHINE_ARM32 0x28 +#define ELF_MACHINE_RV32 0xf3 + /* Common data structures */ typedef struct arena_block { char *memory; @@ -682,15 +686,28 @@ typedef struct { strbuf_t *elf_dynsym; strbuf_t *elf_dynstr; strbuf_t *elf_relplt; + strbuf_t *elf_relaplt; strbuf_t *elf_plt; strbuf_t *elf_got; int elf_interp_start; int elf_relplt_start; + int elf_relaplt_start; int elf_plt_start; int elf_got_start; int relplt_size; + int relaplt_size; int plt_size; int got_size; + + /* Currently, we don't consider the scenarios involving + * a mixture of REL and RELA relocation entries. + * + * Therefore, use a flag to determine the type of + * relocation entries to be processed: + * - true: use RELA relocation entries + * - false: use REL relocation entries + */ + bool use_relaplt; } dynamic_sections_t; /* For .dynsym section. */ @@ -709,6 +726,12 @@ typedef struct { int r_info; } elf32_rel_t; +typedef struct { + int r_offset; + int r_info; + int r_addend; +} elf32_rela_t; + /* For .dynamic section */ typedef struct { int d_tag; diff --git a/src/elf.c b/src/elf.c index 17e2244a..ac2ff253 100644 --- a/src/elf.c +++ b/src/elf.c @@ -75,17 +75,20 @@ void elf_generate_header(void) * - number of section headers = 15 * - section header index of .shstrtab = 14 */ + int elf_relplt_size = dynamic_sections.use_relaplt + ? dynamic_sections.elf_relaplt->size + : dynamic_sections.elf_relplt->size; phnum = 4; shnum = 15; shstrndx = 14; - shoff = - elf_header_len + elf_code->size + elf_data->size + - elf_rodata->size + elf_symtab->size + elf_strtab->size + - elf_shstrtab->size + dynamic_sections.elf_interp->size + - dynamic_sections.elf_relplt->size + dynamic_sections.elf_plt->size + - dynamic_sections.elf_got->size + dynamic_sections.elf_dynstr->size + - dynamic_sections.elf_dynsym->size + - dynamic_sections.elf_dynamic->size; + shoff = elf_header_len + elf_code->size + elf_data->size + + elf_rodata->size + elf_symtab->size + elf_strtab->size + + elf_shstrtab->size + dynamic_sections.elf_interp->size + + elf_relplt_size + dynamic_sections.elf_plt->size + + dynamic_sections.elf_got->size + + dynamic_sections.elf_dynstr->size + + dynamic_sections.elf_dynsym->size + + dynamic_sections.elf_dynamic->size; } else { /* In static linking mode: * - number of program headers = 2 @@ -187,9 +190,12 @@ void elf_generate_header(void) void elf_generate_program_headers(void) { + strbuf_t *elf_relplt = dynamic_sections.use_relaplt + ? dynamic_sections.elf_relaplt + : dynamic_sections.elf_relplt; if (!elf_program_header || !elf_code || !elf_data || !elf_rodata || (dynlink && - (!dynamic_sections.elf_interp || !dynamic_sections.elf_relplt || + (!dynamic_sections.elf_interp || !elf_relplt || !dynamic_sections.elf_plt || !dynamic_sections.elf_got || !dynamic_sections.elf_dynstr || !dynamic_sections.elf_dynsym || !dynamic_sections.elf_dynamic))) { @@ -232,10 +238,8 @@ void elf_generate_program_headers(void) phdr.p_flags = 5; /* flags */ phdr.p_align = PAGESIZE; /* alignment */ if (dynlink) { - phdr.p_filesz += - dynamic_sections.elf_relplt->size + dynamic_sections.elf_plt->size; - phdr.p_memsz += - dynamic_sections.elf_relplt->size + dynamic_sections.elf_plt->size; + phdr.p_filesz += elf_relplt->size + dynamic_sections.elf_plt->size; + phdr.p_memsz += elf_relplt->size + dynamic_sections.elf_plt->size; } elf_write_blk(elf_program_header, &phdr, sizeof(elf32_phdr_t)); @@ -250,8 +254,7 @@ void elf_generate_program_headers(void) phdr.p_flags = 6; /* flags */ phdr.p_align = PAGESIZE; /* alignment */ if (dynlink) { - phdr.p_offset += - dynamic_sections.elf_relplt->size + dynamic_sections.elf_plt->size; + phdr.p_offset += elf_relplt->size + dynamic_sections.elf_plt->size; phdr.p_vaddr = dynamic_sections.elf_interp_start; phdr.p_paddr = dynamic_sections.elf_interp_start; phdr.p_filesz += dynamic_sections.elf_interp->size + @@ -272,7 +275,7 @@ 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_rodata->size + - dynamic_sections.elf_relplt->size + + elf_relplt->size + dynamic_sections.elf_plt->size; /* offset of segment */ phdr.p_vaddr = dynamic_sections.elf_interp_start; /* virtual address */ phdr.p_paddr = dynamic_sections.elf_interp_start; /* physical address */ @@ -286,7 +289,7 @@ void elf_generate_program_headers(void) phdr.p_type = 2; /* PT_DYNAMIC */ phdr.p_offset = elf_header_len + elf_code->size + elf_rodata->size + - dynamic_sections.elf_relplt->size + dynamic_sections.elf_plt->size + + elf_relplt->size + dynamic_sections.elf_plt->size + dynamic_sections.elf_interp->size + dynamic_sections.elf_got->size + dynamic_sections.elf_dynstr->size + dynamic_sections.elf_dynsym->size; /* offset of segment */ @@ -308,11 +311,14 @@ void elf_generate_program_headers(void) void elf_generate_section_headers(void) { + strbuf_t *elf_relplt = dynamic_sections.use_relaplt + ? dynamic_sections.elf_relaplt + : dynamic_sections.elf_relplt; /* Check for null pointers to prevent crashes */ if (!elf_section_header || !elf_code || !elf_data || !elf_rodata || !elf_symtab || !elf_strtab || !elf_shstrtab || (dynlink && - (!dynamic_sections.elf_interp || !dynamic_sections.elf_relplt || + (!dynamic_sections.elf_interp || !elf_relplt || !dynamic_sections.elf_plt || !dynamic_sections.elf_got || !dynamic_sections.elf_dynstr || !dynamic_sections.elf_dynsym || !dynamic_sections.elf_dynamic))) { @@ -396,20 +402,37 @@ void elf_generate_section_headers(void) sh_name += strlen(".rodata") + 1; if (dynlink) { - /* .rel.plt */ + /* .rel.plt or .rela.plt */ + int sh_type, sh_addr, sh_size, sh_entsize, __ofs, __sh_name; + + if (dynamic_sections.use_relaplt) { + sh_type = 4; /* SHT_RELA */ + sh_addr = dynamic_sections.elf_relaplt_start; + sh_size = dynamic_sections.elf_relaplt->size; + sh_entsize = sizeof(elf32_rela_t); + __ofs = dynamic_sections.elf_relaplt->size; + __sh_name = strlen(".rela.plt") + 1; + } else { + sh_type = 9; /* SHT_REL */ + sh_addr = dynamic_sections.elf_relplt_start; + sh_size = dynamic_sections.elf_relplt->size; + sh_entsize = sizeof(elf32_rel_t); + __ofs = dynamic_sections.elf_relplt->size; + __sh_name = strlen(".rel.plt") + 1; + } shdr.sh_name = sh_name; - shdr.sh_type = 9; /* SHT_REL */ + shdr.sh_type = sh_type; shdr.sh_flags = 0x42; /* 0x40 | SHF_ALLOC */ - shdr.sh_addr = dynamic_sections.elf_relplt_start; + shdr.sh_addr = sh_addr; shdr.sh_offset = ofs; - shdr.sh_size = dynamic_sections.elf_relplt->size; + shdr.sh_size = sh_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); + shdr.sh_entsize = sh_entsize; elf_write_blk(elf_section_header, &shdr, sizeof(elf32_shdr_t)); - ofs += dynamic_sections.elf_relplt->size; - sh_name += strlen(".rel.plt") + 1; + ofs += __ofs; + sh_name += __sh_name; /* .plt */ shdr.sh_name = sh_name; @@ -597,9 +620,12 @@ void elf_align(strbuf_t *elf_array) void elf_generate_sections(void) { + strbuf_t *elf_relplt = dynamic_sections.use_relaplt + ? dynamic_sections.elf_relaplt + : dynamic_sections.elf_relplt; if (!elf_shstrtab || (dynlink && - (!dynamic_sections.elf_interp || !dynamic_sections.elf_relplt || + (!dynamic_sections.elf_interp || !elf_relplt || !dynamic_sections.elf_plt || !dynamic_sections.elf_got || !dynamic_sections.elf_dynstr || !dynamic_sections.elf_dynsym || !dynamic_sections.elf_dynamic))) { @@ -609,21 +635,20 @@ void elf_generate_sections(void) if (dynlink) { /* In dynamic linking mode, elf_generate_sections() also generates - * .interp, .dynsym, .dynstr, .relplt, .got and dynamic sections. + * .interp, .dynsym, .dynstr, .rel.plt (.rela.plt), .got and dynamic + * sections. * * .plt section is generated at the code generation phase. - * - * TODO: - * Define a new structure named 'elf32_rela_t' and use it to generate - * relocation entries for RISC-V architecture. */ elf32_sym_t sym; elf32_dyn_t dyn; elf32_rel_t rel; + elf32_rela_t rela; int dymsym_idx = 1, func_plt_ofs, func_got_ofs, st_name = 0; memset(&sym, 0, sizeof(elf32_sym_t)); memset(&dyn, 0, sizeof(elf32_dyn_t)); memset(&rel, 0, sizeof(elf32_rel_t)); + memset(&rela, 0, sizeof(elf32_rela_t)); /* .interp section */ elf_write_str(dynamic_sections.elf_interp, DYN_LINKER); @@ -651,9 +676,20 @@ void elf_generate_sections(void) * Since __libc_start_main is not added to the function list, * it must be handled additionally first. */ - rel.r_offset = dynamic_sections.elf_got_start + PTR_SIZE * 3; - rel.r_info = (dymsym_idx << 8) | R_ARCH_JUMP_SLOT; - elf_write_blk(dynamic_sections.elf_relplt, &rel, sizeof(elf32_rel_t)); + if (dynamic_sections.use_relaplt) { + rela.r_offset = + dynamic_sections.elf_got_start + PTR_SIZE * RESERVED_GOT_NUM; + rela.r_info = (dymsym_idx << 8) | R_ARCH_JUMP_SLOT; + rela.r_addend = 0; + elf_write_blk(dynamic_sections.elf_relaplt, &rela, + sizeof(elf32_rela_t)); + } else { + rel.r_offset = + dynamic_sections.elf_got_start + PTR_SIZE * RESERVED_GOT_NUM; + rel.r_info = (dymsym_idx << 8) | R_ARCH_JUMP_SLOT; + elf_write_blk(dynamic_sections.elf_relplt, &rel, + sizeof(elf32_rel_t)); + } sym.st_name = st_name; sym.st_info = ELF32_ST_INFO(1, 2); /* STB_GLOBAL = 1, STT_FUNC = 2 */ @@ -664,58 +700,80 @@ void elf_generate_sections(void) elf_write_byte(dynamic_sections.elf_dynstr, 0); st_name += strlen("__libc_start_main") + 1; - /* Because PLT[1] and GOT[3] are reserved for __libc_start_main, - * its plt_offset and got_offset must be PLT_FIXUP_SIZE and - * PTR_SIZE * 3, respectively. Therefore, no offset assignment is - * required for this function. + /* Because PLT[1] and GOT[RESERVED_GOT_NUM] are reserved for + * __libc_start_main, its plt_offset and got_offset must be + * PLT_FIXUP_SIZE and PTR_SIZE * RESERVED_GOT_NUM, respectively. + * Therefore, no offset assignment is required for this function. */ 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) { + if (!func->is_used || func->bbs) + continue; + /* If the function is used and has no basic block, + * consider it to be an external function. + */ + + if (dynamic_sections.use_relaplt) { + rela.r_offset += PTR_SIZE; + rela.r_info = (dymsym_idx << 8) | R_ARCH_JUMP_SLOT; + rela.r_addend = 0; + elf_write_blk(dynamic_sections.elf_relaplt, &rela, + sizeof(elf32_rela_t)); + } else { rel.r_offset += PTR_SIZE; rel.r_info = (dymsym_idx << 8) | R_ARCH_JUMP_SLOT; elf_write_blk(dynamic_sections.elf_relplt, &rel, sizeof(elf32_rel_t)); + } - sym.st_name = st_name; - sym.st_info = - ELF32_ST_INFO(1, 2); /* STB_GLOBAL = 1, STT_FUNC = 2 */ - elf_write_blk(dynamic_sections.elf_dynsym, &sym, - sizeof(elf32_sym_t)); - dymsym_idx += 1; + sym.st_name = st_name; + sym.st_info = + ELF32_ST_INFO(1, 2); /* STB_GLOBAL = 1, STT_FUNC = 2 */ + elf_write_blk(dynamic_sections.elf_dynsym, &sym, + sizeof(elf32_sym_t)); + dymsym_idx += 1; - elf_write_str(dynamic_sections.elf_dynstr, - func->return_def.var_name); - elf_write_byte(dynamic_sections.elf_dynstr, 0); - st_name += strlen(func->return_def.var_name) + 1; + elf_write_str(dynamic_sections.elf_dynstr, + func->return_def.var_name); + elf_write_byte(dynamic_sections.elf_dynstr, 0); + st_name += strlen(func->return_def.var_name) + 1; - func->plt_offset = func_plt_ofs; - func->got_offset = func_got_ofs; + func->plt_offset = func_plt_ofs; + func->got_offset = func_got_ofs; - func_plt_ofs += PLT_ENT_SIZE; - func_got_ofs += PTR_SIZE; - } + func_plt_ofs += PLT_ENT_SIZE; + func_got_ofs += PTR_SIZE; } /* Ensure proper alignment for .dynstr section. */ elf_align(dynamic_sections.elf_dynstr); /* .got section * - * - GOT[0] holds the virtual address of .dynamic section. - * - GOT[1] and GOT[2] are reserved for link_map and resolver, - * and are initialized to 0. + * - Arm architecture: + * - GOT[0] holds the virtual address of .dynamic section. + * - GOT[1] and GOT[2] are reserved for link_map and resolver, + * and are initialized to 0. + * - RISC-V architecture: + * - GOT[0] and GOT[1] are reserved for link_map and resolver, + * and are initialized to 0. * - The remaining entries are initialized to &PLT[0]. */ - elf_write_int(dynamic_sections.elf_got, - dynamic_sections.elf_got_start + - dynamic_sections.got_size + - dynamic_sections.elf_dynstr->size + - dynamic_sections.elf_dynsym->size); - elf_write_int(dynamic_sections.elf_got, 0); - elf_write_int(dynamic_sections.elf_got, 0); - for (int i = PTR_SIZE * 3; i < dynamic_sections.got_size; i += PTR_SIZE) + switch (ELF_MACHINE) { + case ELF_MACHINE_ARM32: + elf_write_int(dynamic_sections.elf_got, + dynamic_sections.elf_got_start + + dynamic_sections.got_size + + dynamic_sections.elf_dynstr->size + + dynamic_sections.elf_dynsym->size); + case ELF_MACHINE_RV32: + elf_write_int(dynamic_sections.elf_got, 0); + elf_write_int(dynamic_sections.elf_got, 0); + break; + } + for (int i = PTR_SIZE * RESERVED_GOT_NUM; i < dynamic_sections.got_size; + i += PTR_SIZE) elf_write_int(dynamic_sections.elf_got, dynamic_sections.elf_plt_start); @@ -740,37 +798,79 @@ void elf_generate_sections(void) dyn.d_un = sizeof(elf32_sym_t); /* Size of an entry. */ elf_write_blk(dynamic_sections.elf_dynamic, &dyn, sizeof(elf32_dyn_t)); - dyn.d_tag = 0x11; /* REL */ - dyn.d_un = dynamic_sections - .elf_relplt_start; /* The virtual address of .rel.plt. */ - elf_write_blk(dynamic_sections.elf_dynamic, &dyn, sizeof(elf32_dyn_t)); - - dyn.d_tag = 0x12; /* RELSZ */ - dyn.d_un = dynamic_sections.relplt_size; - elf_write_blk(dynamic_sections.elf_dynamic, &dyn, sizeof(elf32_dyn_t)); - - dyn.d_tag = 0x13; /* RELENT */ - dyn.d_un = sizeof(elf32_rel_t); - elf_write_blk(dynamic_sections.elf_dynamic, &dyn, sizeof(elf32_dyn_t)); + if (dynamic_sections.use_relaplt) { + dyn.d_tag = 0x7; /* RELA */ + dyn.d_un = + dynamic_sections + .elf_relaplt_start; /* The virtual address of .rela.plt. */ + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x8; /* RELASZ */ + dyn.d_un = dynamic_sections.relaplt_size; + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x9; /* RELAENT */ + dyn.d_un = sizeof(elf32_rela_t); + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x2; /* PLTRELSZ */ + dyn.d_un = dynamic_sections.relaplt_size; + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x14; /* PLTREL */ + dyn.d_un = 0x7; + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + /* The virtual address of .rela.plt. */ + dyn.d_tag = 0x17; /* JMPREL */ + dyn.d_un = dynamic_sections.elf_relaplt_start; + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + } else { + dyn.d_tag = 0x11; /* REL */ + dyn.d_un = + dynamic_sections + .elf_relplt_start; /* The virtual address of .rel.plt. */ + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x12; /* RELSZ */ + dyn.d_un = dynamic_sections.relplt_size; + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x13; /* RELENT */ + dyn.d_un = sizeof(elf32_rel_t); + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x2; /* PLTRELSZ */ + dyn.d_un = dynamic_sections.relplt_size; + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + dyn.d_tag = 0x14; /* PLTREL */ + dyn.d_un = 0x11; + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + + /* The virtual address of .rel.plt. */ + dyn.d_tag = 0x17; /* JMPREL */ + dyn.d_un = dynamic_sections.elf_relplt_start; + elf_write_blk(dynamic_sections.elf_dynamic, &dyn, + sizeof(elf32_dyn_t)); + } dyn.d_tag = 0x3; /* PLTGOT */ dyn.d_un = dynamic_sections.elf_got_start; /* The virtual address of .got.*/ elf_write_blk(dynamic_sections.elf_dynamic, &dyn, sizeof(elf32_dyn_t)); - dyn.d_tag = 0x2; /* PLTRELSZ */ - dyn.d_un = dynamic_sections.relplt_size; - elf_write_blk(dynamic_sections.elf_dynamic, &dyn, sizeof(elf32_dyn_t)); - - dyn.d_tag = 0x14; /* PLTREL */ - dyn.d_un = 0x11; - elf_write_blk(dynamic_sections.elf_dynamic, &dyn, sizeof(elf32_dyn_t)); - - dyn.d_tag = 0x17; /* JMPREL */ - dyn.d_un = dynamic_sections - .elf_relplt_start; /* The virtual address of .rel.plt. */ - elf_write_blk(dynamic_sections.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(dynamic_sections.elf_dynamic, &dyn, sizeof(elf32_dyn_t)); @@ -789,7 +889,10 @@ void elf_generate_sections(void) elf_write_str(elf_shstrtab, ".rodata"); elf_write_byte(elf_shstrtab, 0); if (dynlink) { - elf_write_str(elf_shstrtab, ".rel.plt"); + if (dynamic_sections.use_relaplt) + elf_write_str(elf_shstrtab, ".rela.plt"); + else + elf_write_str(elf_shstrtab, ".rel.plt"); elf_write_byte(elf_shstrtab, 0); elf_write_str(elf_shstrtab, ".plt"); elf_write_byte(elf_shstrtab, 0); @@ -844,47 +947,67 @@ void elf_preprocess(void) elf_code_start = ELF_START + elf_header_len; elf_rodata_start = elf_code_start + elf_offset; if (dynlink) { - /* Precalculate the sizes of .rel.plt, .plt and .got sections. + /* Precalculate the sizes of .rel.plt (.rela.plt), .plt and .got + * sections. * * Suppose the compiled program has n external functions: - * - .rel.plt contains n entries. + * - .rel.plt (.rela.plt) contains n entries. * - .plt has n entries plus one fixup entry. - * - .got includes n + 3 entries - * - GOT[0] holds the virtual address of .dynamic section. - * - GOT[1] and GOT[2] are reserved for link_map and resolver - * (both set to 0). - * - The remaining entries correspond to all external functions. + * - .got includes n + RESERVED_GOT_NUM entries + * - Arm architecture: + * - GOT[0] holds the virtual address of .dynamic section. + * - GOT[1] and GOT[2] are reserved for link_map and resolver + * (both set to 0). + * - RISC-V architecture: + * - GOT[0] and GOT[1] are reserved for resolver and link_map. + * - Common: + * - The remaining entries correspond to all external functions. * * Next, consider the case of __libc_start_main before initializing * the sizes: - * - .rel.plt has the one entry for __libc_start_main. + * - .rel.plt (.rela.plt) has the one entry for __libc_start_main. * - .plt includes one fixup entry plus one entry for __libc_start_main. - * - .got has 3 + 1 entries. - * - 3 entries for GOT[0] - GOT[2]. - * - 1 entry (GOT[3]) reserved for __libc_start_main. + * - .got has RESERVED_GOT_NUM + 1 entries. + * - RESERVED_GOT_NUM entries for GOT[0] - GOT[RESERVED_GOT_NUM - 1]. + * - 1 entry (GOT[RESERVED_GOT_NUM]) reserved for __libc_start_main. * * Therefore, the following code initialize the section sizes based on * the layout described above, and then traverse the function list in a * for loop to increment the sizes for each newly found external * function. */ - dynamic_sections.relplt_size = sizeof(elf32_rel_t); + if (dynamic_sections.use_relaplt) + dynamic_sections.relaplt_size = sizeof(elf32_rela_t); + else + dynamic_sections.relplt_size = sizeof(elf32_rel_t); dynamic_sections.plt_size = PLT_FIXUP_SIZE + PLT_ENT_SIZE; - dynamic_sections.got_size = PTR_SIZE * 3 + PTR_SIZE; + dynamic_sections.got_size = PTR_SIZE * RESERVED_GOT_NUM + PTR_SIZE; for (func_t *func = FUNC_LIST.head; func; func = func->next) { - if (func->is_used && !func->bbs) { + if (!func->is_used || func->bbs) + continue; + if (dynamic_sections.use_relaplt) + dynamic_sections.relaplt_size += sizeof(elf32_rela_t); + else dynamic_sections.relplt_size += sizeof(elf32_rel_t); - dynamic_sections.plt_size += PLT_ENT_SIZE; - dynamic_sections.got_size += PTR_SIZE; - } + dynamic_sections.plt_size += PLT_ENT_SIZE; + dynamic_sections.got_size += PTR_SIZE; } /* Set the starting addresses of the three sections. */ int elf_interp_size = strlen(DYN_LINKER) + 1; elf_interp_size = ALIGN_UP(elf_interp_size, 4); - dynamic_sections.elf_relplt_start = elf_rodata_start + elf_rodata->size; - dynamic_sections.elf_plt_start = - dynamic_sections.elf_relplt_start + dynamic_sections.relplt_size; + if (dynamic_sections.use_relaplt) { + dynamic_sections.elf_relaplt_start = + elf_rodata_start + elf_rodata->size; + dynamic_sections.elf_plt_start = + dynamic_sections.elf_relaplt_start + + dynamic_sections.relaplt_size; + } else { + dynamic_sections.elf_relplt_start = + elf_rodata_start + elf_rodata->size; + dynamic_sections.elf_plt_start = dynamic_sections.elf_relplt_start + + dynamic_sections.relplt_size; + } /* Since the first section of the second load segment is .interp * when using dynamic linking mode, adding PAGESIZE to elf_interp_start * is to ensure that two load segments don't share a common page. @@ -944,8 +1067,13 @@ void elf_generate(const char *outfile) if (dynlink) { /* Read-only sections */ - for (int i = 0; i < dynamic_sections.elf_relplt->size; i++) - fputc(dynamic_sections.elf_relplt->elements[i], fp); + if (dynamic_sections.use_relaplt) + for (int i = 0; i < dynamic_sections.elf_relaplt->size; i++) + fputc(dynamic_sections.elf_relaplt->elements[i], fp); + else { + for (int i = 0; i < dynamic_sections.elf_relplt->size; i++) + fputc(dynamic_sections.elf_relplt->elements[i], fp); + } for (int i = 0; i < dynamic_sections.elf_plt->size; i++) fputc(dynamic_sections.elf_plt->elements[i], fp); /* Readable and writable sections */ diff --git a/src/globals.c b/src/globals.c index f284d24c..98cfeb36 100644 --- a/src/globals.c +++ b/src/globals.c @@ -1308,11 +1308,23 @@ void global_init(void) elf_bss_size = 0; elf_shstrtab = strbuf_create(MAX_SHSTR); elf_section_header = strbuf_create(MAX_SECTION_HEADER); + + switch (ELF_MACHINE) { + case ELF_MACHINE_ARM32: + dynamic_sections.use_relaplt = false; + break; + case ELF_MACHINE_RV32: + dynamic_sections.use_relaplt = true; + break; + } dynamic_sections.elf_interp = strbuf_create(MAX_INTERP); dynamic_sections.elf_dynamic = strbuf_create(MAX_DYNAMIC); dynamic_sections.elf_dynsym = strbuf_create(MAX_DYNSYM); dynamic_sections.elf_dynstr = strbuf_create(MAX_DYNSTR); - dynamic_sections.elf_relplt = strbuf_create(MAX_RELPLT); + if (dynamic_sections.use_relaplt) + dynamic_sections.elf_relaplt = strbuf_create(MAX_RELAPLT); + else + dynamic_sections.elf_relplt = strbuf_create(MAX_RELPLT); dynamic_sections.elf_plt = strbuf_create(MAX_PLT); dynamic_sections.elf_got = strbuf_create(MAX_GOTPLT); } @@ -1449,7 +1461,10 @@ void global_release(void) strbuf_free(dynamic_sections.elf_dynamic); strbuf_free(dynamic_sections.elf_dynsym); strbuf_free(dynamic_sections.elf_dynstr); - strbuf_free(dynamic_sections.elf_relplt); + if (dynamic_sections.use_relaplt) + strbuf_free(dynamic_sections.elf_relaplt); + else + strbuf_free(dynamic_sections.elf_relplt); strbuf_free(dynamic_sections.elf_plt); strbuf_free(dynamic_sections.elf_got); } diff --git a/src/riscv-codegen.c b/src/riscv-codegen.c index ee641b60..213c1b81 100644 --- a/src/riscv-codegen.c +++ b/src/riscv-codegen.c @@ -10,6 +10,8 @@ #include "globals.c" #include "riscv.c" +#define RV32_ALIGNMENT 16 + void update_elf_offset(ph2_ir_t *ph2_ir) { switch (ph2_ir->op) { @@ -118,12 +120,19 @@ void update_elf_offset(ph2_ir_t *ph2_ir) void cfg_flatten(void) { - func_t *func = find_func("__syscall"); - /* Prologue ~ 6 instructions (24 bytes). Place __syscall right after. */ - func->bbs->elf_offset = 24; + func_t *func; + + if (dynlink) + elf_offset = 68; + else { + func = find_func("__syscall"); + /* Prologue ~ 6 instructions (24 bytes). Place __syscall right after. */ + func->bbs->elf_offset = 24; + /* Reserve space for prologue (24) + syscall trampoline (36) = 60 bytes. + */ + elf_offset = 60; + } - /* Reserve space for prologue (24) + syscall trampoline (36) = 60 bytes. */ - elf_offset = 60; GLOBAL_FUNC->bbs->elf_offset = elf_offset; for (ph2_ir_t *ph2_ir = GLOBAL_FUNC->bbs->ph2_ir_list.head; ph2_ir; @@ -132,7 +141,10 @@ void cfg_flatten(void) } /* prepare 'argc' and 'argv', then proceed to 'main' function */ - elf_offset += 24; + if (dynlink) + elf_offset += 32; + else + elf_offset += 24; for (func = FUNC_LIST.head; func; func = func->next) { /* Skip function declarations without bodies */ @@ -144,6 +156,14 @@ void cfg_flatten(void) flatten_ir->src0 = func->stack_size; strncpy(flatten_ir->func_name, func->return_def.var_name, MAX_VAR_LEN); + /* Except for local variables, it must allocate additional space + * to preserve the content of ra at each function entry point. + * + * 'stack_size' doesn't include the additional space, so an extra + * number '4' is added to 'stack_size'. + */ + int stack_top_ofs = ALIGN_UP(func->stack_size + 4, RV32_ALIGNMENT); + for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) { bb->elf_offset = elf_offset; @@ -154,9 +174,23 @@ void cfg_flatten(void) for (ph2_ir_t *insn = bb->ph2_ir_list.head; insn; insn = insn->next) { - /* TODO: recalculate the offset for instructions with the - * 'ofs_based_on_stack_top' flag set. - */ + if (insn->ofs_based_on_stack_top) { + switch (insn->op) { + case OP_load: + case OP_address_of: + insn->src0 = insn->src0 + stack_top_ofs; + break; + case OP_store: + insn->src1 = insn->src1 + stack_top_ofs; + break; + default: + /* Ignore opcodes with the ofs_based_on_stack_top + * flag set since only the three opcodes above needs + * to access a variable's address. + */ + break; + } + } flatten_ir = add_existed_ph2_ir(insn); if (insn->op == OP_return) { @@ -193,9 +227,10 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) switch (ph2_ir->op) { case OP_define: + ofs = ALIGN_UP(ph2_ir->src0 + 4, RV32_ALIGNMENT); emit(__sw(__ra, __sp, -4)); - emit(__lui(__t0, rv_hi(ph2_ir->src0 + 4))); - emit(__addi(__t0, __t0, rv_lo(ph2_ir->src0 + 4))); + emit(__lui(__t0, rv_hi(ofs))); + emit(__addi(__t0, __t0, rv_lo(ofs))); emit(__sub(__sp, __sp, __t0)); return; case OP_load_constant: @@ -274,7 +309,16 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) return; case OP_call: func = find_func(ph2_ir->func_name); - emit(__jal(__ra, func->bbs->elf_offset - elf_code->size)); + if (func->bbs) + ofs = func->bbs->elf_offset - elf_code->size; + else if (dynlink) { + ofs = (dynamic_sections.elf_plt_start + func->plt_offset) - + (elf_code_start + elf_code->size); + } else { + printf("The '%s' function is not implemented\n", ph2_ir->func_name); + abort(); + } + emit(__jal(__ra, ofs)); return; case OP_load_data_address: emit(__lui(rd, rv_hi(elf_data_start + ph2_ir->src0))); @@ -286,7 +330,14 @@ 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 if (dynlink) + ofs = dynamic_sections.elf_plt_start + func->plt_offset; + else { + printf("The '%s' function is not implemented\n", ph2_ir->func_name); + abort(); + } emit(__lui(__t0, rv_hi(ofs))); emit(__addi(__t0, __t0, rv_lo(ofs))); emit(__sw(__t0, rs1, 0)); @@ -302,8 +353,9 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) emit(__addi(__zero, __zero, 0)); else emit(__addi(__a0, rs1, 0)); - emit(__lui(__t0, rv_hi(ph2_ir->src1 + 4))); - emit(__addi(__t0, __t0, rv_lo(ph2_ir->src1 + 4))); + ofs = ALIGN_UP(ph2_ir->src1 + 4, RV32_ALIGNMENT); + emit(__lui(__t0, rv_hi(ofs))); + emit(__addi(__t0, __t0, rv_lo(ofs))); emit(__add(__sp, __sp, __t0)); emit(__lw(__ra, __sp, -4)); emit(__jalr(__zero, __ra, 0)); @@ -482,26 +534,100 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) } } +void plt_generate(void); void code_generate(void) { - /* 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))); - emit(__addi(__t0, __t0, rv_lo(GLOBAL_FUNC->stack_size))); + int ofs; + + if (dynlink) { + plt_generate(); + /* - Initial stack layout when the program starts: + * + * +----------------+ (high address) + * | ... | + * +----------------+ + * | argv[argc - 1] | + * +----------------+ + * | ... | + * +----------------+ + * | argv[0] | + * +----------------+ + * | argc | + * +----------------+ <- sp points to this location. + * + * - At the program entry point, it must call __libc_start_main() + * under dynamic linking. The function prototype is as follows: + * + * int __libc_start_main(int (*main) (int, char **, char **), + * int argc, char **argv, + * void (*init) (void), + * void (*fini) (void), + * void (*rtld_fini) (void), + * void (*stack_end)); + * + * Currently, to execute a dynamically linked program with the + * minimal effort required, we perform the following call: + * -> __libc_start_main(main_wrapper, argc, argv, NULL, + * NULL, NULL, stack_end) + */ + emit(__lui(__a0, rv_hi(elf_code_start + 36))); + emit(__addi(__a0, __a0, rv_lo(elf_code_start + 36))); + emit(__lw(__a1, __sp, 0)); + emit(__addi(__a2, __sp, 4)); + emit(__addi(__a3, __zero, 0)); + emit(__addi(__a4, __zero, 0)); + emit(__addi(__a5, __zero, 0)); + emit(__addi(__a6, __sp, 0)); + + /* Call __libc_start_main() via PLT[1] */ + ofs = (dynamic_sections.elf_plt_start + PLT_FIXUP_SIZE) - + (elf_code_start + elf_code->size); + emit(__jal(__ra, ofs)); + + /* The main wrapper is located here under the dynamic linking mode + * + * Use t1 and t2 registers to temporarily store 'argc' and 'argv', + * while preserving ra on the stack. + * + * After the main function completes its execution, it must use + * the content of ra to transfer control back to __libc_start_main(). + */ + emit(__addi(__t1, __a0, 0)); + emit(__addi(__t2, __a1, 0)); + emit(__sw(__ra, __sp, -4)); + ofs = ALIGN_UP(GLOBAL_FUNC->stack_size + 4, RV32_ALIGNMENT); + } else { + /* When using static linking, the starting address + * of the main wrapper is here. + * + * Save original sp in s0 first. + */ + ofs = ALIGN_UP(GLOBAL_FUNC->stack_size, RV32_ALIGNMENT); + emit(__addi(__s0, __sp, 0)); + } + /* Next, the main wrapper performs: + * 1. allocate global stack + * 2. run init + * 3. call the main function + */ + emit(__lui(__t0, rv_hi(ofs))); + emit(__addi(__t0, __t0, rv_lo(ofs))); emit(__sub(__sp, __sp, __t0)); emit(__addi(__gp, __sp, 0)); /* Set up global pointer */ emit(__jal(__ra, GLOBAL_FUNC->bbs->elf_offset - elf_code->size)); - /* syscall trampoline for __syscall - must be at offset 24 */ - emit(__addi(__a7, __a0, 0)); - emit(__addi(__a0, __a1, 0)); - emit(__addi(__a1, __a2, 0)); - emit(__addi(__a2, __a3, 0)); - emit(__addi(__a3, __a4, 0)); - emit(__addi(__a4, __a5, 0)); - emit(__addi(__a5, __a6, 0)); - emit(__ecall()); - emit(__jalr(__zero, __ra, 0)); + if (!dynlink) { + /* syscall trampoline for __syscall */ + emit(__addi(__a7, __a0, 0)); + emit(__addi(__a0, __a1, 0)); + emit(__addi(__a1, __a2, 0)); + emit(__addi(__a2, __a3, 0)); + emit(__addi(__a3, __a4, 0)); + emit(__addi(__a4, __a5, 0)); + emit(__addi(__a5, __a6, 0)); + emit(__ecall()); + emit(__jalr(__zero, __ra, 0)); + } ph2_ir_t *ph2_ir; for (ph2_ir = GLOBAL_FUNC->bbs->ph2_ir_list.head; ph2_ir; @@ -509,16 +635,31 @@ void code_generate(void) emit_ph2_ir(ph2_ir); /* prepare 'argc' and 'argv', then proceed to 'main' function */ - /* use original sp saved in s0 to get argc/argv */ if (MAIN_BB) { - emit(__addi(__t0, __s0, 0)); - emit(__lw(__a0, __t0, 0)); - emit(__addi(__a1, __t0, 4)); - emit(__jal(__ra, MAIN_BB->elf_offset - elf_code->size)); + if (dynlink) { + emit(__addi(__a0, __t1, 0)); + emit(__addi(__a1, __t2, 0)); + emit(__jal(__ra, MAIN_BB->elf_offset - elf_code->size)); - /* exit with main's return value in a0 */ - emit(__addi(__a7, __zero, 93)); - emit(__ecall()); + /* Restore sp and transfer control back to __libc_start_main() + * using the preserved ra. + */ + emit(__lui(__t0, rv_hi(ofs))); + emit(__addi(__t0, __t0, rv_lo(ofs))); + emit(__add(__sp, __sp, __t0)); + emit(__lw(__ra, __sp, -4)); + emit(__jalr(__zero, __ra, 0)); + } else { + /* use original sp saved in s0 to get argc/argv */ + emit(__addi(__t0, __s0, 0)); + emit(__lw(__a0, __t0, 0)); + emit(__addi(__a1, __t0, 4)); + emit(__jal(__ra, MAIN_BB->elf_offset - elf_code->size)); + + /* exit with main's return value in a0 */ + emit(__addi(__a7, __zero, 93)); + emit(__ecall()); + } } for (int i = 0; i < ph2_ir_idx; i++) { @@ -526,3 +667,63 @@ void code_generate(void) emit_ph2_ir(ph2_ir); } } + +void plt_generate() +{ + int addr_of_plt = dynamic_sections.elf_plt_start; + int addr_of_got = dynamic_sections.elf_got_start; + int end = dynamic_sections.plt_size - PLT_FIXUP_SIZE; + int ofs, pcrel_hi, pcrel_lo; + + ofs = addr_of_got - addr_of_plt; + pcrel_hi = ofs & ~0xFFF; + pcrel_lo = ofs & 0xFFF; + if (pcrel_lo > 2047) { + pcrel_hi += 1; + pcrel_lo -= 0x1000; + } + + /* t0 -> link map (GOT[1]) + * t1 -> .got offset + * t2 -> %pcrel_hi(.got.plt) (but it is unused) + * t3 -> _dl_runtime_resolve (GOT[0]) + */ + elf_write_int(dynamic_sections.elf_plt, __auipc(__t2, pcrel_hi)); + elf_write_int(dynamic_sections.elf_plt, __sub(__t1, __t1, __t3)); + elf_write_int(dynamic_sections.elf_plt, __lw(__t3, __t2, pcrel_lo)); + elf_write_int(dynamic_sections.elf_plt, __addi(__t1, __t1, -44)); + elf_write_int(dynamic_sections.elf_plt, __addi(__t0, __t2, pcrel_lo)); + elf_write_int(dynamic_sections.elf_plt, __srli(__t1, __t1, 2)); + elf_write_int(dynamic_sections.elf_plt, __lw(__t0, __t0, 4)); + elf_write_int(dynamic_sections.elf_plt, __jalr(__zero, __t3, 0)); + for (int i = 0; i * PLT_ENT_SIZE < end; i++) { + /* elf_generate() ensures that the .got section is placed + * a higher memory address than the plt section. + * + * Consequently, 'ofs' must always be positive. + * + * t1 = &PLT[N] + 12 (address of the 'nop' instruction) + * + * First call: + * t3 = &PLT[0] + * + * Subsequent calls: + * t3 = Address of the function + */ + addr_of_plt = + dynamic_sections.elf_plt_start + PLT_FIXUP_SIZE + PLT_ENT_SIZE * i; + addr_of_got = dynamic_sections.elf_got_start + PTR_SIZE * (i + 2); + ofs = addr_of_got - addr_of_plt; + pcrel_hi = ofs & ~0xFFF; + pcrel_lo = ofs & 0xFFF; + if (pcrel_lo > 2047) { + pcrel_hi += 1; + pcrel_lo -= 0x1000; + } + + elf_write_int(dynamic_sections.elf_plt, __auipc(__t3, pcrel_hi)); + elf_write_int(dynamic_sections.elf_plt, __lw(__t3, __t3, pcrel_lo)); + elf_write_int(dynamic_sections.elf_plt, __jalr(__t1, __t3, 0)); + elf_write_int(dynamic_sections.elf_plt, __addi(__zero, __zero, 0)); + } +} diff --git a/tests/snapshots/fib-riscv-dynamic.json b/tests/snapshots/fib-riscv-dynamic.json new file mode 100644 index 00000000..34eede5f --- /dev/null +++ b/tests/snapshots/fib-riscv-dynamic.json @@ -0,0 +1 @@ +{"_subgraph_cnt":13,"directed":true,"edges":[{"_gvid":0,"head":14,"headport":"n","tail":13,"tailport":"s"},{"_gvid":1,"head":15,"tail":14,"weight":"100"},{"_gvid":2,"head":16,"tail":15,"weight":"100"},{"_gvid":3,"head":17,"headport":"n","tail":16,"tailport":"sw"},{"_gvid":4,"head":22,"headport":"n","tail":16,"tailport":"se"},{"_gvid":5,"head":18,"tail":17,"weight":"100"},{"_gvid":6,"head":19,"headport":"n","tail":18,"tailport":"s"},{"_gvid":7,"head":19,"headport":"n","tail":20,"tailport":"s"},{"_gvid":8,"head":19,"headport":"n","tail":21,"tailport":"s"},{"_gvid":9,"head":23,"headport":"n","tail":22,"tailport":"s"},{"_gvid":10,"head":24,"tail":23,"weight":"100"},{"_gvid":11,"head":25,"tail":24,"weight":"100"},{"_gvid":12,"head":26,"headport":"n","tail":25,"tailport":"sw"},{"_gvid":13,"head":27,"headport":"n","tail":25,"tailport":"se"},{"_gvid":14,"head":20,"tail":26,"weight":"100"},{"_gvid":15,"head":28,"headport":"n","tail":27,"tailport":"s"},{"_gvid":16,"head":29,"tail":28,"weight":"100"},{"_gvid":17,"head":30,"tail":29,"weight":"100"},{"_gvid":18,"head":31,"tail":30,"weight":"100"},{"_gvid":19,"head":32,"tail":31,"weight":"100"},{"_gvid":20,"head":33,"tail":32,"weight":"100"},{"_gvid":21,"head":34,"tail":33,"weight":"100"},{"_gvid":22,"head":35,"tail":34,"weight":"100"},{"_gvid":23,"head":36,"tail":35,"weight":"100"},{"_gvid":24,"head":37,"tail":36,"weight":"100"},{"_gvid":25,"head":38,"tail":37,"weight":"100"},{"_gvid":26,"head":21,"tail":38,"weight":"100"},{"_gvid":27,"head":40,"tail":39,"weight":"100"},{"_gvid":28,"head":41,"tail":40,"weight":"100"},{"_gvid":29,"head":42,"tail":41,"weight":"100"},{"_gvid":30,"head":43,"tail":42,"weight":"100"},{"_gvid":31,"head":44,"tail":43,"weight":"100"},{"_gvid":32,"head":45,"tail":44,"weight":"100"},{"_gvid":33,"head":46,"tail":45,"weight":"100"},{"_gvid":34,"head":47,"tail":46,"weight":"100"},{"_gvid":35,"head":48,"tail":47,"weight":"100"},{"_gvid":36,"head":49,"headport":"n","tail":48,"tailport":"s"}],"label":"","name":"CFG","objects":[{"_gvid":0,"edges":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],"nodes":[13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"subgraphs":[1,2,3,4,5,6,7,8,9]},{"_gvid":1,"edges":[],"nodes":[13],"subgraphs":[]},{"_gvid":2,"edges":[1,2],"nodes":[14,15,16],"subgraphs":[]},{"_gvid":3,"edges":[5],"nodes":[17,18],"subgraphs":[]},{"_gvid":4,"edges":[],"nodes":[19],"subgraphs":[]},{"_gvid":5,"edges":[],"nodes":[22],"subgraphs":[]},{"_gvid":6,"edges":[10,11],"nodes":[23,24,25],"subgraphs":[]},{"_gvid":7,"edges":[14],"nodes":[20,26],"subgraphs":[]},{"_gvid":8,"edges":[],"nodes":[27],"subgraphs":[]},{"_gvid":9,"edges":[16,17,18,19,20,21,22,23,24,25,26],"nodes":[21,28,29,30,31,32,33,34,35,36,37,38],"subgraphs":[]},{"_gvid":10,"edges":[27,28,29,30,31,32,33,34,35,36],"nodes":[39,40,41,42,43,44,45,46,47,48,49],"subgraphs":[11,12]},{"_gvid":11,"edges":[27,28,29,30,31,32,33,34,35],"nodes":[39,40,41,42,43,44,45,46,47,48],"subgraphs":[]},{"_gvid":12,"edges":[],"nodes":[49],"subgraphs":[]},{"_gvid":13,"edges":[],"label":"pseudo","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":14,"edges":[],"label":".t00 := CONST 0","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":15,"edges":[],"label":".t10 := n0 == .t00","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":16,"edges":[],"label":"BRANCH .t10","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":17,"edges":[],"label":".t20 := CONST 0","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":18,"edges":[],"label":"RETURN .t20","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":19,"edges":[],"label":"pseudo","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":20,"edges":[],"label":"RETURN .t50","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":21,"edges":[],"label":"RETURN .t120","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":22,"edges":[],"label":"pseudo","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":23,"edges":[],"label":".t30 := CONST 1","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":24,"edges":[],"label":".t40 := n0 == .t30","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":25,"edges":[],"label":"BRANCH .t40","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":26,"edges":[],"label":".t50 := CONST 1","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":27,"edges":[],"label":"pseudo","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":28,"edges":[],"label":".t60 := CONST 1","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":29,"edges":[],"label":".t70 := n0 - .t60","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":30,"edges":[],"label":"PUSH .t70","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":31,"edges":[],"label":"CALL @fib","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":32,"edges":[],"label":".t80 := RETURN VALUE","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":33,"edges":[],"label":".t90 := CONST 2","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":34,"edges":[],"label":".t100 := n0 - .t90","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":35,"edges":[],"label":"PUSH .t100","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":36,"edges":[],"label":"CALL @fib","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":37,"edges":[],"label":".t110 := RETURN VALUE","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":38,"edges":[],"label":".t120 := .t80 + .t110","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":39,"edges":[],"label":".t130 := [.rodata] + 0","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":40,"edges":[],"label":".t140 := CONST 10","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":41,"edges":[],"label":"PUSH .t140","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":42,"edges":[],"label":"CALL @fib","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":43,"edges":[],"label":".t150 := RETURN VALUE","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":44,"edges":[],"label":"PUSH .t130","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":45,"edges":[],"label":"PUSH .t150","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":46,"edges":[],"label":"CALL @printf","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":47,"edges":[],"label":".t160 := CONST 0","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":48,"edges":[],"label":"RETURN .t160","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":49,"edges":[],"label":"pseudo","nodes":[],"shape":"box","subgraphs":[]}],"strict":true} diff --git a/tests/snapshots/hello-riscv-dynamic.json b/tests/snapshots/hello-riscv-dynamic.json new file mode 100644 index 00000000..f005855f --- /dev/null +++ b/tests/snapshots/hello-riscv-dynamic.json @@ -0,0 +1 @@ +{"_subgraph_cnt":3,"directed":true,"edges":[{"_gvid":0,"head":4,"tail":3,"weight":"100"},{"_gvid":1,"head":5,"tail":4,"weight":"100"},{"_gvid":2,"head":6,"tail":5,"weight":"100"},{"_gvid":3,"head":7,"tail":6,"weight":"100"},{"_gvid":4,"head":8,"tail":7,"weight":"100"},{"_gvid":5,"head":9,"tail":8,"weight":"100"},{"_gvid":6,"head":10,"tail":9,"weight":"100"},{"_gvid":7,"head":11,"tail":10,"weight":"100"},{"_gvid":8,"head":12,"headport":"n","tail":11,"tailport":"s"}],"label":"","name":"CFG","objects":[{"_gvid":0,"edges":[0,1,2,3,4,5,6,7,8],"nodes":[3,4,5,6,7,8,9,10,11,12],"subgraphs":[1,2]},{"_gvid":1,"edges":[0,1,2,3,4,5,6,7],"nodes":[3,4,5,6,7,8,9,10,11],"subgraphs":[]},{"_gvid":2,"edges":[],"nodes":[12],"subgraphs":[]},{"_gvid":3,"edges":[],"label":".t00 := [.rodata] + 0","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":4,"edges":[],"label":"PUSH .t00","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":5,"edges":[],"label":"PUSH argc0","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":6,"edges":[],"label":"CALL @printf","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":7,"edges":[],"label":".t10 := [.rodata] + 4","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":8,"edges":[],"label":"PUSH .t10","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":9,"edges":[],"label":"CALL @printf","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":10,"edges":[],"label":".t20 := CONST 0","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":11,"edges":[],"label":"RETURN .t20","nodes":[],"shape":"box","subgraphs":[]},{"_gvid":12,"edges":[],"label":"pseudo","nodes":[],"shape":"box","subgraphs":[]}],"strict":true}