diff --git a/components/elfloader/common/include/tos_elfloader_err.h b/components/elfloader/common/include/tos_elfloader_err.h index 2778b67d..fcee38d7 100644 --- a/components/elfloader/common/include/tos_elfloader_err.h +++ b/components/elfloader/common/include/tos_elfloader_err.h @@ -20,18 +20,19 @@ typedef enum elfloader_err_en { ELFLOADER_ERR_NONE, + ELFLOADER_ERR_FD_READ_FAILED, ELFLOADER_ERR_HEADER_INVALID, - ELFLOADER_ERR_TYPE_INVALID, ELFLOADER_ERR_NO_DYN, ELFLOADER_ERR_NO_SYMTAB, ELFLOADER_ERR_NO_STRTAB, ELFLOADER_ERR_NO_TEXT, ELFLOADER_ERR_NO_LOAD_SEGMENTS, - ELFLOADER_ERR_FD_READ_FAILED, + ELFLOADER_ERR_OUT_OF_MEMORY, + ELFLOADER_ERR_RELOCATE_FAILED, + ELFLOADER_ERR_PTR_NULL, ELFLOADER_ERR_SECTION_NOT_FOUND, ELFLOADER_ERR_SYM_NOT_FOUND, - ELFLOADER_ERR_OUT_OF_MEMORY, - ELFLOADER_ERR_PTR_NULL, + ELFLOADER_ERR_TYPE_INVALID, } el_err_t; #endif /* _TOS_ELFLOADER_ERR_H_ */ diff --git a/components/elfloader/common/include/tos_elfloader_relocate.h b/components/elfloader/common/include/tos_elfloader_relocate.h index 63825d26..86ed8aae 100644 --- a/components/elfloader/common/include/tos_elfloader_relocate.h +++ b/components/elfloader/common/include/tos_elfloader_relocate.h @@ -18,7 +18,7 @@ #ifndef _TOS_ELFLOADER_RELOCATE_H_ #define _TOS_ELFLOADER_RELOCATE_H_ -__KNL__ void elfloader_arch_relocate(uint32_t reloc_addr, int32_t load_bias, uint32_t addr, elf32_rela_t *rela, int is_rela); +__KNL__ el_err_t elfloader_arch_relocate(uint32_t reloc_addr, int32_t load_bias, uint32_t addr, elf32_rela_t *rela, int is_rela, elf32_sym_t *sym); #endif /* _TOS_ELFLOADER_RELOCATE_H_ */ diff --git a/components/elfloader/common/tos_elfloader_relocate-arm.c b/components/elfloader/common/tos_elfloader_relocate-arm.c index fe5ee98e..8fd12eb5 100644 --- a/components/elfloader/common/tos_elfloader_relocate-arm.c +++ b/components/elfloader/common/tos_elfloader_relocate-arm.c @@ -18,11 +18,23 @@ #include "tos_elfloader.h" /* values for ELF32_R_TYPE(info) */ +#define R_ARM_NONE 0 +#define R_ARM_PC24 1 #define R_ARM_ABS32 2 #define R_ARM_THM_CALL 10 #define R_ARM_GLOB_DAT 21 #define R_ARM_JUMP_SLOT 22 #define R_ARM_RELATIVE 23 +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_THM_JUMP24 30 +#define R_ARM_TARGET1 38 +#define R_ARM_V4BX 40 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 /* - S (when used on its own) is the address of the symbol. @@ -38,33 +50,172 @@ addresses). This value must always be word-aligned. See §4.6.1.8, Proxy generat - GOT(S) is the address of the GOT entry for the symbol S. */ -// TODO: support more relocation type -__KNL__ void elfloader_arch_relocate(uint32_t reloc_addr, int32_t load_bias, uint32_t addr, elf32_rela_t *rela, int is_rela) +__KNL__ el_err_t elfloader_arch_relocate(uint32_t reloc_addr, int32_t load_bias, uint32_t addr, elf32_rela_t *rela, int is_rela, elf32_sym_t *sym) { /* ATTENTION: different reloc_addr calculation algorithm for relocatable object and shared object */ + int32_t offset; + uint32_t tmp; + uint32_t upper, lower, sign, j1, j2; switch (ELF32_R_TYPE(rela->r_info)) { + case R_ARM_NONE: + /* ignore */ + break; + + case R_ARM_ABS32: + case R_ARM_TARGET1: + /* (S + A) | T */ + *(uint32_t *)reloc_addr += addr; + break; + + case R_ARM_PC24: + case R_ARM_CALL: + case R_ARM_JUMP24: + /* ((S + A) | T) – P */ + if (addr & 3) { + tos_kprintf("unsupported interworking call(ARM -> Thumb)\n"); + return ELFLOADER_ERR_RELOCATE_FAILED; + } + + offset = *(uint32_t *)reloc_addr; + offset = (offset & 0x00ffffff) << 2; + if (offset & 0x02000000) { + offset -= 0x04000000; + } + + offset += addr - reloc_addr; + + if (offset <= (int32_t)0xfe000000 || offset >= (int32_t)0x02000000) { + tos_kprintf("relocation out of range\n"); + return ELFLOADER_ERR_RELOCATE_FAILED; + } + + offset >>= 2; + offset &= 0x00ffffff; + + *(uint32_t *)reloc_addr &= 0xff000000; + *(uint32_t *)reloc_addr |= offset; + break; + + case R_ARM_V4BX: + *(uint32_t *)reloc_addr &= 0xf000000f; + *(uint32_t *)reloc_addr |= 0x01a0f000; + break; + + case R_ARM_PREL31: + /* ((S + A) | T) – P */ + offset = (*(int32_t *)reloc_addr << 1) >> 1; /* sign extend */ + offset += addr - reloc_addr; + + if (offset >= 0x40000000 || offset < -0x40000000) { + tos_kprintf("relocation out of range\n"); + return ELFLOADER_ERR_RELOCATE_FAILED; + } + + *(uint32_t *)reloc_addr &= 0x80000000; + *(uint32_t *)reloc_addr |= offset & 0x7fffffff; + break; + case R_ARM_GLOB_DAT: case R_ARM_JUMP_SLOT: /* (S + A) | T */ *(uint32_t *)reloc_addr = addr; break; + case R_ARM_MOVW_ABS_NC: + case R_ARM_MOVT_ABS: + offset = tmp = *(uint32_t *)reloc_addr; + offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff); + offset = (offset ^ 0x8000) - 0x8000; + + offset += addr; + if (ELF32_R_TYPE(rela->r_info) == R_ARM_MOVT_ABS) { + offset >>= 16; + } + + tmp &= 0xfff0f000; + tmp |= ((offset & 0xf000) << 4) | (offset & 0x0fff); + + *(uint32_t *)reloc_addr = tmp; + break; + + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + if (ELF32_SYM_TYPE(sym->st_info) == STT_FUNC && !(addr & 1)) { + tos_kprintf("unsupported interworking call(Thumb -> ARM)\n"); + return ELFLOADER_ERR_RELOCATE_FAILED; + } + + upper = *(uint16_t *)reloc_addr; + lower = *(uint16_t *)(reloc_addr + 2); + + sign = (upper >> 10) & 1; + j1 = (lower >> 13) & 1; + j2 = (lower >> 11) & 1; + offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) | + ((~(j2 ^ sign) & 1) << 22) | + ((upper & 0x03ff) << 12) | + ((lower & 0x07ff) << 1); + if (offset & 0x01000000) { + offset -= 0x02000000; + } + offset += addr - reloc_addr; + + if (offset <= (int32_t)0xff000000 || offset >= (int32_t)0x01000000) { + tos_kprintf("relocation out of range\n"); + return ELFLOADER_ERR_RELOCATE_FAILED; + } + + sign = (offset >> 24) & 1; + j1 = sign ^ (~(offset >> 23) & 1); + j2 = sign ^ (~(offset >> 22) & 1); + upper = (uint16_t)((upper & 0xf800) | (sign << 10) | + ((offset >> 12) & 0x03ff)); + lower = (uint16_t)((lower & 0xd000) | + (j1 << 13) | (j2 << 11) | + ((offset >> 1) & 0x07ff)); + + *(uint16_t *)reloc_addr = (uint16_t)upper; + *(uint16_t *)(reloc_addr + 2) = (uint16_t)lower; + break; + + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + upper = *(uint16_t *)reloc_addr; + lower = *(uint16_t *)(reloc_addr + 2); + + offset = ((upper & 0x000f) << 12) | + ((upper & 0x0400) << 1) | + ((lower & 0x7000) >> 4) | (lower & 0x00ff); + offset = (offset ^ 0x8000) - 0x8000; + offset += addr; + + if (ELF32_R_TYPE(rela->r_info) == R_ARM_THM_MOVT_ABS) { + offset >>= 16; + } + + upper = (uint16_t)((upper & 0xfbf0) | + ((offset & 0xf000) >> 12) | + ((offset & 0x0800) >> 1)); + lower = (uint16_t)((lower & 0x8f00) | + ((offset & 0x0700) << 4) | + (offset & 0x00ff)); + *(uint16_t *)reloc_addr = (uint16_t)upper; + *(uint16_t *)(reloc_addr + 2) = (uint16_t)lower; + break; + case R_ARM_RELATIVE: /* B(S) + A */ *(uint32_t *)reloc_addr += load_bias; break; - case R_ARM_ABS32: - /* (S + A) | T */ - *(uint32_t *)reloc_addr += addr; - break; - default: - printf("Unsupported Relocation Type: %d\n", ELF32_R_TYPE(rela->r_info)); + tos_kprintf("unsupported relocation type: %d\n", ELF32_R_TYPE(rela->r_info)); break; } + + return ELFLOADER_ERR_NONE; } diff --git a/components/elfloader/relocatable_object/tos_elfloader_relocatable_object.c b/components/elfloader/relocatable_object/tos_elfloader_relocatable_object.c index 05bf7038..c9bcd02f 100644 --- a/components/elfloader/relocatable_object/tos_elfloader_relocatable_object.c +++ b/components/elfloader/relocatable_object/tos_elfloader_relocatable_object.c @@ -136,7 +136,9 @@ __STATIC__ el_err_t elfloader_relocate(int fd, void *address, return ELFLOADER_ERR_SYM_NOT_FOUND; } - elfloader_arch_relocate(rela.r_offset + (uint32_t)address, 0, (uint32_t)addr, &rela, is_rela); + if (elfloader_arch_relocate(rela.r_offset + (uint32_t)address, 0, (uint32_t)addr, &rela, is_rela, &sym) != ELFLOADER_ERR_NONE) { + return ELFLOADER_ERR_RELOCATE_FAILED; + } rel_offset += rel_entsize; } diff --git a/components/elfloader/shared_object/tos_elfloader_shared_object.c b/components/elfloader/shared_object/tos_elfloader_shared_object.c index 57029bf8..21f9407b 100644 --- a/components/elfloader/shared_object/tos_elfloader_shared_object.c +++ b/components/elfloader/shared_object/tos_elfloader_shared_object.c @@ -109,7 +109,9 @@ __STATIC__ el_err_t elfloader_relocate(int fd, int32_t load_bias, return ELFLOADER_ERR_SYM_NOT_FOUND; } - elfloader_arch_relocate(rela.r_offset + load_bias, load_bias, (uint32_t)addr, &rela, is_rela); + if (elfloader_arch_relocate(rela.r_offset + load_bias, load_bias, (uint32_t)addr, &rela, is_rela, &sym) != ELFLOADER_ERR_NONE) { + return ELFLOADER_ERR_RELOCATE_FAILED; + } rel_offset += rel_entsize; } @@ -249,7 +251,7 @@ __API__ el_err_t tos_elfloader_load(el_module_t *module, int fd) } /* reserving memory for LOAD segments */ - base = tos_mmheap_aligned_alloc(vaddr_end - vaddr_start, 64); + base = tos_mmheap_alloc(vaddr_end - vaddr_start); if (!base) { return ELFLOADER_ERR_OUT_OF_MEMORY; }