xref: /openbsd/libexec/ld.so/arm/rtld_machine.c (revision 274d7c50)
1 /*	$OpenBSD: rtld_machine.c,v 1.37 2019/11/27 01:24:35 guenther Exp $ */
2 
3 /*
4  * Copyright (c) 2004 Dale Rahn
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28 
29 #define _DYN_LOADER
30 
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <sys/syscall.h>
34 #include <sys/unistd.h>
35 
36 #include <nlist.h>
37 #include <link.h>
38 
39 #include "syscall.h"
40 #include "archdep.h"
41 #include "resolve.h"
42 
43 int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
44 
45 void _dl_bind_start(void); /* XXX */
46 Elf_Addr _dl_bind(elf_object_t *object, int reloff);
47 
48 #define R_TYPE(x) R_ARM_ ## x
49 
50 int
51 _dl_md_reloc(elf_object_t *object, int rel, int relsz)
52 {
53 	long	i;
54 	long	numrel;
55 	long	relrel;
56 	Elf_Addr loff;
57 	Elf_Addr prev_value = 0;
58 	const Elf_Sym *prev_sym = NULL;
59 	Elf_Rel *rels;
60 
61 	loff = object->obj_base;
62 	numrel = object->Dyn.info[relsz] / sizeof(Elf_Rel);
63 	relrel = object->relcount;
64 	rels = (Elf_Rel *)(object->Dyn.info[rel]);
65 
66 	if (rels == NULL)
67 		return 0;
68 
69 	if (relrel > numrel)
70 		_dl_die("relcount > numrel: %ld > %ld", relrel, numrel);
71 
72 	/* tight loop for leading RELATIVE relocs */
73 	for (i = 0; i < relrel; i++, rels++) {
74 		Elf_Addr *where;
75 
76 		where = (Elf_Addr *)(rels->r_offset + loff);
77 		*where += loff;
78 	}
79 	for (; i < numrel; i++, rels++) {
80 		Elf_Addr *where, value;
81 		Elf_Word type;
82 		const Elf_Sym *sym;
83 		const char *symn;
84 
85 		where = (Elf_Addr *)(rels->r_offset + loff);
86 
87 		sym = object->dyn.symtab;
88 		sym += ELF_R_SYM(rels->r_info);
89 		symn = object->dyn.strtab + sym->st_name;
90 
91 		type = ELF_R_TYPE(rels->r_info);
92 		switch (type) {
93 		case R_TYPE(NONE):
94 		case R_TYPE(JUMP_SLOT):		/* shouldn't happen */
95 			continue;
96 
97 		case R_TYPE(RELATIVE):
98 			*where += loff;
99 			continue;
100 
101 		case R_TYPE(ABS32):
102 		case R_TYPE(GLOB_DAT):
103 			value = *where;
104 			break;
105 
106 		case R_TYPE(COPY):
107 		{
108 			struct sym_res sr;
109 
110 			sr = _dl_find_symbol(symn,
111 			    SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT,
112 			    sym, object);
113 			if (sr.sym == NULL)
114 				return 1;
115 
116 			value = sr.obj->obj_base + sr.sym->st_value;
117 			_dl_bcopy((void *)value, where, sym->st_size);
118 			continue;
119 		}
120 
121 		default:
122 			_dl_die("relocation error %d", type);
123 		}
124 
125 
126 		/* Finish the ABS32 and GLOB_DAT cases */
127 		if (sym->st_shndx != SHN_UNDEF &&
128 		    ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
129 			value += loff;
130 		} else if (sym == prev_sym) {
131 			value += prev_value;
132 		} else {
133 			struct sym_res sr;
134 
135 			sr = _dl_find_symbol(symn,
136 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
137 			    sym, object);
138 			if (sr.sym == NULL) {
139 				if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
140 					return 1;
141 				continue;
142 			}
143 			prev_sym = sym;
144 			prev_value = sr.obj->obj_base + sr.sym->st_value;
145 			value += prev_value;
146 		}
147 
148 		*where = value;
149 	}
150 
151 	return 0;
152 }
153 
154 static int
155 _dl_md_reloc_all_plt(elf_object_t *object, const Elf_Rel *reloc,
156     const Elf_Rel *rend)
157 {
158 	for (; reloc < rend; reloc++) {
159 		const Elf_Sym *sym;
160 		const char *symn;
161 		Elf_Addr *where;
162 		struct sym_res sr;
163 
164 		sym = object->dyn.symtab;
165 		sym += ELF_R_SYM(reloc->r_info);
166 		symn = object->dyn.strtab + sym->st_name;
167 
168 		sr = _dl_find_symbol(symn,
169 		    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object);
170 		if (sr.sym == NULL) {
171 			if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
172 				return 1;
173 			continue;
174 		}
175 
176 		where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
177 		*where = sr.obj->obj_base + sr.sym->st_value;
178 	}
179 
180 	return 0;
181 }
182 
183 /*
184  *	Relocate the Global Offset Table (GOT).
185  */
186 int
187 _dl_md_reloc_got(elf_object_t *object, int lazy)
188 {
189 	Elf_Addr	*pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
190 	const Elf_Rel	*reloc, *rend;
191 
192 	if (pltgot == NULL)
193 		return 0; /* it is possible to have no PLT/GOT relocations */
194 
195 	if (object->Dyn.info[DT_PLTREL] != DT_REL)
196 		return 0;
197 
198 	if (object->traced)
199 		lazy = 1;
200 
201 	reloc = (const Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
202 	rend = (const Elf_Rel *)((char *)reloc + object->Dyn.info[DT_PLTRELSZ]);
203 
204 	if (!lazy)
205 		return _dl_md_reloc_all_plt(object, reloc, rend);
206 
207 	/* Lazy */
208 	pltgot[1] = (Elf_Addr)object;
209 	pltgot[2] = (Elf_Addr)_dl_bind_start;
210 
211 	for (; reloc < rend; reloc++) {
212 		Elf_Addr *where;
213 		where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
214 		*where += object->obj_base;
215 	}
216 
217 	return 0;
218 }
219 
220 Elf_Addr
221 _dl_bind(elf_object_t *object, int relidx)
222 {
223 	Elf_Rel *rel;
224 	const Elf_Sym *sym;
225 	const char *symn;
226 	struct sym_res sr;
227 	int64_t cookie = pcookie;
228 	struct {
229 		struct __kbind param;
230 		Elf_Word newval;
231 	} buf;
232 
233 	rel = ((Elf_Rel *)object->Dyn.info[DT_JMPREL]) + (relidx);
234 
235 	sym = object->dyn.symtab;
236 	sym += ELF_R_SYM(rel->r_info);
237 	symn = object->dyn.strtab + sym->st_name;
238 
239 	sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
240 	    sym, object);
241 	if (sr.sym == NULL)
242 		_dl_die("lazy binding failed!");
243 
244 	buf.newval = sr.obj->obj_base + sr.sym->st_value;
245 
246 	if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn))
247 		return buf.newval;
248 
249 	buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rel->r_offset);
250 	buf.param.kb_size = sizeof(Elf_Word);
251 
252 	/* directly code the syscall, so that it's actually inline here */
253 	{
254 		register long syscall_num __asm("r12") = SYS_kbind;
255 		register void *arg1 __asm("r0") = &buf;
256 		register long  arg2 __asm("r1") = sizeof(buf);
257 		register long  arg3 __asm("r2") = 0xffffffff &  cookie;
258 		register long  arg4 __asm("r3") = 0xffffffff & (cookie >> 32);
259 
260 		__asm volatile("swi 0" : "+r" (arg1), "+r" (arg2)
261 		    : "r" (syscall_num), "r" (arg3), "r" (arg4)
262 		    : "cc", "memory");
263 	}
264 
265 	return buf.newval;
266 }
267