diff options
Diffstat (limited to 'trunk/src/arch-ppc64.c')
-rw-r--r-- | trunk/src/arch-ppc64.c | 63 |
1 files changed, 50 insertions, 13 deletions
diff --git a/trunk/src/arch-ppc64.c b/trunk/src/arch-ppc64.c index 6f9f644..a764b99 100644 --- a/trunk/src/arch-ppc64.c +++ b/trunk/src/arch-ppc64.c @@ -83,7 +83,8 @@ static int ppc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start, GElf_Addr adjust) { - if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE) + if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE + || GELF_R_TYPE (rela->r_info) == R_PPC64_IRELATIVE) { GElf_Addr val = read_ube64 (dso, rela->r_offset); @@ -92,6 +93,11 @@ ppc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start, if (rela->r_addend >= start) rela->r_addend += adjust; } + else if (GELF_R_TYPE (rela->r_info) == R_PPC64_JMP_IREL) + { + if (rela->r_addend >= start) + rela->r_addend += adjust; + } return 0; } @@ -162,7 +168,9 @@ ppc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela, DSO *dso = info->dso; GElf_Addr value; - if (GELF_R_TYPE (rela->r_info) == R_PPC64_NONE) + if (GELF_R_TYPE (rela->r_info) == R_PPC64_NONE + || GELF_R_TYPE (rela->r_info) == R_PPC64_IRELATIVE + || GELF_R_TYPE (rela->r_info) == R_PPC64_JMP_IREL) return 0; else if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE) { @@ -308,6 +316,7 @@ static int ppc64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela, char *buf, GElf_Addr dest_addr) { + GElf_Rela *ret; switch (GELF_R_TYPE (rela->r_info)) { case R_PPC64_ADDR64: @@ -322,6 +331,16 @@ ppc64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela, case R_PPC64_UADDR16: buf_write_be16 (buf, rela->r_addend); break; + case R_PPC64_IRELATIVE: + if (dest_addr == 0) + return 5; + ret = prelink_conflict_add_rela (info); + if (ret == NULL) + return 1; + ret->r_offset = dest_addr; + ret->r_info = GELF_R_INFO (0, R_PPC64_IRELATIVE); + ret->r_addend = rela->r_addend; + break; default: abort (); } @@ -439,16 +458,13 @@ ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info, int r_type; if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE - || GELF_R_TYPE (rela->r_info) == R_PPC64_NONE - || info->dso == dso) + || GELF_R_TYPE (rela->r_info) == R_PPC64_NONE) /* Fast path: nothing to do. */ return 0; conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info), GELF_R_TYPE (rela->r_info)); if (conflict == NULL) { - if (info->curtls == NULL) - return 0; switch (GELF_R_TYPE (rela->r_info)) { /* Even local DTPMOD and TPREL relocs need conflicts. */ @@ -458,18 +474,20 @@ ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info, case R_PPC64_TPREL16_LO: case R_PPC64_TPREL16_HI: case R_PPC64_TPREL16_HA: + if (info->curtls == NULL || info->dso == dso) + return 0; + break; + /* Similarly IRELATIVE relocations always need conflicts. */ + case R_PPC64_IRELATIVE: + case R_PPC64_JMP_IREL: break; default: return 0; } value = 0; } - else if (conflict->ifunc) - { - error (0, 0, "%s: STT_GNU_IFUNC not handled on PowerPC64 yet", - dso->filename); - return 1; - } + else if (info->dso == dso && !conflict->ifunc) + return 0; else { /* DTPREL wants to see only real conflicts, not lookups @@ -498,10 +516,17 @@ ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info, { case R_PPC64_GLOB_DAT: r_type = R_PPC64_ADDR64; - break; case R_PPC64_ADDR64: case R_PPC64_UADDR64: + if (conflict != NULL && conflict->ifunc) + r_type = R_PPC64_IRELATIVE; + break; + case R_PPC64_IRELATIVE: + case R_PPC64_JMP_IREL: + break; case R_PPC64_JMP_SLOT: + if (conflict != NULL && conflict->ifunc) + r_type = R_PPC64_JMP_IREL; break; case R_PPC64_ADDR32: case R_PPC64_UADDR32: @@ -640,6 +665,13 @@ ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info, r_type); return 1; } + if (conflict != NULL && conflict->ifunc + && r_type != R_PPC64_IRELATIVE && r_type != R_PPC64_JMP_IREL) + { + error (0, 0, "%s: relocation %d against IFUNC symbol", dso->filename, + (int) GELF_R_TYPE (rela->r_info)); + return 1; + } ret->r_info = GELF_R_INFO (0, r_type); ret->r_addend = value; return 0; @@ -668,8 +700,12 @@ ppc64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr) case R_PPC64_JMP_SLOT: /* .plt section will become SHT_NOBITS. */ return 0; + case R_PPC64_JMP_IREL: + /* .iplt section will become SHT_NOBITS. */ + return 0; case R_PPC64_RELATIVE: case R_PPC64_ADDR64: + case R_PPC64_IRELATIVE: write_be64 (dso, rela->r_offset, rela->r_addend); break; case R_PPC64_GLOB_DAT: @@ -766,6 +802,7 @@ ppc64_reloc_size (int reloc_type) case R_PPC64_DTPMOD64: case R_PPC64_DTPREL64: case R_PPC64_TPREL64: + case R_PPC64_IRELATIVE: return 8; default: break; |