summaryrefslogtreecommitdiff
path: root/kexec
diff options
context:
space:
mode:
Diffstat (limited to 'kexec')
-rw-r--r--kexec/arch/ppc64/kexec-elf-rel-ppc64.c27
-rw-r--r--kexec/kexec-elf-rel.c10
2 files changed, 32 insertions, 5 deletions
diff --git a/kexec/arch/ppc64/kexec-elf-rel-ppc64.c b/kexec/arch/ppc64/kexec-elf-rel-ppc64.c
index 5fc2f87..9b191d0 100644
--- a/kexec/arch/ppc64/kexec-elf-rel-ppc64.c
+++ b/kexec/arch/ppc64/kexec-elf-rel-ppc64.c
@@ -144,6 +144,33 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type,
*(uint16_t *)location = (((uint64_t)value >> 48) & 0xffff);
break;
+ /* R_PPC64_REL16_HA and R_PPC64_REL16_LO are handled to support
+ * ABIv2 r2 assignment based on r12 for PIC executable.
+ * Here address is know so replace
+ * 0: addis 2,12,.TOC.-0b@ha
+ * addi 2,2,.TOC.-0b@l
+ * by
+ * lis 2,.TOC.@ha
+ * addi 2,2,.TOC.@l
+ */
+ case R_PPC64_REL16_HA:
+ /* check that we are dealing with the addis 2,12 instruction */
+ if (((*(uint32_t*)location) & 0xffff0000) != 0x3c4c0000)
+ die("Unexpected instruction for R_PPC64_REL16_HA");
+ value += my_r2(ehdr);
+ /* replacing by lis 2 */
+ *(uint32_t *)location = 0x3c400000 + ((value >> 16) & 0xffff);
+ break;
+
+ case R_PPC64_REL16_LO:
+ /* check that we are dealing with the addi 2,2 instruction */
+ if (((*(uint32_t*)location) & 0xffff0000) != 0x38420000)
+ die("Unexpected instruction for R_PPC64_REL16_LO");
+
+ value += my_r2(ehdr) - 4;
+ *(uint16_t *)location = value & 0xffff;
+ break;
+
default:
die("Unknown rela relocation: %lu\n", r_type);
break;
diff --git a/kexec/kexec-elf-rel.c b/kexec/kexec-elf-rel.c
index 020cab0..c625f30 100644
--- a/kexec/kexec-elf-rel.c
+++ b/kexec/kexec-elf-rel.c
@@ -379,12 +379,12 @@ int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
* Relocation Entries: If the index is STN_UNDEF,
* the undefined symbol index, the relocation uses 0
* as the "symbol value".
- * So, is this really an error condition to flag die?
+ * TOC symbols appear as undefined but should be
+ * resolved as well. Their type is STT_NOTYPE so allow
+ * such symbols to be processed.
*/
- /*
- die("Undefined symbol: %s\n", name);
- */
- continue;
+ if (ELF32_ST_TYPE(sym.st_info) != STT_NOTYPE)
+ die("Undefined symbol: %s\n", name);
}
sec_base = 0;
if (sym.st_shndx == SHN_COMMON) {