From 93f0189f14a575fbc64dd170afabbfdba63c441c Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Katsuyoshi" Date: Thu, 2 Jul 2026 18:12:22 +0900 Subject: [PATCH] remap symbol indexes after sorting symtab --- lib/caotral/linker/builder.rb | 23 +++++++++++++------- sample/C/mixed_external_and_libc_functions.c | 7 ++++++ test/caotral/linker/symbol_remap_test.rb | 19 ++++++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 sample/C/mixed_external_and_libc_functions.c diff --git a/lib/caotral/linker/builder.rb b/lib/caotral/linker/builder.rb index f0e3d4e..c5c3e3c 100644 --- a/lib/caotral/linker/builder.rb +++ b/lib/caotral/linker/builder.rb @@ -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!( @@ -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 @@ -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] @@ -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) diff --git a/sample/C/mixed_external_and_libc_functions.c b/sample/C/mixed_external_and_libc_functions.c new file mode 100644 index 0000000..1b61378 --- /dev/null +++ b/sample/C/mixed_external_and_libc_functions.c @@ -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(); +} diff --git a/test/caotral/linker/symbol_remap_test.rb b/test/caotral/linker/symbol_remap_test.rb index 7d232d0..981ec3a 100644 --- a/test/caotral/linker/symbol_remap_test.rb +++ b/test/caotral/linker/symbol_remap_test.rb @@ -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