diff options
author | kib <kib@FreeBSD.org> | 2006-11-30 10:50:29 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2006-11-30 10:50:29 +0000 |
commit | 29a6b4a0eb224e61fc5685128b8e502266e86652 (patch) | |
tree | e2c54c5513e0411e28d56061a991147f8a31746c /sys/kern | |
parent | b911f6e6f0bc5628a07e488e14a3453deb7cb04c (diff) | |
download | FreeBSD-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')
-rw-r--r-- | sys/kern/link_elf_obj.c | 47 |
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; |