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
This commit is contained in:
parent
2eaa80698f
commit
169d513cb4
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=104072
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user