Skip to content

Commit

Permalink
Fix up relocations properly while compacting the binary
Browse files Browse the repository at this point in the history
  • Loading branch information
Victorious3 committed Nov 2, 2023
1 parent bb21ee6 commit 7340efa
Showing 1 changed file with 49 additions and 35 deletions.
84 changes: 49 additions & 35 deletions bfd_merge.pr
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ type Section = struct {
}

type Relocations = struct {
offset: size_t
count: size_t
reloc: **s_reloc_cache_entry
src: &Vector(&Section)
// TODO It would take less memory to have some sort of range based data structure
// Because all we do here is add the same object to it in a loop
origin: &Vector(&Object)
}

export def hash(sec: &Section) -> uint64 {
Expand All @@ -41,6 +42,19 @@ def find_symbol(o: &Object, name: Str) -> &Symbol {
return null
}

def find_symbol(o: &Object, origin: &Object, section: &Section, reloc: *s_reloc_cache_entry) -> &Symbol {
let addr = reloc.address !int64
for var sym in o.symbols {
let loc = sym.location !int64
if sym.origin == origin and sym.section == section {
if addr >= loc and addr < loc + sym.size {
return sym
}
}
}
return null
}

def delete_symbol(o: &Object, name: Str) {
for var i in 0..o.symbols.length {
let sym = o.symbols[i]
Expand Down Expand Up @@ -78,11 +92,13 @@ def delete(obj: &Object) {
}

type Symbol = struct {
origin: &Object
name: Str
symbol: *s_bfd_symbol
section: &Section
size: size_t
offset: size_t // Offset based on deleted sections
offset: int64 // Offset based on deleted sections
location: size_t // Original location based on the offset within a file
}

def bfd_asymbol_value(sy: *s_bfd_symbol) -> size_t {
Expand Down Expand Up @@ -118,7 +134,7 @@ def merge_section(res: &Object, obj_a: &Object, name: Str) {
new_sec.alignment_power = a_sec.section.alignment_power

let section = { section = new_sec, name = section_name, offsets = map::make(type &Section, size_t), size = 0 } !&Section
section.relocations.src = vector::make(type &Section)
section.relocations.origin = vector::make(type &Object)
res.sections[name] = section
}

Expand Down Expand Up @@ -153,9 +169,12 @@ def merge_section_data(res: &Object, obj_a: &Object, name: Str) {
let rel = relent[i]
let sym_name = make_string((@rel.sym_ptr_ptr).name)
let sym = find_symbol(obj_a, sym_name)
new_sec.relocations.src.push(sym.section)
rel.address += offset
}

for var i in 0..count {
new_sec.relocations.origin.push(obj_a)
}
}

free(relent)
Expand All @@ -182,17 +201,12 @@ def write_section_data(res: &Object, name: Str) {
for var i in 0..count {
let rel = relent[i]
let sym_name = make_string((@rel.sym_ptr_ptr).name)
let sym = find_symbol(res, sym_name)
let src_sec = sec.relocations.src[i]
var offset: size_t = sym.offset
let sym = find_symbol(res, sec.relocations.origin[i], sec, rel)
rel.sym_ptr_ptr = *find_symbol(res, sym_name).symbol

if src_sec {
let dst_sec = res.sections[src_sec.name]
offset = dst_sec.offsets[src_sec]
if sym {
rel.address += sym.offset
}

rel.sym_ptr_ptr = *sym.symbol
rel.addend += offset
}
res.bfd.xvec._bfd_set_reloc(res.bfd, sec.section, relent, count !uint)
}
Expand Down Expand Up @@ -233,41 +247,34 @@ def load_symbols(res: &Object) {
}
}

let out_sym = { sym_name, sym, section, size } !&Symbol
let out_sym = { res, sym_name, sym, section, size } !&Symbol
res.symbols.push(out_sym)
res.sym_size += 1
i += 1
}
}

def remove_symbol(res: &Object, name: Str) {
if find_symbol(res, name) == null { return }
// returns the difference in size when a symbol is deleted
def remove_symbol(res: &Object, name: Str) -> int {
if find_symbol(res, name) == null { return 0 }
let sym = find_symbol(res, name)
let sec = sym.section

delete_symbol(res, name)

// TODO Can't compact sections due to relative branching
/*if sec {
var size_diff = 0
if sec {
// Purge the symbol from the section
let data = allocate(sec.size - sym.size)
memcopy(sec.data, data, sym.symbol.value)
memcopy(sec.data ++ sym.symbol.value ++ sym.size, data ++ sym.symbol.value, sec.size - sym.symbol.value - sym.size)
free(sec.data)

sec.data = data

// Update section offsets
for var off_sec in @sec.offsets.keys() {
let offset = sec.offsets[off_sec]
if offset >= sym.symbol.value {
sec.offsets[off_sec] = offset - sym.size
}
}

// Actually shrink the section
sec.size -= sym.size
}*/
size_diff -= sym.size
}

var i = 0
while i < res.sym_size {
Expand All @@ -288,14 +295,17 @@ def remove_symbol(res: &Object, name: Str) {
res.symtab = symtab
res.sym_size -= 1

/*if sec {
if sec {
for var sym2 in res.symbols {
// Offset symbols
if sym.section and sym2.symbol.value > sym.symbol.value and sym.section == sym2.section {
sym2.symbol.value -= sym.size
sym2.offset -= sym.size
}
}
}*/
}

return size_diff
}

// TODO There are in fact ways to do this without a string compare but it doesn't seem to work
Expand Down Expand Up @@ -324,7 +334,7 @@ def copy_symbols(to: &Object, frm: &Object) {
let section = frm.sections[sym.section.name] if sym.section else null
let to_section = to.sections[sym.section.name] if sym.section else null

var offset: size_t = 0
var offset: int64 = 0
if to_section and to_section.offsets.contains(section) {
offset = to_section.offsets[section]
}
Expand All @@ -339,7 +349,7 @@ def copy_symbols(to: &Object, frm: &Object) {
new_sym.value = sym.symbol.value + offset

to.symtab[i] = new_sym
let symbol = { name, new_sym, to_section, sym.size } !&Symbol
let symbol = { frm, name, new_sym, to_section, sym.size, offset, sym.symbol.value } !&Symbol

if not is_und_section(sym.symbol.section) {
if find_symbol(to, name) != null {
Expand All @@ -355,8 +365,9 @@ def copy_symbols(to: &Object, frm: &Object) {
}
}

var size_diff = 0
for var name in @duplicates.keys() {
remove_symbol(to, name)
size_diff += remove_symbol(to, name)
}

to.symtab = reallocate(to.symtab, size_of *s_bfd_symbol * (frm.sym_size + duplicates.size)) !**s_bfd_symbol
Expand All @@ -369,6 +380,9 @@ def copy_symbols(to: &Object, frm: &Object) {
sym.symbol.value += entry.symbol.section.offsets[entry.from_section]
}

sym.symbol.value = sym.symbol.value !int + size_diff
sym.offset += size_diff

to.symbols.push(sym)
to.symtab[to.sym_size] = sym.symbol
to.sym_size += 1
Expand Down

0 comments on commit 7340efa

Please sign in to comment.