link_elf.c (ee900504cf6496ff421d8f1ff73de9550f11ed8f) link_elf.c (7035cf14ee3b658181facc80b72179e06a9a4f35)
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1998-2000 Doug Rabson
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions

--- 176 unchanged lines hidden (view full) ---

185#else
186 "elf64",
187#endif
188 link_elf_methods, sizeof(struct elf_file)
189};
190
191static int parse_dynamic(elf_file_t);
192static int relocate_file(elf_file_t);
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1998-2000 Doug Rabson
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions

--- 176 unchanged lines hidden (view full) ---

185#else
186 "elf64",
187#endif
188 link_elf_methods, sizeof(struct elf_file)
189};
190
191static int parse_dynamic(elf_file_t);
192static int relocate_file(elf_file_t);
193static int relocate_file1(elf_file_t ef, int (*elf_reloc_func)(
194 linker_file_t lf, Elf_Addr relocbase, const void *data,
195 int type, elf_lookup_fn lookup));
193static int link_elf_preload_parse_symbols(elf_file_t);
194
195static struct elf_set_head set_pcpu_list;
196#ifdef VIMAGE
197static struct elf_set_head set_vnet_list;
198#endif
199
200static void

--- 976 unchanged lines hidden (view full) ---

1177 if (ELF_R_SYM(r_info)) {
1178 ref = ef->symtab + ELF_R_SYM(r_info);
1179 return (ef->strtab + ref->st_name);
1180 }
1181 return (NULL);
1182}
1183
1184static int
196static int link_elf_preload_parse_symbols(elf_file_t);
197
198static struct elf_set_head set_pcpu_list;
199#ifdef VIMAGE
200static struct elf_set_head set_vnet_list;
201#endif
202
203static void

--- 976 unchanged lines hidden (view full) ---

1180 if (ELF_R_SYM(r_info)) {
1181 ref = ef->symtab + ELF_R_SYM(r_info);
1182 return (ef->strtab + ref->st_name);
1183 }
1184 return (NULL);
1185}
1186
1187static int
1185relocate_file(elf_file_t ef)
1188relocate_file1(elf_file_t ef, int (*elf_reloc_func)(linker_file_t lf,
1189 Elf_Addr relocbase, const void *data, int type, elf_lookup_fn lookup))
1186{
1187 const Elf_Rel *rellim;
1188 const Elf_Rel *rel;
1189 const Elf_Rela *relalim;
1190 const Elf_Rela *rela;
1191 const char *symname;
1192
1193 /* Perform relocations without addend if there are any: */
1194 rel = ef->rel;
1195 if (rel != NULL) {
1196 rellim = (const Elf_Rel *)
1197 ((const char *)ef->rel + ef->relsize);
1198 while (rel < rellim) {
1190{
1191 const Elf_Rel *rellim;
1192 const Elf_Rel *rel;
1193 const Elf_Rela *relalim;
1194 const Elf_Rela *rela;
1195 const char *symname;
1196
1197 /* Perform relocations without addend if there are any: */
1198 rel = ef->rel;
1199 if (rel != NULL) {
1200 rellim = (const Elf_Rel *)
1201 ((const char *)ef->rel + ef->relsize);
1202 while (rel < rellim) {
1199 if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel,
1203 if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rel,
1200 ELF_RELOC_REL, elf_lookup)) {
1201 symname = symbol_name(ef, rel->r_info);
1202 printf("link_elf: symbol %s undefined\n", symname);
1203 return (ENOENT);
1204 }
1205 rel++;
1206 }
1207 }
1208
1209 /* Perform relocations with addend if there are any: */
1210 rela = ef->rela;
1211 if (rela != NULL) {
1212 relalim = (const Elf_Rela *)
1213 ((const char *)ef->rela + ef->relasize);
1214 while (rela < relalim) {
1204 ELF_RELOC_REL, elf_lookup)) {
1205 symname = symbol_name(ef, rel->r_info);
1206 printf("link_elf: symbol %s undefined\n", symname);
1207 return (ENOENT);
1208 }
1209 rel++;
1210 }
1211 }
1212
1213 /* Perform relocations with addend if there are any: */
1214 rela = ef->rela;
1215 if (rela != NULL) {
1216 relalim = (const Elf_Rela *)
1217 ((const char *)ef->rela + ef->relasize);
1218 while (rela < relalim) {
1215 if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela,
1219 if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rela,
1216 ELF_RELOC_RELA, elf_lookup)) {
1217 symname = symbol_name(ef, rela->r_info);
1218 printf("link_elf: symbol %s undefined\n",
1219 symname);
1220 return (ENOENT);
1221 }
1222 rela++;
1223 }
1224 }
1225
1226 /* Perform PLT relocations without addend if there are any: */
1227 rel = ef->pltrel;
1228 if (rel != NULL) {
1229 rellim = (const Elf_Rel *)
1230 ((const char *)ef->pltrel + ef->pltrelsize);
1231 while (rel < rellim) {
1220 ELF_RELOC_RELA, elf_lookup)) {
1221 symname = symbol_name(ef, rela->r_info);
1222 printf("link_elf: symbol %s undefined\n",
1223 symname);
1224 return (ENOENT);
1225 }
1226 rela++;
1227 }
1228 }
1229
1230 /* Perform PLT relocations without addend if there are any: */
1231 rel = ef->pltrel;
1232 if (rel != NULL) {
1233 rellim = (const Elf_Rel *)
1234 ((const char *)ef->pltrel + ef->pltrelsize);
1235 while (rel < rellim) {
1232 if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel,
1236 if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rel,
1233 ELF_RELOC_REL, elf_lookup)) {
1234 symname = symbol_name(ef, rel->r_info);
1235 printf("link_elf: symbol %s undefined\n",
1236 symname);
1237 return (ENOENT);
1238 }
1239 rel++;
1240 }
1241 }
1242
1243 /* Perform relocations with addend if there are any: */
1244 rela = ef->pltrela;
1245 if (rela != NULL) {
1246 relalim = (const Elf_Rela *)
1247 ((const char *)ef->pltrela + ef->pltrelasize);
1248 while (rela < relalim) {
1237 ELF_RELOC_REL, elf_lookup)) {
1238 symname = symbol_name(ef, rel->r_info);
1239 printf("link_elf: symbol %s undefined\n",
1240 symname);
1241 return (ENOENT);
1242 }
1243 rel++;
1244 }
1245 }
1246
1247 /* Perform relocations with addend if there are any: */
1248 rela = ef->pltrela;
1249 if (rela != NULL) {
1250 relalim = (const Elf_Rela *)
1251 ((const char *)ef->pltrela + ef->pltrelasize);
1252 while (rela < relalim) {
1249 if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela,
1253 if (elf_reloc_func(&ef->lf, (Elf_Addr)ef->address, rela,
1250 ELF_RELOC_RELA, elf_lookup)) {
1251 symname = symbol_name(ef, rela->r_info);
1252 printf("link_elf: symbol %s undefined\n",
1253 symname);
1254 return (ENOENT);
1255 }
1256 rela++;
1257 }
1258 }
1259
1260 return (0);
1261}
1262
1254 ELF_RELOC_RELA, elf_lookup)) {
1255 symname = symbol_name(ef, rela->r_info);
1256 printf("link_elf: symbol %s undefined\n",
1257 symname);
1258 return (ENOENT);
1259 }
1260 rela++;
1261 }
1262 }
1263
1264 return (0);
1265}
1266
1267static int
1268relocate_file(elf_file_t ef)
1269{
1270 int e;
1271
1272 e = relocate_file1(ef, elf_reloc);
1273#if defined(__i386__) || defined(__amd64__)
1274 if (e == 0)
1275 e = relocate_file1(ef, elf_reloc_ifunc);
1276#endif
1277 return (e);
1278}
1279
1263/*
1264 * Hash function for symbol table lookup. Don't even think about changing
1265 * this. It is specified by the System V ABI.
1266 */
1267static unsigned long
1268elf_hash(const char *name)
1269{
1270 const unsigned char *p = (const unsigned char *) name;

--- 41 unchanged lines hidden (view full) ---

1312 return (ENOENT);
1313 }
1314
1315 strp = ef->strtab + symp->st_name;
1316
1317 if (strcmp(name, strp) == 0) {
1318 if (symp->st_shndx != SHN_UNDEF ||
1319 (symp->st_value != 0 &&
1280/*
1281 * Hash function for symbol table lookup. Don't even think about changing
1282 * this. It is specified by the System V ABI.
1283 */
1284static unsigned long
1285elf_hash(const char *name)
1286{
1287 const unsigned char *p = (const unsigned char *) name;

--- 41 unchanged lines hidden (view full) ---

1329 return (ENOENT);
1330 }
1331
1332 strp = ef->strtab + symp->st_name;
1333
1334 if (strcmp(name, strp) == 0) {
1335 if (symp->st_shndx != SHN_UNDEF ||
1336 (symp->st_value != 0 &&
1320 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
1337 (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
1338 ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC))) {
1321 *sym = (c_linker_sym_t) symp;
1322 return (0);
1323 }
1324 return (ENOENT);
1325 }
1326
1327 symnum = ef->chains[symnum];
1328 }
1329
1330 /* If we have not found it, look at the full table (if loaded) */
1331 if (ef->symtab == ef->ddbsymtab)
1332 return (ENOENT);
1333
1334 /* Exhaustive search */
1335 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
1336 strp = ef->ddbstrtab + symp->st_name;
1337 if (strcmp(name, strp) == 0) {
1338 if (symp->st_shndx != SHN_UNDEF ||
1339 (symp->st_value != 0 &&
1339 *sym = (c_linker_sym_t) symp;
1340 return (0);
1341 }
1342 return (ENOENT);
1343 }
1344
1345 symnum = ef->chains[symnum];
1346 }
1347
1348 /* If we have not found it, look at the full table (if loaded) */
1349 if (ef->symtab == ef->ddbsymtab)
1350 return (ENOENT);
1351
1352 /* Exhaustive search */
1353 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
1354 strp = ef->ddbstrtab + symp->st_name;
1355 if (strcmp(name, strp) == 0) {
1356 if (symp->st_shndx != SHN_UNDEF ||
1357 (symp->st_value != 0 &&
1340 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
1358 (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
1359 ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC))) {
1341 *sym = (c_linker_sym_t) symp;
1342 return (0);
1343 }
1344 return (ENOENT);
1345 }
1346 }
1347
1348 return (ENOENT);
1349}
1350
1351static int
1352link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
1353 linker_symval_t *symval)
1354{
1360 *sym = (c_linker_sym_t) symp;
1361 return (0);
1362 }
1363 return (ENOENT);
1364 }
1365 }
1366
1367 return (ENOENT);
1368}
1369
1370static int
1371link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
1372 linker_symval_t *symval)
1373{
1355 elf_file_t ef = (elf_file_t) lf;
1356 const Elf_Sym* es = (const Elf_Sym*) sym;
1374 elf_file_t ef;
1375 const Elf_Sym *es;
1376 caddr_t val;
1357
1377
1378 ef = (elf_file_t)lf;
1379 es = (const Elf_Sym *)sym;
1358 if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) {
1359 symval->name = ef->strtab + es->st_name;
1380 if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) {
1381 symval->name = ef->strtab + es->st_name;
1360 symval->value = (caddr_t) ef->address + es->st_value;
1382 val = (caddr_t)ef->address + es->st_value;
1383 if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
1384 val = ((caddr_t (*)(void))val)();
1385 symval->value = val;
1361 symval->size = es->st_size;
1362 return (0);
1363 }
1364 if (ef->symtab == ef->ddbsymtab)
1365 return (ENOENT);
1366 if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
1367 symval->name = ef->ddbstrtab + es->st_name;
1386 symval->size = es->st_size;
1387 return (0);
1388 }
1389 if (ef->symtab == ef->ddbsymtab)
1390 return (ENOENT);
1391 if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
1392 symval->name = ef->ddbstrtab + es->st_name;
1368 symval->value = (caddr_t) ef->address + es->st_value;
1393 val = (caddr_t)ef->address + es->st_value;
1394 if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
1395 val = ((caddr_t (*)(void))val)();
1396 symval->value = val;
1369 symval->size = es->st_size;
1370 return (0);
1371 }
1372 return (ENOENT);
1373}
1374
1375static int
1376link_elf_search_symbol(linker_file_t lf, caddr_t value,

--- 93 unchanged lines hidden (view full) ---

1470{
1471 elf_file_t ef = (elf_file_t)file;
1472 const Elf_Sym *symp;
1473 int i, error;
1474
1475 /* Exhaustive search */
1476 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
1477 if (symp->st_value != 0 &&
1397 symval->size = es->st_size;
1398 return (0);
1399 }
1400 return (ENOENT);
1401}
1402
1403static int
1404link_elf_search_symbol(linker_file_t lf, caddr_t value,

--- 93 unchanged lines hidden (view full) ---

1498{
1499 elf_file_t ef = (elf_file_t)file;
1500 const Elf_Sym *symp;
1501 int i, error;
1502
1503 /* Exhaustive search */
1504 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
1505 if (symp->st_value != 0 &&
1478 ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
1506 (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
1507 ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
1479 error = callback(ef->ddbstrtab + symp->st_name, opaque);
1480 if (error != 0)
1481 return (error);
1482 }
1483 }
1484 return (0);
1485}
1486

--- 4 unchanged lines hidden (view full) ---

1491 linker_symval_t symval;
1492 elf_file_t ef = (elf_file_t)file;
1493 const Elf_Sym* symp;
1494 int i, error;
1495
1496 /* Exhaustive search */
1497 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
1498 if (symp->st_value != 0 &&
1508 error = callback(ef->ddbstrtab + symp->st_name, opaque);
1509 if (error != 0)
1510 return (error);
1511 }
1512 }
1513 return (0);
1514}
1515

--- 4 unchanged lines hidden (view full) ---

1520 linker_symval_t symval;
1521 elf_file_t ef = (elf_file_t)file;
1522 const Elf_Sym* symp;
1523 int i, error;
1524
1525 /* Exhaustive search */
1526 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
1527 if (symp->st_value != 0 &&
1499 ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
1528 (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
1529 ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
1500 error = link_elf_symbol_values(file,
1501 (c_linker_sym_t) symp, &symval);
1502 if (error != 0)
1503 return (error);
1504 error = callback(file, i, &symval, opaque);
1505 if (error != 0)
1506 return (error);
1507 }

--- 142 unchanged lines hidden (view full) ---

1650
1651 *strtab = ef->ddbstrtab;
1652
1653 if (*strtab == NULL)
1654 return (0);
1655
1656 return (ef->ddbstrcnt);
1657}
1530 error = link_elf_symbol_values(file,
1531 (c_linker_sym_t) symp, &symval);
1532 if (error != 0)
1533 return (error);
1534 error = callback(file, i, &symval, opaque);
1535 if (error != 0)
1536 return (error);
1537 }

--- 142 unchanged lines hidden (view full) ---

1680
1681 *strtab = ef->ddbstrtab;
1682
1683 if (*strtab == NULL)
1684 return (0);
1685
1686 return (ef->ddbstrcnt);
1687}
1688
1689#if defined(__i386__) || defined(__amd64__)
1690void
1691link_elf_ireloc(caddr_t kmdp)
1692{
1693 struct elf_file eff;
1694 elf_file_t ef;
1695
1696 ef = &eff;
1697 bzero(ef, sizeof(*ef));
1698 ef->modptr = kmdp;
1699 ef->dynamic = (Elf_Dyn *)&_DYNAMIC;
1700 parse_dynamic(ef);
1701 ef->address = 0;
1702 link_elf_preload_parse_symbols(ef);
1703 relocate_file1(ef, elf_reloc_ifunc);
1704}
1705#endif