aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/link_elf.c10
-rw-r--r--sys/kern/link_elf_obj.c10
-rw-r--r--sys/sparc64/sparc64/elf_machdep.c47
-rw-r--r--sys/sys/linker.h1
4 files changed, 60 insertions, 8 deletions
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 998000551076..ea4f0dd2d772 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -1188,6 +1188,16 @@ link_elf_get_gp(linker_file_t lf)
}
#endif
+const Elf_Sym *
+elf_get_sym(linker_file_t lf, Elf_Word symidx)
+{
+ elf_file_t ef = (elf_file_t)lf;
+
+ if (symidx >= ef->nchains)
+ return (NULL);
+ return (ef->symtab + symidx);
+}
+
/*
* Symbol lookup function that can be used when the symbol index is known (ie
* in relocations). It uses the symbol index instead of doing a fully fledged
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index 998000551076..ea4f0dd2d772 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -1188,6 +1188,16 @@ link_elf_get_gp(linker_file_t lf)
}
#endif
+const Elf_Sym *
+elf_get_sym(linker_file_t lf, Elf_Word symidx)
+{
+ elf_file_t ef = (elf_file_t)lf;
+
+ if (symidx >= ef->nchains)
+ return (NULL);
+ return (ef->symtab + symidx);
+}
+
/*
* Symbol lookup function that can be used when the symbol index is known (ie
* in relocations). It uses the symbol index instead of doing a fully fledged
diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c
index 272b82338157..4889bc9ab881 100644
--- a/sys/sparc64/sparc64/elf_machdep.c
+++ b/sys/sparc64/sparc64/elf_machdep.c
@@ -131,10 +131,10 @@ static int reloc_target_flags[] = {
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */
- _RF_A| _RF_B|_RF_SZ(32) | _RF_RS(10), /* HI22 */
+ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 13 */
- _RF_A| _RF_B|_RF_SZ(32) | _RF_RS(0), /* LO10 */
+ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LO10 */
_RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */
_RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */
_RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */
@@ -144,8 +144,8 @@ static int reloc_target_flags[] = {
_RF_SZ(32) | _RF_RS(0), /* COPY */
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */
_RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */
- _RF_A| _RF_B|_RF_SZ(64) | _RF_RS(0), /* RELATIVE */
- _RF_S|_RF_A| _RF_U|_RF_SZ(32) | _RF_RS(0), /* UA_32 */
+ _RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0), /* RELATIVE */
+ _RF_S|_RF_A| _RF_U| _RF_SZ(32) | _RF_RS(0), /* UA_32 */
_RF_A| _RF_SZ(32) | _RF_RS(0), /* PLT32 */
_RF_A| _RF_SZ(32) | _RF_RS(10), /* HIPLT22 */
@@ -181,6 +181,22 @@ static int reloc_target_flags[] = {
_RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0), /* UA16 */
};
+#if 0
+static const char *reloc_names[] = {
+ "NONE", "RELOC_8", "RELOC_16", "RELOC_32", "DISP_8",
+ "DISP_16", "DISP_32", "WDISP_30", "WDISP_22", "HI22",
+ "22", "13", "LO10", "GOT10", "GOT13",
+ "GOT22", "PC10", "PC22", "WPLT30", "COPY",
+ "GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32", "PLT32",
+ "HIPLT22", "LOPLT10", "LOPLT10", "PCPLT22", "PCPLT32",
+ "10", "11", "64", "OLO10", "HH22",
+ "HM10", "LM22", "PC_HH22", "PC_HM10", "PC_LM22",
+ "WDISP16", "WDISP19", "GLOB_JMP", "7", "5", "6",
+ "DISP64", "PLT64", "HIX22", "LOX10", "H44", "M44",
+ "L44", "REGISTER", "UA64", "UA16"
+};
+#endif
+
#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0)
#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0)
#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0)
@@ -224,6 +240,7 @@ int
elf_reloc(linker_file_t lf, const void *data, int type)
{
const Elf_Rela *rela;
+ const Elf_Sym *sym;
Elf_Addr relocbase;
Elf_Half *where32;
Elf_Addr *where;
@@ -255,10 +272,24 @@ elf_reloc(linker_file_t lf, const void *data, int type)
value = rela->r_addend;
if (RELOC_RESOLVE_SYMBOL(rtype)) {
- addr = elf_lookup(lf, symidx, 1);
- if (addr == 0)
- return (-1);
- value += addr;
+ /*
+ * Work around what appears to be confusion between binutils
+ * and the v9 ABI. LO10 and HI22 relocations are listed as
+ * S + A, but for STB_LOCAL symbols it seems that the value
+ * in the Elf_Sym refered to by the symbol index is wrong,
+ * instead the value is in the addend field of the Elf_Rela
+ * record. So if the symbol is local don't look it up, just
+ * use the addend as its value and add in the relocbase.
+ */
+ sym = elf_get_sym(lf, symidx);
+ if (ELF_ST_BIND(sym->st_info) == STB_LOCAL)
+ value += relocbase;
+ else {
+ addr = elf_lookup(lf, symidx, 1);
+ if (addr == 0)
+ return (-1);
+ value += addr;
+ }
}
if (RELOC_PC_RELATIVE(rtype))
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
index 0090a5f7d7af..bd45a698438e 100644
--- a/sys/sys/linker.h
+++ b/sys/sys/linker.h
@@ -230,6 +230,7 @@ extern int kld_debug;
/* Support functions */
int elf_reloc(linker_file_t _lf, const void *_rel, int _type);
Elf_Addr elf_lookup(linker_file_t, Elf_Word, int);
+const Elf_Sym *elf_get_sym(linker_file_t _lf, Elf_Word _symidx);
/* values for type */
#define ELF_RELOC_REL 1