- Add support for TLS relocations.

- Emitt an error when encountering an unsupported and in case of the
  kernel also for unaligned relocations.
- Fix R_SPARC_LOX10 relocations. Apparently these are hardly ever used.
This commit is contained in:
Marius Strobl 2011-03-11 21:08:02 +00:00
parent cb32ba5229
commit 080ca1a51b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=219533
2 changed files with 150 additions and 14 deletions

View File

@ -66,6 +66,9 @@ __FBSDID("$FreeBSD$");
#define _RF_B 0x08000000 /* Load address relative */
#define _RF_U 0x04000000 /* Unaligned */
#define _RF_X 0x02000000 /* Bare symbols, needs proc */
#define _RF_D 0x01000000 /* Use dynamic TLS offset */
#define _RF_O 0x00800000 /* Use static TLS offset */
#define _RF_I 0x00400000 /* Use TLS object ID */
#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
#define _RF_RS(s) ( (s) & 0xff) /* right shift */
static const int reloc_target_flags[] = {
@ -126,6 +129,32 @@ static const int reloc_target_flags[] = {
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REGISTER */
_RF_S|_RF_A| _RF_U| _RF_SZ(64) | _RF_RS(0), /* UA64 */
_RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0), /* UA16 */
/* TLS */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* GD_HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GD_LO10 */
0, /* GD_ADD */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* GD_CALL */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LDM_HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LDM_LO10 */
0, /* LDM_ADD */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* LDM_CALL */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LDO_HIX22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LDO_LOX10 */
0, /* LDO_ADD */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* IE_HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* IE_LO10 */
0, /* IE_LD */
0, /* IE_LDX */
0, /* IE_ADD */
_RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(10), /* LE_HIX22 */
_RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(0), /* LE_LOX10 */
_RF_S| _RF_I| _RF_SZ(32) | _RF_RS(0), /* DTPMOD32 */
_RF_S| _RF_I| _RF_SZ(64) | _RF_RS(0), /* DTPMOD64 */
_RF_S|_RF_A| _RF_D| _RF_SZ(32) | _RF_RS(0), /* DTPOFF32 */
_RF_S|_RF_A| _RF_D| _RF_SZ(64) | _RF_RS(0), /* DTPOFF64 */
_RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(0), /* TPOFF32 */
_RF_S|_RF_A| _RF_O| _RF_SZ(64) | _RF_RS(0) /* TPOFF64 */
};
#if 0
@ -137,7 +166,11 @@ static const char *const reloc_names[] = {
"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"
"L44", "REGISTER", "UA64", "UA16", "GD_HI22", "GD_LO10", "GD_ADD",
"GD_CALL", "LDM_HI22", "LDMO10", "LDM_ADD", "LDM_CALL", "LDO_HIX22",
"LDO_LOX10", "LDO_ADD", "IE_HI22", "IE_LO10", "IE_LD", "IE_LDX",
"IE_ADD", "LE_HIX22", "LE_LOX10", "DTPMOD32", "DTPMOD64", "DTPOFF32",
"DTPOFF64", "TPOFF32", "TPOFF64"
};
#endif
@ -147,6 +180,9 @@ static const char *const reloc_names[] = {
#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0)
#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
#define RELOC_BARE_SYMBOL(t) ((reloc_target_flags[t] & _RF_X) != 0)
#define RELOC_USE_TLS_DOFF(t) ((reloc_target_flags[t] & _RF_D) != 0)
#define RELOC_USE_TLS_OFF(t) ((reloc_target_flags[t] & _RF_O) != 0)
#define RELOC_USE_TLS_ID(t) ((reloc_target_flags[t] & _RF_I) != 0)
#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
@ -176,6 +212,16 @@ static const long reloc_target_bitmask[] = {
_BM(22), _BM(13), /* HIX22, LOX10 */
_BM(22), _BM(10), _BM(13), /* H44, M44, L44 */
-1, -1, _BM(16), /* REGISTER, UA64, UA16 */
_BM(22), _BM(10), 0, _BM(30), /* GD_HI22, GD_LO10, GD_ADD, GD_CALL */
_BM(22), _BM(10), 0, /* LDM_HI22, LDMO10, LDM_ADD */
_BM(30), /* LDM_CALL */
_BM(22), _BM(10), 0, /* LDO_HIX22, LDO_LOX10, LDO_ADD */
_BM(22), _BM(10), 0, 0, /* IE_HI22, IE_LO10, IE_LD, IE_LDX */
0, /* IE_ADD */
_BM(22), _BM(13), /* LE_HIX22, LE_LOX10 */
_BM(32), -1, /* DTPMOD32, DTPMOD64 */
_BM(32), -1, /* DTPOFF32, DTPOFF64 */
_BM(32), -1 /* TPOFF32, TPOFF64 */
#undef _BM
};
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
@ -303,12 +349,22 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache,
if (type == R_SPARC_COPY)
return (0);
/* Ignore ADD and CALL relocations for dynamic TLS references. */
if (type == R_SPARC_TLS_GD_ADD || type == R_SPARC_TLS_GD_CALL ||
type == R_SPARC_TLS_LDM_ADD || type == R_SPARC_TLS_LDM_CALL ||
type == R_SPARC_TLS_LDO_ADD)
return (0);
/*
* Note: R_SPARC_UA16 must be numerically largest relocation type.
* Note: R_SPARC_TLS_TPOFF64 must be the numerically largest
* relocation type.
*/
if (type >= sizeof(reloc_target_bitmask) /
sizeof(*reloc_target_bitmask))
sizeof(*reloc_target_bitmask)) {
_rtld_error("%s: Unsupported relocation type %d in non-PLT "
"object\n", obj->path, type);
return (-1);
}
value = rela->r_addend;
@ -333,14 +389,37 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache,
if (def == NULL)
return (-1);
/* Add in the symbol's absolute address. */
value += (Elf_Addr)(defobj->relocbase + def->st_value);
if (RELOC_USE_TLS_ID(type))
value = (Elf_Addr)defobj->tlsindex;
else if (RELOC_USE_TLS_DOFF(type))
value += (Elf_Addr)def->st_value;
else if (RELOC_USE_TLS_OFF(type)) {
/*
* We lazily allocate offsets for static TLS as we
* see the first relocation that references the TLS
* block. This allows us to support (small amounts
* of) static TLS in dynamically loaded modules. If
* we run out of space, we generate an error.
*/
if (!defobj->tls_done &&
!allocate_tls_offset((Obj_Entry*)defobj)) {
_rtld_error("%s: No space available for "
"static Thread Local Storage", obj->path);
return (-1);
}
value += (Elf_Addr)(def->st_value -
defobj->tlsoffset);
} else {
/* Add in the symbol's absolute address. */
value += (Elf_Addr)(def->st_value +
defobj->relocbase);
}
}
if (type == R_SPARC_OLO10)
value = (value & 0x3ff) + ELF64_R_TYPE_DATA(rela->r_info);
if (type == R_SPARC_HIX22)
if (type == R_SPARC_HIX22 || type == R_SPARC_TLS_LE_HIX22)
value ^= 0xffffffffffffffff;
if (RELOC_PC_RELATIVE(type))
@ -365,6 +444,9 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache,
value >>= RELOC_VALUE_RIGHTSHIFT(type);
value &= mask;
if (type == R_SPARC_LOX10 || type == R_SPARC_TLS_LE_LOX10)
value |= 0x1c00;
if (RELOC_UNALIGNED(type)) {
/* Handle unaligned relocations. */
Elf_Addr tmp;

View File

@ -102,8 +102,7 @@ static Elf64_Brandinfo freebsd_brand_info = {
};
SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST,
(sysinit_cfunc_t) elf64_insert_brand_entry,
&freebsd_brand_info);
(sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_info);
static Elf64_Brandinfo freebsd_brand_oinfo = {
.brand = ELFOSABI_FREEBSD,
@ -118,9 +117,7 @@ static Elf64_Brandinfo freebsd_brand_oinfo = {
};
SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf64_insert_brand_entry,
&freebsd_brand_oinfo);
(sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_oinfo);
void
elf64_dump_thread(struct thread *td __unused, void *dst __unused,
@ -150,6 +147,9 @@ elf64_dump_thread(struct thread *td __unused, void *dst __unused,
#define _RF_B 0x08000000 /* Load address relative */
#define _RF_U 0x04000000 /* Unaligned */
#define _RF_X 0x02000000 /* Bare symbols, needs proc */
#define _RF_D 0x01000000 /* Use dynamic TLS offset */
#define _RF_O 0x00800000 /* Use static TLS offset */
#define _RF_I 0x00400000 /* Use TLS object ID */
#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
#define _RF_RS(s) ( (s) & 0xff) /* right shift */
static const int reloc_target_flags[] = {
@ -210,6 +210,34 @@ static const int reloc_target_flags[] = {
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REGISTER */
_RF_S|_RF_A| _RF_U| _RF_SZ(64) | _RF_RS(0), /* UA64 */
_RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0), /* UA16 */
#if 0
/* TLS */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* GD_HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GD_LO10 */
0, /* GD_ADD */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* GD_CALL */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LDM_HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LDM_LO10 */
0, /* LDM_ADD */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* LDM_CALL */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LDO_HIX22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LDO_LOX10 */
0, /* LDO_ADD */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* IE_HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* IE_LO10 */
0, /* IE_LD */
0, /* IE_LDX */
0, /* IE_ADD */
_RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(10), /* LE_HIX22 */
_RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(0), /* LE_LOX10 */
_RF_S| _RF_I| _RF_SZ(32) | _RF_RS(0), /* DTPMOD32 */
_RF_S| _RF_I| _RF_SZ(64) | _RF_RS(0), /* DTPMOD64 */
_RF_S|_RF_A| _RF_D| _RF_SZ(32) | _RF_RS(0), /* DTPOFF32 */
_RF_S|_RF_A| _RF_D| _RF_SZ(64) | _RF_RS(0), /* DTPOFF64 */
_RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(0), /* TPOFF32 */
_RF_S|_RF_A| _RF_O| _RF_SZ(64) | _RF_RS(0) /* TPOFF64 */
#endif
};
#if 0
@ -221,7 +249,11 @@ static const char *const reloc_names[] = {
"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"
"L44", "REGISTER", "UA64", "UA16", "GD_HI22", "GD_LO10", "GD_ADD",
"GD_CALL", "LDM_HI22", "LDMO10", "LDM_ADD", "LDM_CALL", "LDO_HIX22",
"LDO_LOX10", "LDO_ADD", "IE_HI22", "IE_LO10", "IE_LD", "IE_LDX",
"IE_ADD", "LE_HIX22", "LE_LOX10", "DTPMOD32", "DTPMOD64", "DTPOFF32",
"DTPOFF64", "TPOFF32", "TPOFF64"
};
#endif
@ -231,6 +263,9 @@ static const char *const reloc_names[] = {
#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0)
#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0)
#define RELOC_BARE_SYMBOL(t) ((reloc_target_flags[t] & _RF_X) != 0)
#define RELOC_USE_TLS_DOFF(t) ((reloc_target_flags[t] & _RF_D) != 0)
#define RELOC_USE_TLS_OFF(t) ((reloc_target_flags[t] & _RF_O) != 0)
#define RELOC_USE_TLS_ID(t) ((reloc_target_flags[t] & _RF_I) != 0)
#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
@ -260,6 +295,18 @@ static const long reloc_target_bitmask[] = {
_BM(22), _BM(13), /* HIX22, LOX10 */
_BM(22), _BM(10), _BM(13), /* H44, M44, L44 */
-1, -1, _BM(16), /* REGISTER, UA64, UA16 */
#if 0
_BM(22), _BM(10), 0, _BM(30), /* GD_HI22, GD_LO10, GD_ADD, GD_CALL */
_BM(22), _BM(10), 0, /* LDM_HI22, LDMO10, LDM_ADD */
_BM(30), /* LDM_CALL */
_BM(22), _BM(10), 0, /* LDO_HIX22, LDO_LOX10, LDO_ADD */
_BM(22), _BM(10), 0, 0, /* IE_HI22, IE_LO10, IE_LD, IE_LDX */
0, /* IE_ADD */
_BM(22), _BM(13), /* LE_HIX22, LE_LOX10 */
_BM(32), -1, /* DTPMOD32, DTPMOD64 */
_BM(32), -1, /* DTPOFF32, DTPOFF64 */
_BM(32), -1 /* TPOFF32, TPOFF64 */
#endif
#undef _BM
};
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
@ -311,11 +358,15 @@ elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
if (rtype == R_SPARC_JMP_SLOT || rtype == R_SPARC_COPY ||
rtype >= sizeof(reloc_target_bitmask) /
sizeof(*reloc_target_bitmask))
sizeof(*reloc_target_bitmask)) {
printf("kldload: unexpected relocation type %ld\n", rtype);
return (-1);
}
if (RELOC_UNALIGNED(rtype))
if (RELOC_UNALIGNED(rtype)) {
printf("kldload: unaligned relocation type %ld\n", rtype);
return (-1);
}
value = rela->r_addend;
@ -344,6 +395,9 @@ elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
value >>= RELOC_VALUE_RIGHTSHIFT(rtype);
value &= mask;
if (rtype == R_SPARC_LOX10)
value |= 0x1c00;
if (RELOC_TARGET_SIZE(rtype) > 32) {
*where &= ~mask;
*where |= value;