aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/link_elf_obj.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2006-11-30 10:50:29 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2006-11-30 10:50:29 +0000
commit7226306ed5046b0f776d7f75b2eb803855d32295 (patch)
treee2c54c5513e0411e28d56061a991147f8a31746c /sys/kern/link_elf_obj.c
parenta4dcb4f6270ae4eb28ee4842512eeb5cdde23d03 (diff)
downloadsrc-7226306ed5046b0f776d7f75b2eb803855d32295.tar.gz
src-7226306ed5046b0f776d7f75b2eb803855d32295.zip
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
Notes
Notes: svn path=/head/; revision=164767
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 a926d545ca19..342410ef658f 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;