Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions lib/caotral/linker/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,9 @@ def build

old_syms = symtab_section.body.dup
symtab_section.body.sort_by! { |sym| sym.info >> 4 }
sym_indexes = {}
symtab_section.body.each_with_index { |sym, index| sym_indexes[sym.object_id] = index }
sym_index_map = old_syms.each_with_index.to_h { |sym, index| [index, sym_indexes[sym.object_id]] }
local_count = symtab_section.body.count { |sym| (sym.info >> 4) == SYMTAB_BIND[:locals] }

symtab_section.header.set!(
Expand Down Expand Up @@ -366,13 +369,6 @@ def build
end
end

resolved_index = {}
symtab_section.body.each_with_index do |sym, index|
name = sym.name_string
next if name.empty? || sym.shndx == 0 || sym.bind != 1
resolved_index[name] ||= index
end

sym_by_elf.each do |elf_obj, syms|
syms.each do |sym|
next if sym.shndx == 0
Expand All @@ -388,6 +384,17 @@ def build
defined_global_index[sym.name_string] ||= index
end

got_plt_offsets = got_plt_offsets.each_with_object({}) do |(old_index, offset), offsets|
new_index = sym_index_map[old_index]
offsets[new_index] = offset unless new_index.nil?
end

rela_plt_section.body.each do |rel|
new_index = sym_index_map[rel.sym]
next if new_index.nil?
rel.set!(info: (new_index << 32) | rel.type)
end

rel_sections.each do |rel_section|
rel_section.body.each do |rel|
orig_sym = old_syms[rel.sym]
Expand All @@ -396,7 +403,7 @@ def build
new_index = if orig_sym.shndx == 0 && defined_global_index.key?(name)
defined_global_index[orig_sym.name_string]
else
resolved_index[name]
sym_index_map[rel.sym]
end
next if new_index.nil?
rel.set!(info: (new_index << 32) | rel.type)
Expand Down
7 changes: 7 additions & 0 deletions sample/C/mixed_external_and_libc_functions.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extern int value_from_b(void);
extern int puts(const char *);

int main(void) {
puts("hello, glibc");
return value_from_b();
}
19 changes: 19 additions & 0 deletions test/caotral/linker/symbol_remap_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,23 @@ def test_remap_external_symbols
ec, hc = check_process(status.to_i)
assert_equal(ec, 42)
end

def test_remap_external_symbols_using_glibc
inputs = ["mixed_external_and_libc_functions.o", "symbol_remap_external_b.o"]
files = inputs.map { |f| "sample/C/#{f.sub(/\.o$/, ".c")}" }
execute = "combined_with_glibc"
@generated = [execute] + inputs
inputs.zip(files).each { |o, i| IO.popen(["gcc", "-fPIC", "-c", "-o", o, "%s" % i]).close }
Caotral::Linker.link!(inputs:, output: execute, linker: "self", pie: true, needed: ["libc.so.6"])
elf = Caotral::Binary::ELF::Reader.read!(input: execute)
dynsym = elf.find_by_name(".dynsym")
dynsym_names = dynsym.body.map(&:name_string)
assert_equal(4, dynsym.body.size)
assert_include(dynsym_names, "main")
assert_include(dynsym_names, "value_from_b")
assert_include(dynsym_names, "puts")
_o, _e, status = Open3.capture3("./#{execute}")
ec, hc = check_process(status.to_i)
assert_equal(ec, 42)
end
end
Loading