annotate head/libexec/rtld-elf/ia64/reloc.c @ 481:737774f27543

Update libexec/rtld-elf to @235221
author Aleksandr Rybalko <ray@ddteam.net>
date Thu, 10 May 2012 14:47:51 +0300
parents f2935497fa04
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
1 /*-
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
2 * Copyright 1996, 1997, 1998, 1999 John D. Polstra.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
3 * All rights reserved.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
4 *
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
5 * Redistribution and use in source and binary forms, with or without
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
6 * modification, are permitted provided that the following conditions
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
7 * are met:
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
8 * 1. Redistributions of source code must retain the above copyright
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
9 * notice, this list of conditions and the following disclaimer.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
10 * 2. Redistributions in binary form must reproduce the above copyright
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
11 * notice, this list of conditions and the following disclaimer in the
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
12 * documentation and/or other materials provided with the distribution.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
13 *
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
24 *
481
737774f27543 Update libexec/rtld-elf to @235221
Aleksandr Rybalko <ray@ddteam.net>
parents: 453
diff changeset
25 * $FreeBSD: head/libexec/rtld-elf/ia64/reloc.c 234841 2012-04-30 13:31:10Z kib $
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
26 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
27
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
28 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
29 * Dynamic linker for ELF.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
30 *
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
31 * John Polstra <[email protected]>.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
32 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
33
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
34 #include <sys/param.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
35 #include <sys/mman.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
36 #include <machine/ia64_cpu.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
37
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
38 #include <dlfcn.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
39 #include <err.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
40 #include <errno.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
41 #include <fcntl.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
42 #include <stdarg.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
43 #include <stdio.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
44 #include <stdlib.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
45 #include <string.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
46 #include <unistd.h>
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
47
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
48 #include "debug.h"
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
49 #include "rtld.h"
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
50
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
51 extern Elf_Dyn _DYNAMIC;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
52
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
53 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
54 * Macros for loading/storing unaligned 64-bit values. These are
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
55 * needed because relocations can point to unaligned data. This
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
56 * occurs in the DWARF2 exception frame tables generated by the
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
57 * compiler, for instance.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
58 *
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
59 * We don't use these when relocating jump slots and GOT entries,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
60 * since they are guaranteed to be aligned.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
61 *
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
62 * XXX dfr stub for now.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
63 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
64 #define load64(p) (*(u_int64_t *) (p))
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
65 #define store64(p, v) (*(u_int64_t *) (p) = (v))
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
66
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
67 /* Allocate an @fptr. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
68
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
69 #define FPTR_CHUNK_SIZE 64
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
70
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
71 struct fptr_chunk {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
72 struct fptr fptrs[FPTR_CHUNK_SIZE];
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
73 };
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
74
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
75 static struct fptr_chunk first_chunk;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
76 static struct fptr_chunk *current_chunk = &first_chunk;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
77 static struct fptr *next_fptr = &first_chunk.fptrs[0];
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
78 static struct fptr *last_fptr = &first_chunk.fptrs[FPTR_CHUNK_SIZE];
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
79
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
80 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
81 * We use static storage initially so that we don't have to call
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
82 * malloc during init_rtld().
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
83 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
84 static struct fptr *
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
85 alloc_fptr(Elf_Addr target, Elf_Addr gp)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
86 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
87 struct fptr* fptr;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
88
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
89 if (next_fptr == last_fptr) {
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
90 current_chunk = xmalloc(sizeof(struct fptr_chunk));
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
91 next_fptr = &current_chunk->fptrs[0];
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
92 last_fptr = &current_chunk->fptrs[FPTR_CHUNK_SIZE];
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
93 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
94 fptr = next_fptr;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
95 next_fptr++;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
96 fptr->target = target;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
97 fptr->gp = gp;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
98 return fptr;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
99 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
100
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
101 static struct fptr **
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
102 alloc_fptrs(Obj_Entry *obj, bool mapped)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
103 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
104 struct fptr **fptrs;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
105 size_t fbytes;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
106
481
737774f27543 Update libexec/rtld-elf to @235221
Aleksandr Rybalko <ray@ddteam.net>
parents: 453
diff changeset
107 fbytes = obj->dynsymcount * sizeof(struct fptr *);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
108
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
109 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
110 * Avoid malloc, if requested. Happens when relocating
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
111 * rtld itself on startup.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
112 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
113 if (mapped) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
114 fptrs = mmap(NULL, fbytes, PROT_READ|PROT_WRITE,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
115 MAP_ANON, -1, 0);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
116 if (fptrs == MAP_FAILED)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
117 fptrs = NULL;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
118 } else {
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
119 fptrs = xcalloc(1, fbytes);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
120 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
121
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
122 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
123 * This assertion is necessary to guarantee function pointer
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
124 * uniqueness
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
125 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
126 assert(fptrs != NULL);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
127
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
128 return (obj->priv = fptrs);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
129 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
130
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
131 static void
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
132 free_fptrs(Obj_Entry *obj, bool mapped)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
133 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
134 struct fptr **fptrs;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
135 size_t fbytes;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
136
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
137 fptrs = obj->priv;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
138 if (fptrs == NULL)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
139 return;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
140
481
737774f27543 Update libexec/rtld-elf to @235221
Aleksandr Rybalko <ray@ddteam.net>
parents: 453
diff changeset
141 fbytes = obj->dynsymcount * sizeof(struct fptr *);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
142 if (mapped)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
143 munmap(fptrs, fbytes);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
144 else
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
145 free(fptrs);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
146 obj->priv = NULL;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
147 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
148
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
149 /* Relocate a non-PLT object with addend. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
150 static int
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
151 reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
152 SymCache *cache, int flags, RtldLockState *lockstate)
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
153 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
154 struct fptr **fptrs;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
155 Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
156
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
157 switch (ELF_R_TYPE(rela->r_info)) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
158 case R_IA_64_REL64LSB:
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
159 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
160 * We handle rtld's relocations in rtld_start.S
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
161 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
162 if (obj != obj_rtld)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
163 store64(where,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
164 load64(where) + (Elf_Addr) obj->relocbase);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
165 break;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
166
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
167 case R_IA_64_DIR64LSB: {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
168 const Elf_Sym *def;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
169 const Obj_Entry *defobj;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
170 Elf_Addr target;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
171
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
172 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
173 flags, cache, lockstate);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
174 if (def == NULL)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
175 return -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
176
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
177 target = (def->st_shndx != SHN_UNDEF)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
178 ? (Elf_Addr)(defobj->relocbase + def->st_value) : 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
179 store64(where, target + rela->r_addend);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
180 break;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
181 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
182
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
183 case R_IA_64_FPTR64LSB: {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
184 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
185 * We have to make sure that all @fptr references to
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
186 * the same function are identical so that code can
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
187 * compare function pointers.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
188 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
189 const Elf_Sym *def;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
190 const Obj_Entry *defobj;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
191 struct fptr *fptr = 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
192 Elf_Addr target, gp;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
193 int sym_index;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
194
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
195 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
196 SYMLOOK_IN_PLT | flags, cache, lockstate);
74
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
197 if (def == NULL) {
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
198 /*
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
199 * XXX r_debug_state is problematic and find_symdef()
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
200 * returns NULL for it. This probably has something to
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
201 * do with symbol versioning (r_debug_state is in the
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
202 * symbol map). If we return -1 in that case we abort
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
203 * relocating rtld, which typically is fatal. So, for
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
204 * now just skip the symbol when we're relocating
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
205 * rtld. We don't care about r_debug_state unless we
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
206 * are being debugged.
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
207 */
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
208 if (obj != obj_rtld)
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
209 return -1;
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
210 break;
dfa0e5092265 svn update @214514
ray@terran.dlink.ua
parents: 1
diff changeset
211 }
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
212
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
213 if (def->st_shndx != SHN_UNDEF) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
214 target = (Elf_Addr)(defobj->relocbase + def->st_value);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
215 gp = (Elf_Addr)defobj->pltgot;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
216
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
217 /* rtld is allowed to reference itself only */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
218 assert(!obj->rtld || obj == defobj);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
219 fptrs = defobj->priv;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
220 if (fptrs == NULL)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
221 fptrs = alloc_fptrs((Obj_Entry *) defobj,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
222 obj->rtld);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
223
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
224 sym_index = def - defobj->symtab;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
225
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
226 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
227 * Find the @fptr, using fptrs as a helper.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
228 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
229 if (fptrs)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
230 fptr = fptrs[sym_index];
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
231 if (!fptr) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
232 fptr = alloc_fptr(target, gp);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
233 if (fptrs)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
234 fptrs[sym_index] = fptr;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
235 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
236 } else
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
237 fptr = NULL;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
238
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
239 store64(where, (Elf_Addr)fptr);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
240 break;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
241 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
242
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
243 case R_IA_64_IPLTLSB: {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
244 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
245 * Relocation typically used to populate C++ virtual function
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
246 * tables. It creates a 128-bit function descriptor at the
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
247 * specified memory address.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
248 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
249 const Elf_Sym *def;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
250 const Obj_Entry *defobj;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
251 struct fptr *fptr;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
252 Elf_Addr target, gp;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
253
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
254 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
255 flags, cache, lockstate);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
256 if (def == NULL)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
257 return -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
258
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
259 if (def->st_shndx != SHN_UNDEF) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
260 target = (Elf_Addr)(defobj->relocbase + def->st_value);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
261 gp = (Elf_Addr)defobj->pltgot;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
262 } else {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
263 target = 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
264 gp = 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
265 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
266
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
267 fptr = (void*)where;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
268 store64(&fptr->target, target);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
269 store64(&fptr->gp, gp);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
270 break;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
271 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
272
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
273 case R_IA_64_DTPMOD64LSB: {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
274 const Elf_Sym *def;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
275 const Obj_Entry *defobj;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
276
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
277 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
278 flags, cache, lockstate);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
279 if (def == NULL)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
280 return -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
281
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
282 store64(where, defobj->tlsindex);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
283 break;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
284 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
285
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
286 case R_IA_64_DTPREL64LSB: {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
287 const Elf_Sym *def;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
288 const Obj_Entry *defobj;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
289
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
290 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
291 flags, cache, lockstate);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
292 if (def == NULL)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
293 return -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
294
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
295 store64(where, def->st_value + rela->r_addend);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
296 break;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
297 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
298
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
299 case R_IA_64_TPREL64LSB: {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
300 const Elf_Sym *def;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
301 const Obj_Entry *defobj;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
302
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
303 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
304 flags, cache, lockstate);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
305 if (def == NULL)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
306 return -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
307
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
308 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
309 * We lazily allocate offsets for static TLS as we
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
310 * see the first relocation that references the
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
311 * TLS block. This allows us to support (small
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
312 * amounts of) static TLS in dynamically loaded
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
313 * modules. If we run out of space, we generate an
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
314 * error.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
315 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
316 if (!defobj->tls_done) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
317 if (!allocate_tls_offset((Obj_Entry*) defobj)) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
318 _rtld_error("%s: No space available for static "
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
319 "Thread Local Storage", obj->path);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
320 return -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
321 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
322 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
323
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
324 store64(where, defobj->tlsoffset + def->st_value + rela->r_addend);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
325 break;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
326 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
327
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
328 case R_IA_64_NONE:
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
329 break;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
330
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
331 default:
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
332 _rtld_error("%s: Unsupported relocation type %u"
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
333 " in non-PLT relocations\n", obj->path,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
334 (unsigned int)ELF_R_TYPE(rela->r_info));
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
335 return -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
336 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
337
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
338 return(0);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
339 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
340
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
341 /* Process the non-PLT relocations. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
342 int
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
343 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
344 RtldLockState *lockstate)
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
345 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
346 const Elf_Rel *rellim;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
347 const Elf_Rel *rel;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
348 const Elf_Rela *relalim;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
349 const Elf_Rela *rela;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
350 SymCache *cache;
481
737774f27543 Update libexec/rtld-elf to @235221
Aleksandr Rybalko <ray@ddteam.net>
parents: 453
diff changeset
351 int bytes = obj->dynsymcount * sizeof(SymCache);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
352 int r = -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
353
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
354 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
355 * The dynamic loader may be called from a thread, we have
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
356 * limited amounts of stack available so we cannot use alloca().
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
357 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
358 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
359 if (cache == MAP_FAILED)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
360 cache = NULL;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
361
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
362 /* Perform relocations without addend if there are any: */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
363 rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
364 for (rel = obj->rel; obj->rel != NULL && rel < rellim; rel++) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
365 Elf_Rela locrela;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
366
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
367 locrela.r_info = rel->r_info;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
368 locrela.r_offset = rel->r_offset;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
369 locrela.r_addend = 0;
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
370 if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache, flags,
86
a350047c8ffe FreeBSD HEAD @svn r216736
ray@terran.dlink.ua
parents: 74
diff changeset
371 lockstate))
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
372 goto done;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
373 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
374
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
375 /* Perform relocations with addend if there are any: */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
376 relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
377 for (rela = obj->rela; obj->rela != NULL && rela < relalim; rela++) {
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
378 if (reloc_non_plt_obj(obj_rtld, obj, rela, cache, flags,
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
379 lockstate))
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
380 goto done;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
381 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
382
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
383 r = 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
384 done:
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
385 if (cache)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
386 munmap(cache, bytes);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
387
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
388 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
389 * Release temporarily mapped fptrs if relocating
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
390 * rtld object itself. A new table will be created
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
391 * in make_function_pointer using malloc when needed.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
392 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
393 if (obj->rtld && obj->priv)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
394 free_fptrs(obj, true);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
395
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
396 return (r);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
397 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
398
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
399 /* Process the PLT relocations. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
400 int
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
401 reloc_plt(Obj_Entry *obj)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
402 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
403 /* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
404 if (obj->pltrelsize != 0) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
405 const Elf_Rel *rellim;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
406 const Elf_Rel *rel;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
407
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
408 rellim = (const Elf_Rel *)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
409 ((char *)obj->pltrel + obj->pltrelsize);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
410 for (rel = obj->pltrel; rel < rellim; rel++) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
411 Elf_Addr *where;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
412
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
413 assert(ELF_R_TYPE(rel->r_info) == R_IA_64_IPLTLSB);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
414
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
415 /* Relocate the @fptr pointing into the PLT. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
416 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
417 *where += (Elf_Addr)obj->relocbase;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
418 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
419 } else {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
420 const Elf_Rela *relalim;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
421 const Elf_Rela *rela;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
422
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
423 relalim = (const Elf_Rela *)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
424 ((char *)obj->pltrela + obj->pltrelasize);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
425 for (rela = obj->pltrela; rela < relalim; rela++) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
426 Elf_Addr *where;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
427
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
428 assert(ELF_R_TYPE(rela->r_info) == R_IA_64_IPLTLSB);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
429
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
430 /* Relocate the @fptr pointing into the PLT. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
431 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
432 *where += (Elf_Addr)obj->relocbase;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
433 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
434 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
435 return 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
436 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
437
247
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
438 int
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
439 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
440 {
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
441
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
442 /* XXX not implemented */
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
443 return (0);
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
444 }
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
445
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
446 int
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
447 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
448 struct Struct_RtldLockState *lockstate)
247
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
449 {
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
450
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
451 /* XXX not implemented */
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
452 return (0);
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
453 }
820af1e39cd6 FreeBSD HEAD @svn 228526r.
ray@terran.dlink.ua
parents: 86
diff changeset
454
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
455 /* Relocate the jump slots in an object. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
456 int
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
457 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
458 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
459 if (obj->jmpslots_done)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
460 return 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
461 /* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
462 if (obj->pltrelsize != 0) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
463 const Elf_Rel *rellim;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
464 const Elf_Rel *rel;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
465
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
466 rellim = (const Elf_Rel *)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
467 ((char *)obj->pltrel + obj->pltrelsize);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
468 for (rel = obj->pltrel; rel < rellim; rel++) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
469 Elf_Addr *where;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
470 const Elf_Sym *def;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
471 const Obj_Entry *defobj;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
472
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
473 assert(ELF_R_TYPE(rel->r_info) == R_IA_64_IPLTLSB);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
474 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
475 def = find_symdef(ELF_R_SYM(rel->r_info), obj,
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
476 &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
477 if (def == NULL)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
478 return -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
479 reloc_jmpslot(where,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
480 (Elf_Addr)(defobj->relocbase
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
481 + def->st_value),
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
482 defobj, obj, rel);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
483 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
484 } else {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
485 const Elf_Rela *relalim;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
486 const Elf_Rela *rela;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
487
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
488 relalim = (const Elf_Rela *)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
489 ((char *)obj->pltrela + obj->pltrelasize);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
490 for (rela = obj->pltrela; rela < relalim; rela++) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
491 Elf_Addr *where;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
492 const Elf_Sym *def;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
493 const Obj_Entry *defobj;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
494
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
495 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
496 def = find_symdef(ELF_R_SYM(rela->r_info), obj,
453
f2935497fa04 FreeBSD HEAD @svn 234370r.
Aleksandr Rybalko <ray@ddteam.net>
parents: 444
diff changeset
497 &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate);
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
498 if (def == NULL)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
499 return -1;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
500 reloc_jmpslot(where,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
501 (Elf_Addr)(defobj->relocbase
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
502 + def->st_value),
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
503 defobj, obj, (Elf_Rel *)rela);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
504 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
505 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
506 obj->jmpslots_done = true;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
507 return 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
508 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
509
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
510 /* Fixup the jump slot at "where" to transfer control to "target". */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
511 Elf_Addr
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
512 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *obj,
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
513 const Obj_Entry *refobj, const Elf_Rel *rel)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
514 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
515 Elf_Addr stubaddr;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
516
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
517 dbg(" reloc_jmpslot: where=%p, target=%p, gp=%p",
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
518 (void *)where, (void *)target, (void *)obj->pltgot);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
519 stubaddr = *where;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
520 if (stubaddr != target) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
521
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
522 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
523 * Point this @fptr directly at the target. Update the
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
524 * gp value first so that we don't break another cpu
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
525 * which is currently executing the PLT entry.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
526 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
527 where[1] = (Elf_Addr) obj->pltgot;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
528 ia64_mf();
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
529 where[0] = target;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
530 ia64_mf();
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
531 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
532
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
533 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
534 * The caller needs an @fptr for the adjusted entry. The PLT
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
535 * entry serves this purpose nicely.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
536 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
537 return (Elf_Addr) where;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
538 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
539
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
540 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
541 * XXX ia64 doesn't seem to have copy relocations.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
542 *
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
543 * Returns 0 on success, -1 on failure.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
544 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
545 int
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
546 do_copy_relocations(Obj_Entry *dstobj)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
547 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
548
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
549 return 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
550 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
551
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
552 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
553 * Return the @fptr representing a given function symbol.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
554 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
555 void *
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
556 make_function_pointer(const Elf_Sym *sym, const Obj_Entry *obj)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
557 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
558 struct fptr **fptrs = obj->priv;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
559 int index = sym - obj->symtab;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
560
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
561 if (!fptrs) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
562 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
563 * This should only happen for something like
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
564 * dlsym("dlopen"). Actually, I'm not sure it can ever
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
565 * happen.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
566 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
567 fptrs = alloc_fptrs((Obj_Entry *) obj, false);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
568 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
569 if (!fptrs[index]) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
570 Elf_Addr target, gp;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
571 target = (Elf_Addr) (obj->relocbase + sym->st_value);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
572 gp = (Elf_Addr) obj->pltgot;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
573 fptrs[index] = alloc_fptr(target, gp);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
574 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
575 return fptrs[index];
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
576 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
577
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
578 void
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
579 call_initfini_pointer(const Obj_Entry *obj, Elf_Addr target)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
580 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
581 struct fptr fptr;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
582
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
583 fptr.gp = (Elf_Addr) obj->pltgot;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
584 fptr.target = target;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
585 dbg(" initfini: target=%p, gp=%p",
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
586 (void *) fptr.target, (void *) fptr.gp);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
587 ((InitFunc) &fptr)();
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
588 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
589
444
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
590 void
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
591 call_init_pointer(const Obj_Entry *obj, Elf_Addr target)
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
592 {
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
593 struct fptr fptr;
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
594
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
595 fptr.gp = (Elf_Addr) obj->pltgot;
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
596 fptr.target = target;
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
597 dbg(" initfini: target=%p, gp=%p",
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
598 (void *) fptr.target, (void *) fptr.gp);
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
599 ((InitArrFunc) &fptr)(main_argc, main_argv, environ);
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
600 }
36d20e2a6e89 FreeBSD HEAD @svn r233228.
Aleksandr Rybalko <ray@ddteam.net>
parents: 247
diff changeset
601
1
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
602 /* Initialize the special PLT entries. */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
603 void
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
604 init_pltgot(Obj_Entry *obj)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
605 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
606 const Elf_Dyn *dynp;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
607 Elf_Addr *pltres = 0;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
608
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
609 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
610 * When there are no PLT relocations, the DT_IA_64_PLT_RESERVE entry
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
611 * is bogus. Do not setup the BOR pointers in that case. An example
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
612 * of where this happens is /usr/lib/libxpg4.so.3.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
613 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
614 if (obj->pltrelasize == 0 && obj->pltrelsize == 0)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
615 return;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
616
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
617 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
618 * Find the PLT RESERVE section.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
619 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
620 for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; dynp++) {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
621 if (dynp->d_tag == DT_IA_64_PLT_RESERVE)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
622 pltres = (u_int64_t *)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
623 (obj->relocbase + dynp->d_un.d_ptr);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
624 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
625 if (!pltres)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
626 errx(1, "Can't find DT_IA_64_PLT_RESERVE entry");
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
627
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
628 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
629 * The PLT RESERVE section is used to get values to pass to
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
630 * _rtld_bind when lazy binding.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
631 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
632 pltres[0] = (Elf_Addr) obj;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
633 pltres[1] = FPTR_TARGET(_rtld_bind_start);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
634 pltres[2] = FPTR_GP(_rtld_bind_start);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
635 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
636
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
637 void
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
638 allocate_initial_tls(Obj_Entry *list)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
639 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
640 void *tpval;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
641
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
642 /*
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
643 * Fix the size of the static TLS block by using the maximum
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
644 * offset allocated so far and adding a bit for dynamic modules to
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
645 * use.
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
646 */
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
647 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
648
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
649 tpval = allocate_tls(list, NULL, TLS_TCB_SIZE, 16);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
650 __asm __volatile("mov r13 = %0" :: "r"(tpval));
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
651 }
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
652
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
653 void *__tls_get_addr(unsigned long module, unsigned long offset)
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
654 {
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
655 register Elf_Addr** tp __asm__("r13");
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
656
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
657 return tls_get_addr_common(tp, module, offset);
8101a7904232 FreeBSD HEAD @205277
ray@terran.dlink.ua
parents:
diff changeset
658 }