diff --git a/librz/bin/format/elf/elf.c b/librz/bin/format/elf/elf.c index 01b8e57b62..25de7060f8 100644 --- a/librz/bin/format/elf/elf.c +++ b/librz/bin/format/elf/elf.c @@ -371,6 +371,8 @@ static bool init(ELFOBJ *bin, RzBinObjectLoadOptions *options) { bin->bits = Elf_(rz_bin_elf_get_bits)(bin); bin->imports = Elf_(rz_bin_elf_analyse_imports)(bin); + bin->got_sym_id_off = ht_uu_new(); + rz_vector_free(sections); return true; @@ -428,6 +430,8 @@ void Elf_(rz_bin_elf_free)(RZ_NULLABLE ELFOBJ *bin) { rz_vector_free(bin->symbols); rz_vector_free(bin->imports); + ht_uu_free(bin->got_sym_id_off); + free(bin->elfctx); free(bin); } diff --git a/librz/bin/format/elf/elf.h b/librz/bin/format/elf/elf.h index 3a4dddc1fa..80318a15f7 100644 --- a/librz/bin/format/elf/elf.h +++ b/librz/bin/format/elf/elf.h @@ -245,6 +245,8 @@ struct Elf_(rz_bin_elf_obj_t) { RzVector /**/ *symbols; // RzVector RzVector /**/ *imports; // RzVector + + HtUU *got_sym_id_off; ///< symbol id to GOT offset map. }; // elf.c diff --git a/librz/bin/format/elf/elf_parser.c b/librz/bin/format/elf/elf_parser.c index b84e7a5c49..ba3d84c1e6 100644 --- a/librz/bin/format/elf/elf_parser.c +++ b/librz/bin/format/elf/elf_parser.c @@ -46,6 +46,9 @@ void elf_patch_relocs_elfobj_only(ELFOBJ *obj, RzBuffer *bin_buf, ut64 baseaddr) rz_bin_reloc_target_builder_free(targets); return; } + + fill_got_sym_id_off_map(obj); + RzBinElfReloc *reloc; ut64 got_addr = get_got_addr(obj); ut64 baddr = baseaddr; diff --git a/librz/bin/p/bin_elf.inc b/librz/bin/p/bin_elf.inc index 6da05439c8..7695553467 100644 --- a/librz/bin/p/bin_elf.inc +++ b/librz/bin/p/bin_elf.inc @@ -643,25 +643,13 @@ static ut64 get_got_addr(ELFOBJ *bin) { * the symbol has no indirection in the GOT. */ RZ_IPI ut64 Elf_(rz_bin_get_reloc_sym_offset_in_got)(RZ_NONNULL ELFOBJ *bin, ut64 sym_id) { - RzBinElfSection *got = Elf_(rz_bin_elf_get_section_with_name)(bin, ".got"); - if (!got) { - got = Elf_(rz_bin_elf_get_section_with_name)(bin, ".got.plt"); - if (!got) { - return UT64_MAX; - } + rz_return_val_if_fail(bin, UT64_MAX); + bool found = false; + ut64 offset = ht_uu_find(bin->got_sym_id_off, sym_id, &found); + if (!found) { + return UT64_MAX; } - // Search all entries of the GOT for the matching symbol id. - RzBinElfReloc *reloc; - rz_bin_elf_foreach_relocs(bin, reloc) { - if (!RZ_BETWEEN(got->rva, reloc->vaddr, got->rva + got->size)) { - // Not a GOT entry. - continue; - } - if (sym_id == reloc->sym) { - return reloc->offset; - } - } - return UT64_MAX; + return offset; } static void patch_relocs_obj(ELFOBJ *bin, ut64 baddr, RzBuffer *patch_buf) { @@ -725,6 +713,37 @@ static void patch_relocs_obj(ELFOBJ *bin, ut64 baddr, RzBuffer *patch_buf) { rz_buf_sparse_set_write_mode(bin->buf_patched, RZ_BUF_SPARSE_WRITE_MODE_THROUGH); } +static void fill_got_sym_id_off_map(ELFOBJ *obj) { + RzBinElfReloc *reloc; + if (ht_uu_size(obj->got_sym_id_off) > 0) { + // Already loaded by another ELF plugin callback. + return; + } + // Fill symbol id -> GOT offset map. + RzBinElfSection *got = Elf_(rz_bin_elf_get_section_with_name)(obj, ".got"); + if (got) { + rz_bin_elf_foreach_relocs(obj, reloc) { + if (!RZ_BETWEEN(got->rva, reloc->vaddr, got->rva + got->size)) { + // Not a GOT entry. + continue; + } + ht_uu_insert(obj->got_sym_id_off, reloc->sym, reloc->offset); + } + } + + got = Elf_(rz_bin_elf_get_section_with_name)(obj, ".got.plt"); + if (!got) { + return; + } + rz_bin_elf_foreach_relocs(obj, reloc) { + if (!RZ_BETWEEN(got->rva, reloc->vaddr, got->rva + got->size)) { + // Not a GOT entry. + continue; + } + ht_uu_insert(obj->got_sym_id_off, reloc->sym, reloc->offset); + } +} + static void patch_relocs(RzBinFile *bf, ELFOBJ *bin) { rz_return_if_fail(bf && bin); RzBinObject *obj = bf->o; @@ -744,6 +763,7 @@ static RzPVector /**/ *virtual_files(RzBinFile *bf) { if (!obj) { return r; } + fill_got_sym_id_off_map(obj); patch_relocs(bf, obj); // virtual file for reloc targets (where the relocs will point into) ut64 rtmsz = reloc_targets_vfile_size(bf, obj);