dont require phdr to link
This commit is contained in:
parent
853a1ba612
commit
fb07130990
5 changed files with 154 additions and 63 deletions
46
mld/link.c
46
mld/link.c
|
@ -12,8 +12,6 @@
|
|||
#include "link.h"
|
||||
#include "mips.h"
|
||||
|
||||
#define SEC_ALIGN 0x1000
|
||||
|
||||
static int load_objects(struct linker *linker)
|
||||
{
|
||||
int max_entries = linker->args->in_count + 1;
|
||||
|
@ -168,7 +166,7 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
|
|||
struct symbol_table *symtab, const Elf32_Sym *sym)
|
||||
{
|
||||
size_t shndx = B16(sym->st_shndx);
|
||||
if (shndx == 0)
|
||||
if (shndx == 0 || shndx == SHN_ABS)
|
||||
return M_SUCCESS; // ignore this symbol
|
||||
|
||||
// find the given section
|
||||
|
@ -184,11 +182,9 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
|
|||
return M_ERROR;
|
||||
}
|
||||
|
||||
Elf32_Shdr const *shdr = &obj->shdr[shndx];
|
||||
struct segment *sec = NULL;
|
||||
for (size_t i = 0; i < obj->phdr_len; i++) {
|
||||
Elf32_Phdr *temp = &obj->phdr[i];
|
||||
if (PHDR_SHDR_MATCH(temp, shdr)) {
|
||||
if (obj->phdr_to_shdr_mapping[i] == shndx) {
|
||||
sec = &obj->segments[i];
|
||||
break;
|
||||
}
|
||||
|
@ -219,6 +215,20 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
|
|||
new.st_shndx = B16(new_shndx);
|
||||
new.st_size = 0;
|
||||
|
||||
// rename symbol if its name is empty to perm placeholder
|
||||
//if (B32(sym->st_name) == 0) {
|
||||
// #define __MAX 512
|
||||
// char name[__MAX];
|
||||
// memset(name, 0, __MAX);
|
||||
// strcat(name, "__sym");
|
||||
// snprintf(name + strlen(name), __MAX - strlen(name), "%d",
|
||||
// B32(sym->st_value));
|
||||
// if (strtab_push(linker->symtab.strtab, name, &str_off))
|
||||
// return M_ERROR;
|
||||
// new.st_name = B32(str_off);
|
||||
// #undef __MAX
|
||||
//}
|
||||
|
||||
if (symtab_get(&linker->symtab, NULL, name, obj->index) == M_SUCCESS) {
|
||||
ERROR("cannot link doubly defiend symbol '%s'", name);
|
||||
return M_ERROR;
|
||||
|
@ -447,33 +457,38 @@ static int relocate_instruction_rela(struct linker *linker,
|
|||
// 16bit absolute
|
||||
if (vaddr_abs > UINT16_MAX)
|
||||
warn = true;
|
||||
ins.immd = (uint16_t)vaddr_abs;
|
||||
ins.immd += (uint16_t)vaddr_abs;
|
||||
break;
|
||||
case R_MIPS_PC16:
|
||||
// 16bit relative shifted
|
||||
if (vaddr_rel > INT16_MAX || vaddr_rel < INT16_MIN)
|
||||
warn = true;
|
||||
ins.offset = vaddr_rel;
|
||||
ins.offset += vaddr_rel;
|
||||
break;
|
||||
case R_MIPS_26:
|
||||
case R_MIPS_JALR:
|
||||
// 26bit absolute shifted
|
||||
if (vaddr_abs >= (1 << 25))
|
||||
warn = true;
|
||||
ins.target = (vaddr_abs & 0x0FFFFFFF) >> 2;
|
||||
ins.target += (vaddr_abs & 0x0FFFFFFF) >> 2;
|
||||
break;
|
||||
case R_MIPS_PC26_S2:
|
||||
// 26bit relative shifted
|
||||
if (vaddr_rel >= (1 << 24) || -vaddr_rel > (1 << 24))
|
||||
warn = true;
|
||||
ins.offs26 = vaddr_rel;
|
||||
ins.offs26 += vaddr_rel;
|
||||
break;
|
||||
case R_MIPS_LO16:
|
||||
// lo 16bit absolute
|
||||
ins.immd = (uint16_t)(vaddr_abs & 0xFFFF);
|
||||
ins.immd += (uint16_t)(vaddr_abs & 0xFFFF);
|
||||
break;
|
||||
case R_MIPS_HI16:
|
||||
// hi 16bit absolute
|
||||
ins.immd = (uint16_t)(vaddr_abs >> 16);
|
||||
ins.immd += (uint16_t)(vaddr_abs >> 16);
|
||||
break;
|
||||
case R_MIPS_32:
|
||||
// 32bit absolute
|
||||
ins.raw = vaddr_abs;
|
||||
break;
|
||||
default:
|
||||
ERROR("do not know how do handle relocation type [%d]", typ);
|
||||
|
@ -596,9 +611,6 @@ static void update_offsets(struct linker *linker)
|
|||
|
||||
static int write_file(struct linker *linker)
|
||||
{
|
||||
extern char *current_file;
|
||||
current_file = linker->args->out_file;
|
||||
|
||||
int fd = open(linker->args->out_file, O_RDWR | O_CREAT, 0711);
|
||||
if (fd < 0) {
|
||||
PERROR("cannot write");
|
||||
|
@ -739,12 +751,16 @@ static void linker_free(struct linker *linker)
|
|||
|
||||
int link_files(struct linker_arguments args) {
|
||||
struct linker linker;
|
||||
extern char *current_file;
|
||||
|
||||
|
||||
int res = M_SUCCESS;
|
||||
if (res == M_SUCCESS)
|
||||
res = linker_init(&linker, &args);
|
||||
if (res == M_SUCCESS)
|
||||
res = load_objects(&linker);
|
||||
|
||||
current_file = args.out_file;
|
||||
if (res == M_SUCCESS)
|
||||
res = relocate_segments(&linker);
|
||||
if (res == M_SUCCESS)
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
#define TEXT_VADDR_MIN 0x00400000
|
||||
#define DATA_VADDR_MIN 0x10000000
|
||||
|
||||
// alignment of a section
|
||||
#define SEC_ALIGN 0x1000
|
||||
|
||||
// pre define
|
||||
struct linker;
|
||||
struct object;
|
||||
|
@ -42,6 +45,7 @@ struct segment;
|
|||
struct string_table;
|
||||
struct symbol_table;
|
||||
struct symbol_table_mapping;
|
||||
struct glboff_table;
|
||||
|
||||
///
|
||||
/// relocation table
|
||||
|
@ -220,6 +224,10 @@ struct object {
|
|||
// program table
|
||||
Elf32_Phdr *phdr;
|
||||
size_t phdr_len;
|
||||
bool phdr_local; // if phdr was created though malloc
|
||||
|
||||
// phdr <=> shdr mappings
|
||||
uint32_t *phdr_to_shdr_mapping;
|
||||
|
||||
// object meta
|
||||
const char *name;
|
||||
|
|
105
mld/obj.c
105
mld/obj.c
|
@ -49,10 +49,10 @@ static int load_ehdr(struct object *object)
|
|||
EHDR_ASSERT(type, sizeof(Elf32_Half));
|
||||
EHDR_ASSERT(machine, sizeof(Elf32_Half));
|
||||
EHDR_ASSERT(version, sizeof(Elf32_Word));
|
||||
EHDR_ASSERT(flags, sizeof(Elf32_Word));
|
||||
// EHDR_ASSERT(flags, sizeof(Elf32_Word));
|
||||
EHDR_ASSERT(ehsize, sizeof(Elf32_Half));
|
||||
EHDR_ASSERT(phentsize, sizeof(Elf32_Half));
|
||||
EHDR_ASSERT(shentsize, sizeof(Elf32_Half));
|
||||
// EHDR_ASSERT(phentsize, sizeof(Elf32_Half));
|
||||
// EHDR_ASSERT(shentsize, sizeof(Elf32_Half));
|
||||
|
||||
#undef EHDR_ASSERT
|
||||
|
||||
|
@ -81,23 +81,94 @@ static int load_shdr(struct object *object)
|
|||
return M_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the phdr
|
||||
*/
|
||||
static int create_phdr(struct object *object)
|
||||
{
|
||||
uint32_t entries = 0;
|
||||
for (uint32_t i = 0; i < object->shdr_len; i++) {
|
||||
Elf32_Shdr *hdr = &object->shdr[i];
|
||||
uint32_t type = B32(hdr->sh_type);
|
||||
|
||||
if (type != SHT_PROGBITS && type != SHT_NOBITS)
|
||||
continue;
|
||||
|
||||
entries += 1;
|
||||
}
|
||||
|
||||
Elf32_Phdr *phdr = malloc(entries * sizeof(Elf32_Phdr));
|
||||
if (phdr == NULL) {
|
||||
PERROR("cannot alloc");
|
||||
return M_ERROR;
|
||||
}
|
||||
|
||||
object->phdr = phdr;
|
||||
object->phdr_len = entries;
|
||||
object->phdr_local = true;
|
||||
|
||||
uint32_t *mapping = malloc(entries * sizeof(uint32_t));
|
||||
if (mapping == NULL) {
|
||||
PERROR("cannot alloc");
|
||||
return M_ERROR;
|
||||
}
|
||||
|
||||
object->phdr_to_shdr_mapping = mapping;
|
||||
|
||||
uint32_t index = 0;
|
||||
for (uint32_t i = 0; i < object->shdr_len; i++) {
|
||||
Elf32_Shdr *hdr = &object->shdr[i];
|
||||
uint32_t type = B32(hdr->sh_type);
|
||||
|
||||
if (type != SHT_PROGBITS && type != SHT_NOBITS)
|
||||
continue;
|
||||
mapping[index] = i;
|
||||
phdr[index++] = (Elf32_Phdr) {
|
||||
.p_type = B32(PT_LOAD),
|
||||
.p_flags = B32(
|
||||
// execute
|
||||
((B32(hdr->sh_flags) & SHF_EXECINSTR)
|
||||
? PF_X : 0) |
|
||||
// write
|
||||
((B32(hdr->sh_flags) & SHF_WRITE)
|
||||
? PF_W : 0) |
|
||||
// read
|
||||
((B32(hdr->sh_flags) & SHF_ALLOC)
|
||||
? PF_R : 0)
|
||||
),
|
||||
.p_offset = hdr->sh_offset,
|
||||
.p_vaddr = hdr->sh_addr,
|
||||
.p_paddr = hdr->sh_addr,
|
||||
.p_filesz = hdr->sh_size,
|
||||
.p_memsz = hdr->sh_size,
|
||||
.p_align = B32(SEC_ALIGN),
|
||||
};
|
||||
}
|
||||
|
||||
return M_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the phdr
|
||||
*/
|
||||
static int load_phdr(struct object *object)
|
||||
{
|
||||
size_t phdr_len = B16(object->ehdr->e_phentsize) *
|
||||
B16(object->ehdr->e_phnum);
|
||||
size_t phdr_off = B32(object->ehdr->e_phoff);
|
||||
object->phdr = (Elf32_Phdr *) (object->mapped + phdr_off);
|
||||
object->phdr_len = B16(object->ehdr->e_phnum);
|
||||
//size_t phdr_len = B16(object->ehdr->e_phentsize) *
|
||||
// B16(object->ehdr->e_phnum);
|
||||
|
||||
if (BOUND_CHK(object, phdr_len, phdr_off)) {
|
||||
ERROR("cannot read phdr");
|
||||
return M_ERROR;
|
||||
}
|
||||
//if (phdr_len < 1)
|
||||
return create_phdr(object);
|
||||
|
||||
return M_SUCCESS;
|
||||
//size_t phdr_off = B32(object->ehdr->e_phoff);
|
||||
//object->phdr = (Elf32_Phdr *) (object->mapped + phdr_off);
|
||||
//object->phdr_len = B16(object->ehdr->e_phnum);
|
||||
|
||||
//if (BOUND_CHK(object, phdr_len, phdr_off)) {
|
||||
// ERROR("cannot read phdr");
|
||||
// return M_ERROR;
|
||||
//}
|
||||
|
||||
//return M_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,7 +302,7 @@ static int load_shstrtab(struct object *object)
|
|||
*/
|
||||
static int load_segments(struct object *object)
|
||||
{
|
||||
object->segment_len = B16(object->ehdr->e_phnum);
|
||||
object->segment_len = object->phdr_len;
|
||||
object->segments = malloc(sizeof(struct segment) *
|
||||
object->segment_len);
|
||||
|
||||
|
@ -287,6 +358,8 @@ int object_load(struct object *object, char *path, uint32_t index)
|
|||
object->mapped = NULL;
|
||||
object->name = path;
|
||||
object->index = index;
|
||||
object->phdr_local = false;
|
||||
object->phdr_to_shdr_mapping = NULL;
|
||||
|
||||
/** load the file */
|
||||
if (map_file(object, path))
|
||||
|
@ -331,6 +404,10 @@ void object_free(struct object *obj)
|
|||
free(obj->strtabs);
|
||||
if (obj->segments != NULL)
|
||||
free(obj->segments);
|
||||
if (obj->phdr_local)
|
||||
free(obj->phdr);
|
||||
if (obj->phdr_to_shdr_mapping)
|
||||
free(obj->phdr_to_shdr_mapping);
|
||||
if (obj->fd > 0)
|
||||
close(obj->fd);
|
||||
if (obj->mapped != NULL && obj->mapped != MAP_FAILED)
|
||||
|
|
20
mld/seg.c
20
mld/seg.c
|
@ -25,14 +25,8 @@ static int load_phdr(struct object *obj, struct segment *seg, size_t index)
|
|||
*/
|
||||
static int load_shdr(struct object *obj, struct segment *seg, size_t index)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
for (size_t i = 0; i < obj->shdr_len; i++) {
|
||||
Elf32_Shdr *hdr = &obj->shdr[i];
|
||||
|
||||
// find shdr that matches the offset in phdr
|
||||
if (!PHDR_SHDR_MATCH(seg->phdr, hdr))
|
||||
continue;
|
||||
uint32_t shndx = obj->phdr_to_shdr_mapping[index];
|
||||
Elf32_Shdr *hdr = &obj->shdr[shndx];
|
||||
|
||||
// get name
|
||||
uint32_t name = B32(hdr->sh_name);
|
||||
|
@ -52,16 +46,8 @@ static int load_shdr(struct object *obj, struct segment *seg, size_t index)
|
|||
return M_ERROR;
|
||||
}
|
||||
|
||||
found = true;
|
||||
seg->shdr = hdr;
|
||||
seg->shdr_idx = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ERROR("cannot find shdr for segment [%d]", index);
|
||||
return M_ERROR;
|
||||
}
|
||||
seg->shdr_idx = shndx;
|
||||
|
||||
return M_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,10 @@ int symtab_get(struct symbol_table *symtab, Elf32_Sym **res, const char *name,
|
|||
if (strcmp(name, symname) != 0)
|
||||
continue;
|
||||
|
||||
// ignore absolute symbols
|
||||
if (B16(sym->st_shndx) == SHN_ABS)
|
||||
continue;
|
||||
|
||||
// only allow retrevial of local variables from the
|
||||
// same object
|
||||
if (sym->st_info >> 4 != STB_GLOBAL && symtab->map != NULL &&
|
||||
|
|
Loading…
Reference in a new issue