summaryrefslogtreecommitdiffstats
path: root/sys/kern/link_elf_obj.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2006-11-30 10:50:29 +0000
committerkib <kib@FreeBSD.org>2006-11-30 10:50:29 +0000
commit29a6b4a0eb224e61fc5685128b8e502266e86652 (patch)
treee2c54c5513e0411e28d56061a991147f8a31746c /sys/kern/link_elf_obj.c
parentb911f6e6f0bc5628a07e488e14a3453deb7cb04c (diff)
downloadFreeBSD-src-29a6b4a0eb224e61fc5685128b8e502266e86652.zip
FreeBSD-src-29a6b4a0eb224e61fc5685128b8e502266e86652.tar.gz
Linker set support depends on the magic __start_<section> and
__stop_<section> symbols generated by the static linker for elf sections. This is done only for the final link, and not for ld -r. Augment elf_obj in-kernel linker by recognizing such special symbols, and resolving them to the start and end of the section automatically. As result, linker sets on amd64 could be used in the same way as on other architectures, without explicit calls to linker_file_lookup_set(). Requested by: rdivacky No objections from: peter, jhb
Diffstat (limited to 'sys/kern/link_elf_obj.c')
-rw-r--r--sys/kern/link_elf_obj.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index a926d54..342410e 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -1115,6 +1115,51 @@ elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps)
}
static void
+link_elf_fix_link_set(elf_file_t ef)
+{
+ static const char startn[] = "__start_";
+ static const char stopn[] = "__stop_";
+ Elf_Sym *sym;
+ const char *sym_name, *linkset_name;
+ Elf_Addr startp, stopp;
+ Elf_Size symidx;
+ int start, i;
+
+ startp = stopp = 0;
+ for (symidx = 1 /* zero entry is special */;
+ symidx < ef->ddbsymcnt; symidx++) {
+ sym = ef->ddbsymtab + symidx;
+ if (sym->st_shndx != SHN_UNDEF)
+ continue;
+
+ sym_name = ef->ddbstrtab + sym->st_name;
+ if (strncmp(sym_name, startn, sizeof(startn) - 1) == 0) {
+ start = 1;
+ linkset_name = sym_name + sizeof(startn) - 1;
+ }
+ else if (strncmp(sym_name, stopn, sizeof(stopn) - 1) == 0) {
+ start = 0;
+ linkset_name = sym_name + sizeof(stopn) - 1;
+ }
+ else
+ continue;
+
+ for (i = 0; i < ef->nprogtab; i++) {
+ if (strcmp(ef->progtab[i].name, linkset_name) == 0) {
+ startp = (Elf_Addr)ef->progtab[i].addr;
+ stopp = (Elf_Addr)(startp + ef->progtab[i].size);
+ break;
+ }
+ }
+ if (i == ef->nprogtab)
+ continue;
+
+ sym->st_value = start ? startp : stopp;
+ sym->st_shndx = i;
+ }
+}
+
+static void
link_elf_reloc_local(linker_file_t lf)
{
elf_file_t ef = (elf_file_t)lf;
@@ -1127,6 +1172,8 @@ link_elf_reloc_local(linker_file_t lf)
int i;
Elf_Size symidx;
+ link_elf_fix_link_set(ef);
+
/* Perform relocations without addend if there are any: */
for (i = 0; i < ef->nrel; i++) {
rel = ef->reltab[i].rel;
OpenPOWER on IntegriCloud