From dbb3aa41f9d83b29e758b13dae40d430fafb5da0 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 31 Jan 2024 20:46:04 +0800 Subject: [PATCH] Add support for more AArch64 ELF relocs (#1699) * Add support for more AArch64 ELF relocs Co-authored-by: Giovanni <561184+wargio@users.noreply.github.com> * Update prev and add more relocs --------- Co-authored-by: Giovanni <561184+wargio@users.noreply.github.com> Co-authored-by: Pavel I --- librz/bin/format/elf/elf_relocs.c | 3 +- librz/bin/p/bin_elf.inc | 116 +++++++++++++++++++++++++++--- librz/include/rz_types.h | 1 + test/db/formats/elf/elf-relarm | 70 +++++++++++++++--- 4 files changed, 169 insertions(+), 21 deletions(-) diff --git a/librz/bin/format/elf/elf_relocs.c b/librz/bin/format/elf/elf_relocs.c index 4ddfc5ec519..4ab81e9d733 100644 --- a/librz/bin/format/elf/elf_relocs.c +++ b/librz/bin/format/elf/elf_relocs.c @@ -117,7 +117,6 @@ static bool get_relocs_entry(ELFOBJ *bin, RzBinElfSection *section, RzVector /*< if (!get_reloc_entry(bin, &tmp, segment->offset + entry_offset, segment->mode)) { return false; } - fix_rva_and_offset(bin, &tmp, section); if (!rz_vector_push(relocs, &tmp)) { @@ -244,7 +243,7 @@ RZ_OWN RzVector /**/ *Elf_(rz_bin_elf_relocs_new)(RZ_NONNULL ELFO bool Elf_(rz_bin_elf_has_relocs)(RZ_NONNULL ELFOBJ *bin) { rz_return_val_if_fail(bin, false); - return bin->relocs; + return bin->relocs && (rz_vector_len(bin->relocs) > 0); } size_t Elf_(rz_bin_elf_get_relocs_count)(RZ_NONNULL ELFOBJ *bin) { diff --git a/librz/bin/p/bin_elf.inc b/librz/bin/p/bin_elf.inc index 8d2cfefb6b6..1f27c8add54 100644 --- a/librz/bin/p/bin_elf.inc +++ b/librz/bin/p/bin_elf.inc @@ -1020,6 +1020,14 @@ static void patch_reloc_hexagon(RZ_INOUT RzBuffer *buf_patched, const ut64 patch } } +// AARCH64-specific defines +// Take the PAGE component of an address or offset. +#define PG(x) ((x) & ~0xFFFULL) +#define PG_OFFSET(x) ((x)&0xFFFULL) +#define ADR_IMM_MASK1 (((1U << 2) - 1) << 29) +#define ADR_IMM_MASK2 (((1U << 19) - 1) << 5) +#define ADR_IMM_MASK3 (((1U << 19) - 1) << 2) + static void patch_reloc(struct Elf_(rz_bin_elf_obj_t) * obj, RzBinElfReloc *rel, ut64 S, ut64 B, ut64 L, ut64 GOT) { ut16 e_machine = obj->ehdr.e_machine; ut64 val = 0; @@ -1040,11 +1048,81 @@ static void patch_reloc(struct Elf_(rz_bin_elf_obj_t) * obj, RzBinElfReloc *rel, } rz_buf_write_ble32_at(obj->buf_patched, patch_addr, val, obj->big_endian); break; - case EM_AARCH64: - val = S + A; - rz_write_le64(buf, val); - rz_buf_write_at(obj->buf_patched, patch_addr, buf, 8); + case EM_AARCH64: { + ut32 keep; + ut32 nbytes = 4; + rz_buf_read_at(obj->buf_patched, patch_addr, buf, 8); + switch (rel->type) { + case RZ_AARCH64_ABS16: + val = S + A; + rz_write_le16(buf, val); + nbytes = 2; + break; + case RZ_AARCH64_ABS32: + val = S + A; + rz_write_le32(buf, val); + break; + case RZ_AARCH64_GLOB_DAT: + case RZ_AARCH64_ABS64: + case RZ_AARCH64_JUMP_SLOT: + val = S + A; + rz_write_le64(buf, val); + nbytes = 8; + break; + case RZ_AARCH64_PREL16: + val = S + A - P; + rz_write_le16(buf, val); + nbytes = 2; + break; + case RZ_AARCH64_PREL32: + val = S + A - P; + rz_write_le32(buf, val); + break; + case RZ_AARCH64_PREL64: + val = S + A - P; + rz_write_le64(buf, val); + nbytes = 8; + break; + case RZ_AARCH64_RELATIVE: + val = B + A; + rz_write_le64(buf, val); + nbytes = 8; + break; + case RZ_AARCH64_ADR_PREL_PG_HI21: + case RZ_AARCH64_ADR_PREL_PG_HI21_NC: + case RZ_AARCH64_ADR_GOT_PAGE: + // Reencode ADR imm + keep = rz_read_le32(buf) & ~(ADR_IMM_MASK1 | ADR_IMM_MASK2); + val = ((st64)(PG(S + A) - PG(P))) >> 12; + rz_write_le32(buf, keep | ((val & RZ_BIT_MASK32(2, 0)) << 29) | ((val & ADR_IMM_MASK3) << 3)); + break; + case RZ_AARCH64_JUMP26: + case RZ_AARCH64_CALL26: + // Reencode 26 bits of the offset + keep = rz_read_le32(buf) & ~RZ_BIT_MASK32(26, 0); + val = ((st64)(S + A - P)) >> 2; + rz_write_le32(buf, keep | (val & RZ_BIT_MASK32(26, 0))); + break; + case RZ_AARCH64_LDST8_ABS_LO12_NC: + case RZ_AARCH64_ADD_ABS_LO12_NC: + keep = rz_read_le32(buf) & ~(RZ_BIT_MASK32(12, 0) << 10); + val = PG_OFFSET(S + A); + rz_write_le32(buf, keep | ((val & RZ_BIT_MASK32(12, 0)) << 10)); + break; + case RZ_AARCH64_LD64_GOT_LO12_NC: + case RZ_AARCH64_LDST64_ABS_LO12_NC: + // Reencode LD/ST imm + keep = rz_read_le32(buf) & ~(RZ_BIT_MASK32(12, 0) << 10); + val = PG_OFFSET(S + A) >> 3; + rz_write_le32(buf, keep | ((val & RZ_BIT_MASK32(12, 0)) << 10)); + break; + default: + nbytes = 0; + break; + } + rz_buf_write_at(obj->buf_patched, patch_addr, buf, nbytes); break; + } case EM_PPC64: { int low = 0, word = 0; switch (rel->type) { @@ -1281,9 +1359,11 @@ static RzBinReloc *reloc_convert(ELFOBJ *bin, RzBinElfReloc *rel, ut64 GOT) { case RZ_386_PC16: ADD(16, -P); case RZ_386_8: ADD(8, 0); case RZ_386_PC8: ADD(8, -P); - case RZ_386_COPY: ADD(32, 0); // XXX: copy symbol at runtime + case RZ_386_COPY: ADD(32, 0); // copy symbol at runtime case RZ_386_IRELATIVE: r->is_ifunc = true; SET(32); - default: break; + default: + RZ_LOG_WARN("unimplemented ELF/X86_32 reloc type %d\n", rel->type); + break; } break; case EM_X86_64: @@ -1303,9 +1383,11 @@ static RzBinReloc *reloc_convert(ELFOBJ *bin, RzBinElfReloc *rel, ut64 GOT) { case RZ_X86_64_8: ADD(8, 0); case RZ_X86_64_PC8: ADD(8, -P); case RZ_X86_64_GOTPCREL: ADD(64, GOT - P); - case RZ_X86_64_COPY: ADD(64, 0); // XXX: copy symbol at runtime + case RZ_X86_64_COPY: ADD(64, 0); // copy symbol at runtime case RZ_X86_64_IRELATIVE: r->is_ifunc = true; SET(64); - default: break; + default: + RZ_LOG_WARN("unimplemented ELF/X86_64 reloc type %d\n", rel->type); + break; } break; case EM_ARM: @@ -1358,12 +1440,28 @@ static RzBinReloc *reloc_convert(ELFOBJ *bin, RzBinElfReloc *rel, ut64 GOT) { case EM_AARCH64: switch (rel->type) { case RZ_AARCH64_NONE: break; + case RZ_AARCH64_ABS64: ADD(64, 0); case RZ_AARCH64_ABS32: ADD(32, 0); case RZ_AARCH64_ABS16: ADD(16, 0); + case RZ_AARCH64_PREL64: ADD(64, 0); + case RZ_AARCH64_PREL32: ADD(32, 0); + case RZ_AARCH64_PREL16: ADD(16, 0); case RZ_AARCH64_GLOB_DAT: SET(64); case RZ_AARCH64_JUMP_SLOT: SET(64); case RZ_AARCH64_RELATIVE: ADD(64, B); - default: break; // reg relocations + case RZ_AARCH64_LDST8_ABS_LO12_NC: ADD(16, 0); + case RZ_AARCH64_ADD_ABS_LO12_NC: ADD(16, 0); + case RZ_AARCH64_JUMP26: ADD(32, 0); + case RZ_AARCH64_CALL26: ADD(32, 0); + case RZ_AARCH64_LDST64_ABS_LO12_NC: ADD(32, 0); + case RZ_AARCH64_LD64_GOT_LO12_NC: ADD(32, 0); + // Page-relative relocations + case RZ_AARCH64_ADR_GOT_PAGE: ADD(32, 0); + case RZ_AARCH64_ADR_PREL_PG_HI21: ADD(32, 0); + case RZ_AARCH64_ADR_PREL_PG_HI21_NC: ADD(32, 0); + default: + RZ_LOG_WARN("unimplemented ELF/AARCH64 reloc type %d\n", rel->type); + break; } break; case EM_PPC: diff --git a/librz/include/rz_types.h b/librz/include/rz_types.h index a879c2c9fd1..97423309ed7 100644 --- a/librz/include/rz_types.h +++ b/librz/include/rz_types.h @@ -293,6 +293,7 @@ static inline void *rz_new_copy(int size, const void *data) { ((char *)(((size_t)(v) + (t - 1)) & ~(t - 1))) #define RZ_BIT_MASK32(x, y) ((1UL << (x)) - (1UL << (y))) +#define RZ_BIT_MASK64(x, y) ((1ULL << (x)) - (1ULL << (y))) #define RZ_BIT_SET(x, y) (((ut8 *)x)[y >> 4] |= (1 << (y & 0xf))) #define RZ_BIT_UNSET(x, y) (((ut8 *)x)[y >> 4] &= ~(1 << (y & 0xf))) #define RZ_BIT_TOGGLE(x, y) (RZ_BIT_CHK(x, y) ? RZ_BIT_UNSET(x, y) : RZ_BIT_SET(x, y)) diff --git a/test/db/formats/elf/elf-relarm b/test/db/formats/elf/elf-relarm index 237d309efd0..411e4182ea7 100644 --- a/test/db/formats/elf/elf-relarm +++ b/test/db/formats/elf/elf-relarm @@ -116,7 +116,7 @@ EXPECT=<