1 /* $NetBSD: kobj_machdep.c,v 1.6 2024/01/18 03:36:24 msaitoh Exp $ */
2
3 /*-
4 * Copyright (c) 2014,2023 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas of 3am Software Foundry, and by Nick Hudson.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33
34 __RCSID("$NetBSD: kobj_machdep.c,v 1.6 2024/01/18 03:36:24 msaitoh Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kobj_impl.h>
39 #include <sys/kobj.h>
40 #include <sys/exec.h>
41 #include <sys/exec_elf.h>
42
43 #include <riscv/locore.h>
44
45 struct hi20 {
46 void *where;
47 long addend;
48 bool local;
49 } last_hi20;
50
51 static int
kobj_findhi20(kobj_t ko,uintptr_t relocbase,bool local,const Elf_Rela * lo12,Elf_Addr * hi20addr)52 kobj_findhi20(kobj_t ko, uintptr_t relocbase, bool local, const Elf_Rela *lo12,
53 Elf_Addr *hi20addr)
54 {
55 const Elf_Rela *relalim;
56 const Elf_Rela *rela;
57 /*
58 * Find the relocation section.
59 */
60 for (size_t i = 0; i < ko->ko_nrela; i++) {
61 rela = ko->ko_relatab[i].rela;
62 if (rela == NULL) {
63 continue;
64 }
65 relalim = rela + ko->ko_relatab[i].nrela;
66
67 /* Check that the relocation is in this section */
68 if (lo12 < rela || relalim < lo12)
69 continue;
70
71 /*
72 * Now find the HI20 relocation from the LO12 relocation
73 * address (hi20addr)
74 */
75 for (; rela < relalim; rela++) {
76 Elf_Addr * const where =
77 (Elf_Addr *)(relocbase + rela->r_offset);
78
79 if (where != hi20addr) {
80 continue;
81 }
82 /* Found the referenced HI20 relocation */
83 uintptr_t symidx = ELF_R_SYM(rela->r_info);
84 #if 0
85 if (symidx >= ko->ko_symcnt) {
86 continue;
87 }
88 #endif
89 /*
90 * If this symbol doesn't is global and we're doing
91 * the local symbols at this point then we can't
92 * resolve it yet, so tell our caller.
93 */
94 const Elf_Sym *sym = kobj_symbol(ko, symidx);
95 if (local && ELF_ST_BIND(sym->st_info) != STB_LOCAL) {
96 last_hi20.local = false;
97 return 1;
98 }
99
100 last_hi20.local = true;
101
102 Elf_Addr addr;
103 const int error = kobj_sym_lookup(ko, symidx, &addr);
104 if (error)
105 return -1;
106
107 long addend = rela->r_addend; /* needs to be signed */
108 addend -= (intptr_t)where;
109
110 last_hi20.where = where;
111 last_hi20.addend = addend;
112 addend += addr;
113
114 return 0;
115 }
116 }
117 return -1;
118 }
119
120
121 int
kobj_reloc(kobj_t ko,uintptr_t relocbase,const void * data,bool isrela,bool local)122 kobj_reloc(kobj_t ko, uintptr_t relocbase, const void *data, bool isrela,
123 bool local)
124 {
125 if (!isrela) {
126 panic("kobj_reloc: REL relocations not supported");
127 }
128
129 const Elf_Rela * const rela = (const Elf_Rela *)data;
130 Elf_Addr * const where = (Elf_Addr *)(relocbase + rela->r_offset);
131 long addend = rela->r_addend; /* needs to be signed */
132 uint32_t *wwhere = (uint32_t *)where;
133 uint16_t * const hwhere = (uint16_t *)where;
134 uint8_t * const bwhere = (uint8_t *)where;
135 const u_int rtype = ELF_R_TYPE(rela->r_info);
136 const u_int symidx = ELF_R_SYM(rela->r_info);
137 const Elf_Sym *sym = kobj_symbol(ko, symidx);
138
139 /*
140 * Check that we need to process this relocation in this pass.
141 * All relocations to local symols can be done in the first pass
142 * apart from PCREL_LO12 that reference a HI20 to a global symbol.
143 */
144 switch (rtype) {
145 case R_RISCV_PCREL_LO12_I:
146 case R_RISCV_PCREL_LO12_S:
147 if (addend != 0) {
148 printf("oops\n");
149 }
150 case R_RISCV_PCREL_HI20:
151 case R_RISCV_HI20:
152 break;
153 default:
154 /* Don't do other relocations again */
155 if (!local && ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
156 return 0;
157 }
158 }
159
160 /* Relocation calculation */
161 switch (rtype) {
162 case R_RISCV_NONE:
163 case R_RISCV_RELAX:
164 return 0;
165
166 case R_RISCV_BRANCH:
167 case R_RISCV_JAL:
168 // XXXNH eh? what's with the symidx test?'
169 if (symidx == 0)
170 break;
171 /* FALLTHROUGH */
172
173 case R_RISCV_CALL_PLT:
174 case R_RISCV_CALL:
175 case R_RISCV_PCREL_HI20:
176 case R_RISCV_RVC_BRANCH:
177 case R_RISCV_RVC_JUMP:
178 case R_RISCV_32_PCREL:
179 addend -= (intptr_t)where; /* A -= P */
180 /* FALLTHROUGH */
181
182 #ifdef _LP64
183 case R_RISCV_64: /* doubleword64 S + A */
184 case R_RISCV_ADD64:
185 case R_RISCV_SUB64:
186 #endif
187 case R_RISCV_HI20:
188 case R_RISCV_PCREL_LO12_I:
189 case R_RISCV_PCREL_LO12_S:
190 case R_RISCV_LO12_I:
191 case R_RISCV_LO12_S:
192 case R_RISCV_ADD32:
193 case R_RISCV_ADD16:
194 case R_RISCV_ADD8:
195 case R_RISCV_SUB32:
196 case R_RISCV_SUB16:
197 case R_RISCV_SUB8:
198 case R_RISCV_SUB6:
199 case R_RISCV_SET32:
200 case R_RISCV_SET16:
201 case R_RISCV_SET8:
202 case R_RISCV_SET6: {
203 Elf_Addr addr;
204 const int error = kobj_sym_lookup(ko, symidx, &addr);
205 if (error) {
206 /*
207 * This is a fatal error in the 2nd pass, i.e.
208 * local == false
209 */
210 if (!local)
211 return -1;
212 return 0;
213 }
214
215 switch (rtype) {
216 case R_RISCV_PCREL_HI20:
217 case R_RISCV_HI20: {
218
219 // XXXNH why is this without middle?
220 last_hi20.addend = addend + addr;
221 last_hi20.where = where;
222 last_hi20.local = ELF_ST_BIND(sym->st_info) == STB_LOCAL;
223
224 /*
225 * If this is the 2nd pass then and the symbol is
226 * local then it's already been fixed up.
227 */
228 if (!local && last_hi20.local) {
229 // last_hi20.global = false;
230 return 0;
231 }
232 const uint32_t lobits = 12;
233 const uint32_t middle = 1U << (lobits - 1);
234
235 addend += addr + middle;
236 break;
237 }
238 case R_RISCV_PCREL_LO12_I:
239 case R_RISCV_PCREL_LO12_S: {
240 if (last_hi20.where != (void *)addr) {
241 int err = kobj_findhi20(ko, relocbase, local,
242 rela, (Elf_Addr *)addr);
243 if (err < 0)
244 return -1;
245 else if (err > 0) {
246 KASSERT(local);
247 return 0;
248 }
249 }
250 /*
251 * In the second pass if the HI20 symbol was local
252 * it was already processed.
253 */
254 if (!local && last_hi20.local) {
255 return 0;
256 }
257 addend = addend + (last_hi20.addend & __BITS(11,0));
258 break;
259 }
260 default:
261 addend += addr; /* A += S */
262 }
263 break;
264 }
265
266 default:
267 printf("%s: unexpected relocation type %u\n\n", __func__, rtype);
268 return -1;
269 }
270
271 /* Relocation memory update */
272 switch (rtype) {
273 case R_RISCV_64: /* word64 S + A */
274 *where = addend;
275 break;
276
277 case R_RISCV_32: /* word32 S + A */
278 case R_RISCV_SET32: /* word32 S + A */
279 case R_RISCV_32_PCREL: /* word32 S + A - P */
280 *wwhere = addend;
281 break;
282
283 case R_RISCV_SET16: /* word16 S + A */
284 *hwhere = addend;
285 break;
286
287 case R_RISCV_SET8: /* word8 S + A */
288 *bwhere = addend;
289 break;
290
291 case R_RISCV_SET6: { /* word6 S + A */
292 const uint8_t mask = __BITS(5, 0);
293
294 *bwhere = (*bwhere & ~mask) | __SHIFTIN(addend, mask);
295 break;
296 }
297
298 case R_RISCV_ADD64: /* word64 V + S + A */
299 *where += addend;
300 break;
301
302 case R_RISCV_ADD32: /* word32 V + S + A */
303 *wwhere += addend;
304 break;
305
306 case R_RISCV_ADD16: /* word16 V + S + A */
307 *hwhere += addend;
308 break;
309
310 case R_RISCV_ADD8: /* word8 V + S + A */
311 *bwhere += addend;
312 break;
313
314 case R_RISCV_SUB64: /* word64 V - S - A */
315 *where -= addend;
316 break;
317
318 case R_RISCV_SUB32: /* word32 V - S - A */
319 *wwhere -= addend;
320 break;
321
322 case R_RISCV_SUB16: /* word16 V - S - A */
323 *hwhere -= addend;
324 break;
325
326 case R_RISCV_SUB8: /* word8 V - S - A */
327 *bwhere -= addend;
328 break;
329
330 case R_RISCV_SUB6: /* word6 V - S - A */
331 // XXXNH
332 *bwhere -= addend;
333 break;
334
335 case R_RISCV_BRANCH: {
336 /*
337 * B-type
338 * 31 | 30 25 | ... | 11 8 | 7 | ...
339 * imm[12] | imm[10:5] | ... | imm[4:1] | imm[11] | ...
340 */
341
342 const uint32_t immA = __SHIFTOUT(addend, __BIT(12));
343 const uint32_t immB = __SHIFTOUT(addend, __BITS(10, 5));
344 const uint32_t immC = __SHIFTOUT(addend, __BITS( 4, 1));
345 const uint32_t immD = __SHIFTOUT(addend, __BIT(11));
346 addend =
347 __SHIFTIN(immA, __BIT(31)) |
348 __SHIFTIN(immB, __BITS(30, 25)) |
349 __SHIFTIN(immC, __BITS(11, 8)) |
350 __SHIFTIN(immD, __BIT(7));
351 const uint32_t mask = __BITS(31, 25) | __BITS(11, 7);
352
353 *wwhere = (*wwhere & ~mask) | addend;
354 break;
355 }
356
357 case R_RISCV_JAL: {
358 /*
359 * J-type
360 * 31 | 30 21 | 20 | 19 12 | ...
361 * imm[20] | imm[10:1] | imm[11] | imm[19:12] | ...
362 */
363
364 const uint32_t immA = __SHIFTOUT(addend, __BIT(20));
365 const uint32_t immB = __SHIFTOUT(addend, __BITS(10, 1));
366 const uint32_t immC = __SHIFTOUT(addend, __BIT(11));
367 const uint32_t immD = __SHIFTOUT(addend, __BITS(19, 12));
368 addend =
369 __SHIFTIN(immA, __BIT(31)) |
370 __SHIFTIN(immB, __BITS(30, 21)) |
371 __SHIFTIN(immC, __BIT(20)) |
372 __SHIFTIN(immD, __BITS(19,12));
373 /* FALLTHROUGH */
374 }
375
376 case R_RISCV_HI20: /* LUI/AUIPC (S + A - P) */
377 case R_RISCV_PCREL_HI20: { /* LUI/AUIPC (S + A - P) */
378 /*
379 * U-Type
380 * 31 12 | ...
381 * imm[31:12] | ...
382 */
383 const uint32_t mask = __BITS(31, 12);
384 *wwhere = (addend & mask) | (*wwhere & ~mask);
385 break;
386 }
387 case R_RISCV_PCREL_LO12_I:
388 case R_RISCV_LO12_I: { /* low12 I-type instructions */
389 /*
390 * I-Type
391 * 31 20 | ...
392 * imm[11:0] | ...
393 */
394
395 *wwhere += ((addend) << 20);
396 break;
397 }
398 case R_RISCV_PCREL_LO12_S:
399 case R_RISCV_LO12_S: { /* low12 S-type instructions */
400 /*
401 * S-type
402 *
403 * 31 25 | ... | 11 7 | ...
404 * imm[11:5] | ... | imm[4:0] | ...
405 *
406 */
407 const uint32_t immA = __SHIFTOUT(addend, __BITS(11, 5));
408 const uint32_t immB = __SHIFTOUT(addend, __BITS( 4, 0));
409 const uint32_t mask = __BITS(31, 25) | __BITS(11, 7);
410 addend =
411 __SHIFTIN(immA, __BITS(31, 25)) |
412 __SHIFTIN(immB, __BITS(11, 7));
413 *wwhere = (*wwhere & ~mask) | addend;
414 break;
415 }
416 case R_RISCV_CALL:
417 case R_RISCV_CALL_PLT: {
418 /*
419 * U-type
420 *
421 * 31 12 | ...
422 * imm[31:12] | ...
423 *
424 *
425 * I-type
426 *
427 * 31 25 | ...
428 * imm[11:0] | ...
429 */
430 // XXXNH better name...
431 const int32_t check = (int32_t)addend >> 20;
432 if (check == 0 || check == -1) {
433 // This falls into the range for the JAL instruction.
434 /*
435 * J-type
436 * 31 | 30 21 | 20 | 19 12 | ...
437 * imm[20] | imm[10:1] | imm[11] | imm[19:12] | ...
438 */
439
440 const uint32_t immA = __SHIFTOUT(addend, __BIT(20));
441 const uint32_t immB = __SHIFTOUT(addend, __BITS(10, 1));
442 const uint32_t immC = __SHIFTOUT(addend, __BIT(11));
443 const uint32_t immD = __SHIFTOUT(addend, __BITS(19, 12));
444 addend =
445 __SHIFTIN(immA, __BIT(31)) |
446 __SHIFTIN(immB, __BITS(30, 21)) |
447 __SHIFTIN(immC, __BIT(20)) |
448 __SHIFTIN(immD, __BITS(19,12));
449
450 // Convert the auipc/jalr to a jal/nop
451 wwhere[0] = addend | (wwhere[1] & 0xf80) | 0x6f;
452 wwhere[1] = 0x00000013; // nop (addi x0, x0, 0)
453 printf("%s: %s where (%p) [0] -> %x, [1] -> %x\n", __func__,
454 "R_RISCV_CALL", wwhere, wwhere[0], wwhere[1]);
455 break;
456 }
457 wwhere[0] = ((addend + 0x800) & 0xfffff000)
458 | (wwhere[0] & 0xfff);
459 wwhere[1] = (addend << 20) | (wwhere[1] & 0x000fffff);
460 printf("%s: %s where (%p) [0] -> %x, [1] -> %x\n", __func__,
461 "R_RISCV_CALL", wwhere, wwhere[0], wwhere[1]);
462
463 break;
464 }
465 case R_RISCV_RVC_BRANCH: {
466 /*
467 * CB-type
468 *
469 * ... | 12 10 | ... | 6 5 3 2 | ...
470 * ... | offset[8|4:3] | ... | offset[7:6|2:1|5] | ...
471 */
472
473 const uint16_t immA = __SHIFTOUT(addend, __BIT(8));
474 const uint16_t immB = __SHIFTOUT(addend, __BITS(4, 3));
475 const uint16_t immC = __SHIFTOUT(addend, __BITS(7, 6));
476 const uint16_t immD = __SHIFTOUT(addend, __BITS(2, 1));
477 const uint16_t immE = __SHIFTOUT(addend, __BIT(5));
478 const uint16_t mask = __BITS(12, 10) | __BITS(6, 2);
479 addend =
480 __SHIFTIN(immA, __BIT(12)) |
481 __SHIFTIN(immB, __BITS(11, 10)) |
482 __SHIFTIN(immC, __BITS( 6, 5)) |
483 __SHIFTIN(immD, __BITS( 4, 3)) |
484 __SHIFTIN(immE, __BIT(2));
485 *hwhere = (*hwhere & ~mask) | addend;
486 break;
487 }
488
489 case R_RISCV_RVC_JUMP: {
490 /*
491 * CJ-type
492 *
493 * ... | 12 2 | ...
494 * ... | offset[11|4|9:8|10|6|7|3:1|5] | ...
495 */
496
497 const uint16_t immA = __SHIFTOUT(addend, __BIT(11));
498 const uint16_t immB = __SHIFTOUT(addend, __BIT(4));
499 const uint16_t immC = __SHIFTOUT(addend, __BITS(9, 8));
500 const uint16_t immD = __SHIFTOUT(addend, __BIT(10));
501 const uint16_t immE = __SHIFTOUT(addend, __BIT(6));
502 const uint16_t immF = __SHIFTOUT(addend, __BIT(7));
503 const uint16_t immG = __SHIFTOUT(addend, __BITS(3, 1));
504 const uint16_t immH = __SHIFTOUT(addend, __BIT(5));
505 const uint16_t mask = __BITS(12, 2);
506 addend =
507 __SHIFTIN(immA, __BIT(12)) |
508 __SHIFTIN(immB, __BIT(11)) |
509 __SHIFTIN(immC, __BITS(10, 9)) |
510 __SHIFTIN(immD, __BIT(8)) |
511 __SHIFTIN(immE, __BIT(7)) |
512 __SHIFTIN(immF, __BIT(6)) |
513 __SHIFTIN(immG, __BITS(5, 3)) |
514 __SHIFTIN(immH, __BIT(2));
515 *hwhere = (*hwhere & ~mask) | addend;
516 break;
517 }
518
519 case R_RISCV_RVC_LUI: {
520 /*
521 * CI-type
522 *
523 * ... | 12 | ... | 6 2 | ...
524 * ... | offset[17] | ... | offset[16:12] | ...
525 */
526
527 const uint16_t immA = __SHIFTOUT(addend, __BIT(17));
528 const uint16_t immB = __SHIFTOUT(addend, __BITS(16,12));
529 const uint16_t mask = __BIT(12) | __BITS(6, 2);
530 addend =
531 __SHIFTIN(immA, __BIT(12)) |
532 __SHIFTIN(immB, __BITS(6, 2));
533 *hwhere = (*hwhere & ~mask) | addend;
534 break;
535 }
536
537 default:
538 printf("Unexpected relocation type %d\n", rtype);
539 }
540
541 return 0;
542 }
543
544 int
kobj_machdep(kobj_t ko,void * base,size_t size,bool load)545 kobj_machdep(kobj_t ko, void *base, size_t size, bool load)
546 {
547 if (load)
548 __asm("fence rw,rw; fence.i");
549
550 return 0;
551 }
552