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
No related merge requests found
......@@ -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