Skip to content
Snippets Groups Projects
Commit af3a2196 authored by q3k's avatar q3k Committed by Serge Bazanski
Browse files

l0der: skip relocations for weak symbols

ld emits relocations for weak undefined symbols. We want to safely skip
them.
parent f6c2bca0
No related branches found
No related tags found
1 merge request!45l0dables: implement l0der
......@@ -70,6 +70,21 @@ typedef struct {
#define SHT_RELA 4
#define SHT_REL 9
#define SHT_DYNSYM 11
typedef struct {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
#define ELF32_ST_BIND(i) ((i)>>4)
#define ELF32_ST_TYPE(i) ((i)&0xf)
#define STB_WEAK 2
typedef struct {
Elf32_Addr r_offset;
......@@ -79,7 +94,7 @@ typedef struct {
#define ELF32_R_SYM(i) ((i)>>8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define R_ARM_RELATIVE 23
#define R_ARM_RELATIVE 0x17
typedef struct {
Elf32_Word p_type;
......
......@@ -28,6 +28,8 @@
* a memory map in stone.
*/
#define WEAK_SYMBOL_MAX 128
struct _pie_load_info {
/// Populated by _load_pie
// Addresses within ELF file.
......@@ -36,6 +38,11 @@ struct _pie_load_info {
// Highest alignment request for a segment.
uint32_t strictest_alignment;
/// Populated by _parse_dynamic_symbols
// List of weak symbols for which relocations can be ignored.
uint32_t weak_symbols[WEAK_SYMBOL_MAX];
uint32_t weak_symbol_count;
/// Populated by _get_load_addr
// Load address of ELF file.
uint32_t load_address;
......@@ -301,6 +308,67 @@ static int _load_segment(FIL *fp, struct _pie_load_info *li, Elf32_Phdr *phdr)
return _seek_and_read(fp, phdr->p_offset, (void*)segment_start, phdr->p_filesz);
}
/*
* Parse dynamic symbol sections.
*/
static int _parse_dynamic_symbols(FIL *fp, struct _pie_load_info *li, Elf32_Ehdr *hdr) {
int res;
FRESULT fres;
Elf32_Shdr shdr;
Elf32_Sym sym;
// Go through all dynamic symbol sections.
for (int i = 0; i < hdr->e_shnum; i++) {
uint32_t shdr_addr = hdr->e_shoff + (i * hdr->e_shentsize);
if ((res = _read_section_header(fp, shdr_addr, &shdr)) != 0) {
return res;
}
if (shdr.sh_type != SHT_DYNSYM) {
continue;
}
if ((res = _check_section_header(fp, &shdr)) != 0) {
return res;
}
if ((shdr.sh_size % sizeof(Elf32_Sym)) != 0) {
LOG_ERR("l0der", "_parse_dynamic_symbols: SHT_DYN section with invalid size: %ld", shdr.sh_size);
return -EIO;
}
uint32_t sym_count = shdr.sh_size / sizeof(Elf32_Sym);
// Read symbols one by one.
if ((fres = f_lseek(fp, shdr.sh_offset)) != FR_OK) {
LOG_ERR("l0der", "_parse_dynamic_symbols: seek to first relocation (at 0x%lx) failed", shdr.sh_offset);
return -EIO;
}
for (int j = 0; j < sym_count; j++) {
unsigned int read;
if ((fres = f_read(fp, &sym, sizeof(Elf32_Sym), &read)) != FR_OK || read != sizeof(Elf32_Sym)) {
LOG_ERR("l0der", "__parse_dynamic_symbols: symbol read failed: %d", fres);
return -EIO;
}
uint32_t bind = ELF32_ST_BIND(sym.st_info);
if (bind != STB_WEAK) {
continue;
}
if (li->weak_symbol_count >= WEAK_SYMBOL_MAX) {
LOG_ERR("l0der", "__parse_dynamic_symbols: too many weak symbols (limit: %d)", WEAK_SYMBOL_MAX);
return -ENOMEM;
}
li->weak_symbols[li->weak_symbol_count++] = j;
}
}
return 0;
}
/*
* Apply dynamic relocations from ELF.
*
......@@ -354,9 +422,27 @@ static int _run_relocations(FIL *fp, struct _pie_load_info *li, Elf32_Ehdr *hdr)
return -EIO;
}
uint32_t sym = ELF32_R_SYM(rel.r_info);
uint8_t type = ELF32_R_TYPE(rel.r_info);
// Skip relocations that are for weak symbols.
// (ie., do not resolve relocation - they default to a safe NULL)
uint8_t skip = 0;
if (sym != 0) {
for (int k = 0; k < li->weak_symbol_count; k++) {
if (li->weak_symbols[k] == sym) {
skip = 1;
break;
}
}
}
if (skip) {
continue;
}
switch (type) {
case R_ARM_RELATIVE:
// Relocate.
if ((rel.r_offset % 4) != 0) {
LOG_ERR("l0der", "_run_relocations: R_ARM_RELATIVE address must be 4-byte aligned");
return -ENOEXEC;
......@@ -388,11 +474,8 @@ static int _load_pie(FIL *fp, Elf32_Ehdr *hdr, struct l0dable_info *info)
int res;
struct _pie_load_info li = {0};
// First pass over program headers: sanity check sizes and calculate
// memory image bounds. l0der currently only supports loading the image into
// the core1 address space, that is from 0x1008_0000 to 0x1010_0000. Thus,
// we need to ensure that all the LOADable segments can fit within this
// range.
// First pass over program headers: sanity check sizes, calculate image
// size bounds, check alignment.
li.image_start = 0xffffffff;
li.image_limit = 0x0;
......@@ -477,6 +560,11 @@ static int _load_pie(FIL *fp, Elf32_Ehdr *hdr, struct l0dable_info *info)
}
}
// Load dynamic symbols.
if ((res = _parse_dynamic_symbols(fp, &li, hdr)) != 0) {
return res;
}
// Run relocations.
if ((res = _run_relocations(fp, &li, hdr)) != 0) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment