summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjake <jake@FreeBSD.org>2002-09-27 23:12:53 +0000
committerjake <jake@FreeBSD.org>2002-09-27 23:12:53 +0000
commitc03e93ab3a4cf602e9fad9ef7bc7537a0cf96e8c (patch)
treeba3c4f5add825cc1d7164df7492430782b2070c4
parentd08d61cf7e649a1706432628cc516edea8878dd9 (diff)
downloadFreeBSD-src-c03e93ab3a4cf602e9fad9ef7bc7537a0cf96e8c.zip
FreeBSD-src-c03e93ab3a4cf602e9fad9ef7bc7537a0cf96e8c.tar.gz
Add a workaround for what seems to be confusion between binutils and the
sparc v9 ABI. The Elf_Rela records for local symbols appear to already have the symbol's value added in to the addend field, even though the ABI specifies we need to lookup the symbol and add its value too. This breaks text relocations in klds because the symbol's value is added twice, and the resulting address points off into nowhere land, so for now just use the addend. Tested by: rwatson
-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 9980005..ea4f0dd 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 9980005..ea4f0dd 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 272b823..4889bc9 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 0090a5f..bd45a69 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
OpenPOWER on IntegriCloud