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 "link.h"
|
||||||
#include "mips.h"
|
#include "mips.h"
|
||||||
|
|
||||||
#define SEC_ALIGN 0x1000
|
|
||||||
|
|
||||||
static int load_objects(struct linker *linker)
|
static int load_objects(struct linker *linker)
|
||||||
{
|
{
|
||||||
int max_entries = linker->args->in_count + 1;
|
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)
|
struct symbol_table *symtab, const Elf32_Sym *sym)
|
||||||
{
|
{
|
||||||
size_t shndx = B16(sym->st_shndx);
|
size_t shndx = B16(sym->st_shndx);
|
||||||
if (shndx == 0)
|
if (shndx == 0 || shndx == SHN_ABS)
|
||||||
return M_SUCCESS; // ignore this symbol
|
return M_SUCCESS; // ignore this symbol
|
||||||
|
|
||||||
// find the given section
|
// find the given section
|
||||||
|
@ -184,11 +182,9 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf32_Shdr const *shdr = &obj->shdr[shndx];
|
|
||||||
struct segment *sec = NULL;
|
struct segment *sec = NULL;
|
||||||
for (size_t i = 0; i < obj->phdr_len; i++) {
|
for (size_t i = 0; i < obj->phdr_len; i++) {
|
||||||
Elf32_Phdr *temp = &obj->phdr[i];
|
if (obj->phdr_to_shdr_mapping[i] == shndx) {
|
||||||
if (PHDR_SHDR_MATCH(temp, shdr)) {
|
|
||||||
sec = &obj->segments[i];
|
sec = &obj->segments[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -219,6 +215,20 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
|
||||||
new.st_shndx = B16(new_shndx);
|
new.st_shndx = B16(new_shndx);
|
||||||
new.st_size = 0;
|
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) {
|
if (symtab_get(&linker->symtab, NULL, name, obj->index) == M_SUCCESS) {
|
||||||
ERROR("cannot link doubly defiend symbol '%s'", name);
|
ERROR("cannot link doubly defiend symbol '%s'", name);
|
||||||
return M_ERROR;
|
return M_ERROR;
|
||||||
|
@ -447,33 +457,38 @@ static int relocate_instruction_rela(struct linker *linker,
|
||||||
// 16bit absolute
|
// 16bit absolute
|
||||||
if (vaddr_abs > UINT16_MAX)
|
if (vaddr_abs > UINT16_MAX)
|
||||||
warn = true;
|
warn = true;
|
||||||
ins.immd = (uint16_t)vaddr_abs;
|
ins.immd += (uint16_t)vaddr_abs;
|
||||||
break;
|
break;
|
||||||
case R_MIPS_PC16:
|
case R_MIPS_PC16:
|
||||||
// 16bit relative shifted
|
// 16bit relative shifted
|
||||||
if (vaddr_rel > INT16_MAX || vaddr_rel < INT16_MIN)
|
if (vaddr_rel > INT16_MAX || vaddr_rel < INT16_MIN)
|
||||||
warn = true;
|
warn = true;
|
||||||
ins.offset = vaddr_rel;
|
ins.offset += vaddr_rel;
|
||||||
break;
|
break;
|
||||||
case R_MIPS_26:
|
case R_MIPS_26:
|
||||||
|
case R_MIPS_JALR:
|
||||||
// 26bit absolute shifted
|
// 26bit absolute shifted
|
||||||
if (vaddr_abs >= (1 << 25))
|
if (vaddr_abs >= (1 << 25))
|
||||||
warn = true;
|
warn = true;
|
||||||
ins.target = (vaddr_abs & 0x0FFFFFFF) >> 2;
|
ins.target += (vaddr_abs & 0x0FFFFFFF) >> 2;
|
||||||
break;
|
break;
|
||||||
case R_MIPS_PC26_S2:
|
case R_MIPS_PC26_S2:
|
||||||
// 26bit relative shifted
|
// 26bit relative shifted
|
||||||
if (vaddr_rel >= (1 << 24) || -vaddr_rel > (1 << 24))
|
if (vaddr_rel >= (1 << 24) || -vaddr_rel > (1 << 24))
|
||||||
warn = true;
|
warn = true;
|
||||||
ins.offs26 = vaddr_rel;
|
ins.offs26 += vaddr_rel;
|
||||||
break;
|
break;
|
||||||
case R_MIPS_LO16:
|
case R_MIPS_LO16:
|
||||||
// lo 16bit absolute
|
// lo 16bit absolute
|
||||||
ins.immd = (uint16_t)(vaddr_abs & 0xFFFF);
|
ins.immd += (uint16_t)(vaddr_abs & 0xFFFF);
|
||||||
break;
|
break;
|
||||||
case R_MIPS_HI16:
|
case R_MIPS_HI16:
|
||||||
// hi 16bit absolute
|
// 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;
|
break;
|
||||||
default:
|
default:
|
||||||
ERROR("do not know how do handle relocation type [%d]", typ);
|
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)
|
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);
|
int fd = open(linker->args->out_file, O_RDWR | O_CREAT, 0711);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
PERROR("cannot write");
|
PERROR("cannot write");
|
||||||
|
@ -739,12 +751,16 @@ static void linker_free(struct linker *linker)
|
||||||
|
|
||||||
int link_files(struct linker_arguments args) {
|
int link_files(struct linker_arguments args) {
|
||||||
struct linker linker;
|
struct linker linker;
|
||||||
|
extern char *current_file;
|
||||||
|
|
||||||
|
|
||||||
int res = M_SUCCESS;
|
int res = M_SUCCESS;
|
||||||
if (res == M_SUCCESS)
|
if (res == M_SUCCESS)
|
||||||
res = linker_init(&linker, &args);
|
res = linker_init(&linker, &args);
|
||||||
if (res == M_SUCCESS)
|
if (res == M_SUCCESS)
|
||||||
res = load_objects(&linker);
|
res = load_objects(&linker);
|
||||||
|
|
||||||
|
current_file = args.out_file;
|
||||||
if (res == M_SUCCESS)
|
if (res == M_SUCCESS)
|
||||||
res = relocate_segments(&linker);
|
res = relocate_segments(&linker);
|
||||||
if (res == M_SUCCESS)
|
if (res == M_SUCCESS)
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
#define TEXT_VADDR_MIN 0x00400000
|
#define TEXT_VADDR_MIN 0x00400000
|
||||||
#define DATA_VADDR_MIN 0x10000000
|
#define DATA_VADDR_MIN 0x10000000
|
||||||
|
|
||||||
|
// alignment of a section
|
||||||
|
#define SEC_ALIGN 0x1000
|
||||||
|
|
||||||
// pre define
|
// pre define
|
||||||
struct linker;
|
struct linker;
|
||||||
struct object;
|
struct object;
|
||||||
|
@ -42,6 +45,7 @@ struct segment;
|
||||||
struct string_table;
|
struct string_table;
|
||||||
struct symbol_table;
|
struct symbol_table;
|
||||||
struct symbol_table_mapping;
|
struct symbol_table_mapping;
|
||||||
|
struct glboff_table;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// relocation table
|
/// relocation table
|
||||||
|
@ -220,6 +224,10 @@ struct object {
|
||||||
// program table
|
// program table
|
||||||
Elf32_Phdr *phdr;
|
Elf32_Phdr *phdr;
|
||||||
size_t phdr_len;
|
size_t phdr_len;
|
||||||
|
bool phdr_local; // if phdr was created though malloc
|
||||||
|
|
||||||
|
// phdr <=> shdr mappings
|
||||||
|
uint32_t *phdr_to_shdr_mapping;
|
||||||
|
|
||||||
// object meta
|
// object meta
|
||||||
const char *name;
|
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(type, sizeof(Elf32_Half));
|
||||||
EHDR_ASSERT(machine, sizeof(Elf32_Half));
|
EHDR_ASSERT(machine, sizeof(Elf32_Half));
|
||||||
EHDR_ASSERT(version, sizeof(Elf32_Word));
|
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(ehsize, sizeof(Elf32_Half));
|
||||||
EHDR_ASSERT(phentsize, sizeof(Elf32_Half));
|
// EHDR_ASSERT(phentsize, sizeof(Elf32_Half));
|
||||||
EHDR_ASSERT(shentsize, sizeof(Elf32_Half));
|
// EHDR_ASSERT(shentsize, sizeof(Elf32_Half));
|
||||||
|
|
||||||
#undef EHDR_ASSERT
|
#undef EHDR_ASSERT
|
||||||
|
|
||||||
|
@ -81,23 +81,94 @@ static int load_shdr(struct object *object)
|
||||||
return M_SUCCESS;
|
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
|
* Map the phdr
|
||||||
*/
|
*/
|
||||||
static int load_phdr(struct object *object)
|
static int load_phdr(struct object *object)
|
||||||
{
|
{
|
||||||
size_t phdr_len = B16(object->ehdr->e_phentsize) *
|
//size_t phdr_len = B16(object->ehdr->e_phentsize) *
|
||||||
B16(object->ehdr->e_phnum);
|
// 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);
|
|
||||||
|
|
||||||
if (BOUND_CHK(object, phdr_len, phdr_off)) {
|
//if (phdr_len < 1)
|
||||||
ERROR("cannot read phdr");
|
return create_phdr(object);
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
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->segments = malloc(sizeof(struct segment) *
|
||||||
object->segment_len);
|
object->segment_len);
|
||||||
|
|
||||||
|
@ -287,6 +358,8 @@ int object_load(struct object *object, char *path, uint32_t index)
|
||||||
object->mapped = NULL;
|
object->mapped = NULL;
|
||||||
object->name = path;
|
object->name = path;
|
||||||
object->index = index;
|
object->index = index;
|
||||||
|
object->phdr_local = false;
|
||||||
|
object->phdr_to_shdr_mapping = NULL;
|
||||||
|
|
||||||
/** load the file */
|
/** load the file */
|
||||||
if (map_file(object, path))
|
if (map_file(object, path))
|
||||||
|
@ -331,6 +404,10 @@ void object_free(struct object *obj)
|
||||||
free(obj->strtabs);
|
free(obj->strtabs);
|
||||||
if (obj->segments != NULL)
|
if (obj->segments != NULL)
|
||||||
free(obj->segments);
|
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)
|
if (obj->fd > 0)
|
||||||
close(obj->fd);
|
close(obj->fd);
|
||||||
if (obj->mapped != NULL && obj->mapped != MAP_FAILED)
|
if (obj->mapped != NULL && obj->mapped != MAP_FAILED)
|
||||||
|
|
54
mld/seg.c
54
mld/seg.c
|
@ -25,43 +25,29 @@ 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)
|
static int load_shdr(struct object *obj, struct segment *seg, size_t index)
|
||||||
{
|
{
|
||||||
bool found = false;
|
uint32_t shndx = obj->phdr_to_shdr_mapping[index];
|
||||||
|
Elf32_Shdr *hdr = &obj->shdr[shndx];
|
||||||
|
|
||||||
for (size_t i = 0; i < obj->shdr_len; i++) {
|
// get name
|
||||||
Elf32_Shdr *hdr = &obj->shdr[i];
|
uint32_t name = B32(hdr->sh_name);
|
||||||
|
if (name >= obj->shstrtab->len) {
|
||||||
// find shdr that matches the offset in phdr
|
ERROR("section name index [%d] out of bounds", name);
|
||||||
if (!PHDR_SHDR_MATCH(seg->phdr, hdr))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// get name
|
|
||||||
uint32_t name = B32(hdr->sh_name);
|
|
||||||
if (name >= obj->shstrtab->len) {
|
|
||||||
ERROR("section name index [%d] out of bounds", name);
|
|
||||||
return M_ERROR;
|
|
||||||
}
|
|
||||||
seg->name = &obj->shstrtab->data[name];
|
|
||||||
|
|
||||||
// map bytes
|
|
||||||
uint32_t len = B32(hdr->sh_size);
|
|
||||||
uint32_t off = B32(hdr->sh_offset);
|
|
||||||
seg->bytes = (unsigned char *) (obj->mapped + off);
|
|
||||||
|
|
||||||
if (BOUND_CHK(obj, len, off)) {
|
|
||||||
ERROR("cannot map seg %s:%d", seg->name, 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;
|
return M_ERROR;
|
||||||
}
|
}
|
||||||
|
seg->name = &obj->shstrtab->data[name];
|
||||||
|
|
||||||
|
// map bytes
|
||||||
|
uint32_t len = B32(hdr->sh_size);
|
||||||
|
uint32_t off = B32(hdr->sh_offset);
|
||||||
|
seg->bytes = (unsigned char *) (obj->mapped + off);
|
||||||
|
|
||||||
|
if (BOUND_CHK(obj, len, off)) {
|
||||||
|
ERROR("cannot map seg %s:%d", seg->name, index);
|
||||||
|
return M_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->shdr = hdr;
|
||||||
|
seg->shdr_idx = shndx;
|
||||||
|
|
||||||
return M_SUCCESS;
|
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)
|
if (strcmp(name, symname) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// ignore absolute symbols
|
||||||
|
if (B16(sym->st_shndx) == SHN_ABS)
|
||||||
|
continue;
|
||||||
|
|
||||||
// only allow retrevial of local variables from the
|
// only allow retrevial of local variables from the
|
||||||
// same object
|
// same object
|
||||||
if (sym->st_info >> 4 != STB_GLOBAL && symtab->map != NULL &&
|
if (sym->st_info >> 4 != STB_GLOBAL && symtab->map != NULL &&
|
||||||
|
|
Loading…
Reference in a new issue