#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kobj_machdep.c,v 1.8 2023/04/28 07:33:56 skrll Exp $");
#define ELFSIZE ARCH_ELFSIZE
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kobj.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
#define _RF_S 0x80000000
#define _RF_A 0x40000000
#define _RF_P 0x20000000
#define _RF_G 0x10000000
#define _RF_B 0x08000000
#define _RF_U 0x04000000
#define _RF_SZ(s) (((s) & 0xff) << 8)
#define _RF_RS(s) ( (s) & 0xff)
static const int reloc_target_flags[] = {
0,
_RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0),
_RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_G| _RF_SZ(32) | _RF_RS(0),
_RF_G| _RF_SZ(32) | _RF_RS(0),
_RF_G| _RF_SZ(32) | _RF_RS(10),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10),
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2),
_RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0),
_RF_SZ(32) | _RF_RS(0),
_RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0),
_RF_S|_RF_A| _RF_U| _RF_SZ(32) | _RF_RS(0),
_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_A| _RF_SZ(32) | _RF_RS(10),
_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0),
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10),
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(42),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(32),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(42),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(32),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2),
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A|_RF_P| _RF_SZ(64) | _RF_RS(0),
_RF_A| _RF_SZ(64) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(22),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(12),
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0),
_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0),
_RF_S|_RF_A| _RF_U| _RF_SZ(64) | _RF_RS(0),
_RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0),
};
#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)
#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_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
static const long reloc_target_bitmask[] = {
#define _BM(x) (~(-(1ULL << (x))))
0,
_BM(8), _BM(16), _BM(32),
_BM(8), _BM(16), _BM(32),
_BM(30), _BM(22),
_BM(22), _BM(22),
_BM(13), _BM(10),
_BM(10), _BM(13), _BM(22),
_BM(10), _BM(22),
_BM(30), 0,
_BM(32), _BM(32), _BM(32),
_BM(32), _BM(32),
_BM(22), _BM(10),
_BM(32), _BM(22), _BM(10),
_BM(10), _BM(11), -1,
_BM(13), _BM(22),
_BM(10), _BM(22),
_BM(22), _BM(10), _BM(22),
_BM(16), _BM(19),
-1,
_BM(7), _BM(5), _BM(6),
-1, -1,
_BM(22), _BM(13),
_BM(22), _BM(10), _BM(12),
-1, -1, _BM(16),
#undef _BM
};
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
int
kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data,
bool isrela, bool local)
{
const Elf_Rela *rela;
Elf_Word *where32;
Elf_Addr *where;
uintptr_t rtype, symidx;
Elf_Addr value;
Elf_Addr mask;
Elf_Addr addr;
vaddr_t base;
int error;
if (!isrela)
return -1;
rela = (const Elf_Rela *)data;
where = (Elf_Addr *)(relocbase + rela->r_offset);
where32 = (Elf_Word *)where;
rtype = ELF64_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
const Elf_Sym *sym = kobj_symbol(ko, symidx);
if (!local && ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
return 0;
}
if (rtype == R_SPARC_NONE)
return 0;
if ((rtype & 0x00ff) == R_SPARC_OLO10)
rtype = R_SPARC_OLO10;
if (rtype == R_SPARC_RELATIVE) {
kobj_stat(ko, &base, NULL);
value = rela->r_addend + (Elf_Addr)base;
where = (Elf_Addr *)((Elf_Addr)base + rela->r_offset);
*where = value;
return 0;
}
if (rtype == R_SPARC_JMP_SLOT || rtype == R_SPARC_COPY ||
rtype >= __arraycount(reloc_target_bitmask))
return -1;
if (RELOC_UNALIGNED(rtype))
return -1;
value = rela->r_addend;
if (RELOC_RESOLVE_SYMBOL(rtype)) {
error = kobj_sym_lookup(ko, symidx, &addr);
if (error)
return -1;
value += addr;
}
if (rtype == R_SPARC_OLO10)
value = (value & 0x3ff) + (((Elf64_Xword)rela->r_info<<32)>>40);
if (RELOC_PC_RELATIVE(rtype))
value -= (Elf_Addr)where;
if (RELOC_BASE_RELATIVE(rtype))
value += relocbase;
mask = RELOC_VALUE_BITMASK(rtype);
value >>= RELOC_VALUE_RIGHTSHIFT(rtype);
value &= mask;
if (RELOC_TARGET_SIZE(rtype) > 32) {
*where &= ~mask;
*where |= value;
} else {
*where32 &= ~mask;
*where32 |= value;
}
return 0;
}
int
kobj_machdep(kobj_t ko, void *base, size_t size, bool load)
{
return 0;
}