support more relocation type in elfloader
mostly copied from linux kernel 4.20, Shh...
This commit is contained in:
@@ -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_ */
|
||||
|
@@ -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_ */
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user