1*b722ba42Sguenther /* $OpenBSD: rtld_machine.c,v 1.71 2022/01/08 06:49:41 guenther Exp $ */
255ed5643Sniklas
355ed5643Sniklas /*
455ed5643Sniklas * Copyright (c) 1999 Dale Rahn
555ed5643Sniklas * Copyright (c) 2001 Niklas Hallqvist
60e2cad47Sart * Copyright (c) 2001 Artur Grabowski
755ed5643Sniklas *
855ed5643Sniklas * Redistribution and use in source and binary forms, with or without
955ed5643Sniklas * modification, are permitted provided that the following conditions
1055ed5643Sniklas * are met:
1155ed5643Sniklas * 1. Redistributions of source code must retain the above copyright
1255ed5643Sniklas * notice, this list of conditions and the following disclaimer.
1355ed5643Sniklas * 2. Redistributions in binary form must reproduce the above copyright
1455ed5643Sniklas * notice, this list of conditions and the following disclaimer in the
1555ed5643Sniklas * documentation and/or other materials provided with the distribution.
1655ed5643Sniklas *
1755ed5643Sniklas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1855ed5643Sniklas * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1955ed5643Sniklas * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2055ed5643Sniklas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2155ed5643Sniklas * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2255ed5643Sniklas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2355ed5643Sniklas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2455ed5643Sniklas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2555ed5643Sniklas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2655ed5643Sniklas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2755ed5643Sniklas * SUCH DAMAGE.
2855ed5643Sniklas *
2955ed5643Sniklas */
3055ed5643Sniklas
3155ed5643Sniklas #define _DYN_LOADER
3255ed5643Sniklas
3355ed5643Sniklas #include <sys/types.h>
34*b722ba42Sguenther #include <sys/exec_elf.h>
357ad95679Sguenther #include <sys/syscall.h>
367ad95679Sguenther #include <sys/unistd.h>
37*b722ba42Sguenther
387ad95679Sguenther #include <machine/pal.h>
39*b722ba42Sguenther #include <machine/reloc.h>
4055ed5643Sniklas
41*b722ba42Sguenther #include "util.h"
4255ed5643Sniklas #include "resolve.h"
4355ed5643Sniklas
444131953dSmiod #define DT_PROC(n) ((n) - DT_LOPROC + DT_NUM)
454131953dSmiod
467ad95679Sguenther int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
477ad95679Sguenther
4855ed5643Sniklas int
_dl_md_reloc(elf_object_t * object,int rel,int relasz)4955ed5643Sniklas _dl_md_reloc(elf_object_t *object, int rel, int relasz)
5055ed5643Sniklas {
51dca21f58Sart long i;
52dca21f58Sart long numrela;
5388098a4dSguenther long relrel;
54e9cfe40cSmiod int fails = 0;
55e3b0f1d9Sguenther Elf_Addr loff;
56e3b0f1d9Sguenther Elf_Addr prev_value = 0;
5788098a4dSguenther const Elf_Sym *prev_sym = NULL;
58e3b0f1d9Sguenther Elf_RelA *relas;
5955ed5643Sniklas
60ce11e090Skurt loff = object->obj_base;
61e3b0f1d9Sguenther numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA);
6288098a4dSguenther relrel = rel == DT_RELA ? object->relacount : 0;
63e3b0f1d9Sguenther relas = (Elf_RelA *)(object->Dyn.info[rel]);
6455ed5643Sniklas
65bb87ac8eSart if (relas == NULL)
66e3b0f1d9Sguenther return 0;
6755ed5643Sniklas
683b50b772Sguenther if (relrel > numrela)
693b50b772Sguenther _dl_die("relacount > numrel: %ld > %ld", relrel, numrela);
7088098a4dSguenther
719e9d93fdSguenther if (! object->Dyn.info[DT_PROC(DT_ALPHA_PLTRO)])
729e9d93fdSguenther _dl_die("unsupported insecure PLT object");
739e9d93fdSguenther
7488098a4dSguenther /* tight loop for leading RELATIVE relocs */
7588098a4dSguenther for (i = 0; i < relrel; i++, relas++) {
7688098a4dSguenther Elf_Addr *r_addr;
7788098a4dSguenther
78e3b0f1d9Sguenther r_addr = (Elf_Addr *)(relas->r_offset + loff);
7988098a4dSguenther
8088098a4dSguenther /* Handle unaligned RELATIVE relocs */
8188098a4dSguenther if ((((Elf_Addr)r_addr) & 0x7) != 0) {
8288098a4dSguenther Elf_Addr tmp;
8388098a4dSguenther _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
8488098a4dSguenther tmp += loff;
8588098a4dSguenther _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
8688098a4dSguenther } else
8788098a4dSguenther *r_addr += loff;
8888098a4dSguenther }
8988098a4dSguenther for (; i < numrela; i++, relas++) {
90e3b0f1d9Sguenther Elf_Addr *r_addr;
91143e5accSguenther struct sym_res sr;
92e3b0f1d9Sguenther const Elf_Sym *sym;
9355ed5643Sniklas const char *symn;
9455ed5643Sniklas
95e3b0f1d9Sguenther r_addr = (Elf_Addr *)(relas->r_offset + loff);
9655ed5643Sniklas
97e3b0f1d9Sguenther if (ELF_R_SYM(relas->r_info) == 0xffffffff)
9855ed5643Sniklas continue;
9939b7d201Sderaadt
10055ed5643Sniklas
10155ed5643Sniklas sym = object->dyn.symtab;
102e3b0f1d9Sguenther sym += ELF_R_SYM(relas->r_info);
10355ed5643Sniklas symn = object->dyn.strtab + sym->st_name;
10455ed5643Sniklas
105e3b0f1d9Sguenther switch (ELF_R_TYPE(relas->r_info)) {
10655ed5643Sniklas case R_TYPE(REFQUAD):
107143e5accSguenther sr = _dl_find_symbol(symn,
1080acae5e5Sdrahn SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
109143e5accSguenther sym, object);
110143e5accSguenther if (sr.sym == NULL)
111dca21f58Sart goto resolve_failed;
112143e5accSguenther *r_addr += sr.obj->obj_base + sr.sym->st_value +
113143e5accSguenther relas->r_addend;
11455ed5643Sniklas break;
11555ed5643Sniklas case R_TYPE(RELATIVE):
11657b5f4bcSart /*
11757b5f4bcSart * There is a lot of unaligned RELATIVE
11857b5f4bcSart * relocs generated by gcc in the exception handlers.
11957b5f4bcSart */
12057b5f4bcSart if ((((Elf_Addr) r_addr) & 0x7) != 0) {
12157b5f4bcSart Elf_Addr tmp;
12257b5f4bcSart #if 0
1232c65dbe9Sart _dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr,
1242c65dbe9Sart ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff);
12557b5f4bcSart #endif
12657b5f4bcSart _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
12757b5f4bcSart tmp += loff;
12857b5f4bcSart _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
12939b7d201Sderaadt } else
130dca21f58Sart *r_addr += loff;
13155ed5643Sniklas break;
13255ed5643Sniklas case R_TYPE(JMP_SLOT):
133143e5accSguenther sr = _dl_find_symbol(symn,
1340acae5e5Sdrahn SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
135143e5accSguenther sym, object);
136143e5accSguenther if (sr.sym == NULL)
137dca21f58Sart goto resolve_failed;
138143e5accSguenther *r_addr = sr.obj->obj_base + sr.sym->st_value +
139143e5accSguenther relas->r_addend;
14055ed5643Sniklas break;
14155ed5643Sniklas case R_TYPE(GLOB_DAT):
14288098a4dSguenther if (sym == prev_sym) {
14388098a4dSguenther *r_addr = prev_value + relas->r_addend;
14488098a4dSguenther break;
14588098a4dSguenther }
146143e5accSguenther sr = _dl_find_symbol(symn,
1470acae5e5Sdrahn SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
148143e5accSguenther sym, object);
149143e5accSguenther if (sr.sym == NULL)
150dca21f58Sart goto resolve_failed;
15188098a4dSguenther prev_sym = sym;
152143e5accSguenther prev_value = sr.obj->obj_base + sr.sym->st_value;
15388098a4dSguenther *r_addr = prev_value + relas->r_addend;
15455ed5643Sniklas break;
15555ed5643Sniklas case R_TYPE(NONE):
15655ed5643Sniklas break;
15755ed5643Sniklas default:
158d9d17dbfSderaadt _dl_die("%s: unsupported relocation '%s' %lld at %p",
1593b50b772Sguenther object->load_name, symn,
160e3b0f1d9Sguenther ELF_R_TYPE(relas->r_info), (void *)r_addr);
16155ed5643Sniklas }
162dca21f58Sart continue;
163dca21f58Sart resolve_failed:
16406462af4Sdrahn if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
165dca21f58Sart fails++;
16655ed5643Sniklas }
167f6193deeSguenther __asm volatile("imb" : : : "memory");
168f7991f91Sart
169e3b0f1d9Sguenther return fails;
17055ed5643Sniklas }
17155ed5643Sniklas
17255ed5643Sniklas /*
1732c65dbe9Sart * Resolve a symbol at run-time.
1742c65dbe9Sart */
1755b36bcefSderaadt Elf_Addr
_dl_bind(elf_object_t * object,int reloff)1765b36bcefSderaadt _dl_bind(elf_object_t *object, int reloff)
1772c65dbe9Sart {
1782c65dbe9Sart Elf_RelA *rela;
179143e5accSguenther struct sym_res sr;
180143e5accSguenther const Elf_Sym *sym;
1812c65dbe9Sart const char *symn;
1827ad95679Sguenther uint64_t cookie = pcookie;
1837ad95679Sguenther struct {
1847ad95679Sguenther struct __kbind param;
1857ad95679Sguenther Elf_Addr newval;
1867ad95679Sguenther } buf;
1872c65dbe9Sart
1882c65dbe9Sart rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff);
189b42aa5e0Sdrahn
1902c65dbe9Sart sym = object->dyn.symtab;
191e3b0f1d9Sguenther sym += ELF_R_SYM(rela->r_info);
1922c65dbe9Sart symn = object->dyn.strtab + sym->st_name;
1932c65dbe9Sart
194143e5accSguenther sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
195143e5accSguenther sym, object);
196143e5accSguenther if (sr.sym == NULL)
1973b50b772Sguenther _dl_die("lazy binding failed!");
198b42aa5e0Sdrahn
199143e5accSguenther buf.newval = sr.obj->obj_base + sr.sym->st_value + rela->r_addend;
200ae398163Smiod
201143e5accSguenther if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn))
202e3b0f1d9Sguenther return buf.newval;
2037ad95679Sguenther
2047ad95679Sguenther buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rela->r_offset);
2057ad95679Sguenther buf.param.kb_size = sizeof(Elf_Addr);
2067ad95679Sguenther
2077ad95679Sguenther /* directly code the syscall, so that it's actually inline here */
2087ad95679Sguenther {
2097ad95679Sguenther register long syscall_num __asm("$0") /* v0 */ = SYS_kbind;
2107ad95679Sguenther register void *arg1 __asm("$16") /* a0 */ = &buf;
2117ad95679Sguenther register long arg2 __asm("$17") /* a1 */ = sizeof(buf);
2127ad95679Sguenther register long arg3 __asm("$18") /* a2 */ = cookie;
2137ad95679Sguenther
2147ad95679Sguenther __asm volatile( "call_pal %1" : "+r" (syscall_num)
2157ad95679Sguenther : "i" (PAL_OSF1_callsys), "r" (arg1), "r" (arg2),
2167ad95679Sguenther "r" (arg3) : "$19", "$20", "memory");
21791d8decdSdrahn }
21891d8decdSdrahn
219e3b0f1d9Sguenther return buf.newval;
2202c65dbe9Sart }
2212c65dbe9Sart
222c9db2c6cSguenther void _dl_bind_start(void) __dso_hidden; /* XXX */
2239e9d93fdSguenther
2242c65dbe9Sart /*
2250e2cad47Sart * Relocate the Global Offset Table (GOT).
22655ed5643Sniklas */
227e9cfe40cSmiod int
_dl_md_reloc_got(elf_object_t * object,int lazy)22855ed5643Sniklas _dl_md_reloc_got(elf_object_t *object, int lazy)
22955ed5643Sniklas {
230e9cfe40cSmiod int fails = 0;
2312c65dbe9Sart Elf_Addr *pltgot;
23291d8decdSdrahn
233e23a26ffSguenther if (object->Dyn.info[DT_PLTREL] != DT_RELA)
234e3b0f1d9Sguenther return 0;
235e23a26ffSguenther
2362c65dbe9Sart pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
2372c65dbe9Sart
2389e9d93fdSguenther if (!lazy || pltgot == NULL) {
239e9cfe40cSmiod fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
240ab7fd747Sdrahn } else {
2418e012c2aSkurt if (object->obj_base != 0) {
24286c5e2bdSart int i, size;
24386c5e2bdSart Elf_Addr *addr;
24486c5e2bdSart Elf_RelA *rela;
24586c5e2bdSart
246ab7fd747Sdrahn size = object->Dyn.info[DT_PLTRELSZ] /
247ab7fd747Sdrahn sizeof(Elf_RelA);
24886c5e2bdSart rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
24986c5e2bdSart
25086c5e2bdSart for (i = 0; i < size; i++) {
251ce11e090Skurt addr = (Elf_Addr *)(object->obj_base +
252ab7fd747Sdrahn rela[i].r_offset);
253ce11e090Skurt *addr += object->obj_base;
25486c5e2bdSart }
25586c5e2bdSart }
256c9db2c6cSguenther pltgot[0] = (Elf_Addr)_dl_bind_start;
2574131953dSmiod pltgot[1] = (Elf_Addr)object;
2584131953dSmiod }
259e23a26ffSguenther
260e3b0f1d9Sguenther return fails;
26155ed5643Sniklas }
262