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 45struct hi20 { 46 void *where; 47 long addend; 48 bool local; 49} last_hi20; 50 51static int 52kobj_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 121int 122kobj_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 544int 545kobj_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