1 /* Copyright (C) 2003, 2004 Red Hat, Inc.
2 * Contributed by Alexandre Oliva <aoliva@redhat.com>
3 * Copyright (C) 2006-2011 Analog Devices, Inc.
5 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
8 #include <inline-hashtab.h>
10 static __always_inline
void htab_delete(struct funcdesc_ht
*htab
);
12 /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete load map. */
13 static __always_inline
void
14 __dl_init_loadaddr_map(struct elf32_fdpic_loadaddr
*loadaddr
, Elf32_Addr dl_boot_got_pointer
,
15 struct elf32_fdpic_loadmap
*map
)
17 if (map
->version
!= 0) {
18 SEND_EARLY_STDERR("Invalid loadmap version number\n");
21 if (map
->nsegs
== 0) {
22 SEND_EARLY_STDERR("Invalid segment count in loadmap\n");
25 loadaddr
->got_value
= (void *)dl_boot_got_pointer
;
30 * Figure out how many LOAD segments there are in the given headers,
31 * and allocate a block for the load map big enough for them.
32 * got_value will be properly initialized later on, with INIT_GOT.
34 static __always_inline
int
35 __dl_init_loadaddr(struct elf32_fdpic_loadaddr
*loadaddr
, Elf32_Phdr
*ppnt
,
41 for (i
= 0; i
< pcnt
; i
++)
42 if (ppnt
[i
].p_type
== PT_LOAD
)
45 loadaddr
->got_value
= 0;
47 size
= sizeof(struct elf32_fdpic_loadmap
) +
48 (sizeof(struct elf32_fdpic_loadseg
) * count
);
49 loadaddr
->map
= _dl_malloc(size
);
53 loadaddr
->map
->version
= 0;
54 loadaddr
->map
->nsegs
= 0;
59 /* Incrementally initialize a load map. */
60 static __always_inline
void
61 __dl_init_loadaddr_hdr(struct elf32_fdpic_loadaddr loadaddr
, void *addr
,
62 Elf32_Phdr
*phdr
, int maxsegs
)
64 struct elf32_fdpic_loadseg
*segdata
;
66 if (loadaddr
.map
->nsegs
== maxsegs
)
69 segdata
= &loadaddr
.map
->segs
[loadaddr
.map
->nsegs
++];
70 segdata
->addr
= (Elf32_Addr
)addr
;
71 segdata
->p_vaddr
= phdr
->p_vaddr
;
72 segdata
->p_memsz
= phdr
->p_memsz
;
74 #if defined(__SUPPORT_LD_DEBUG__)
76 _dl_dprintf(_dl_debug_file
, "%i: mapped %x at %x, size %x\n",
77 loadaddr
.map
->nsegs
- 1,
78 segdata
->p_vaddr
, segdata
->addr
, segdata
->p_memsz
);
82 /* Replace an existing entry in the load map. */
83 static __always_inline
void
84 __dl_update_loadaddr_hdr(struct elf32_fdpic_loadaddr loadaddr
, void *addr
,
87 struct elf32_fdpic_loadseg
*segdata
;
91 for (i
= 0; i
< loadaddr
.map
->nsegs
; i
++)
92 if (loadaddr
.map
->segs
[i
].p_vaddr
== phdr
->p_vaddr
&&
93 loadaddr
.map
->segs
[i
].p_memsz
== phdr
->p_memsz
)
95 if (i
== loadaddr
.map
->nsegs
)
98 segdata
= loadaddr
.map
->segs
+ i
;
99 oldaddr
= (void *)segdata
->addr
;
100 _dl_munmap(oldaddr
, segdata
->p_memsz
);
101 segdata
->addr
= (Elf32_Addr
)addr
;
103 #if defined (__SUPPORT_LD_DEBUG__)
105 _dl_dprintf(_dl_debug_file
, "%i: changed mapping %x at %x (old %x), size %x\n",
106 loadaddr
.map
->nsegs
- 1,
107 segdata
->p_vaddr
, segdata
->addr
, oldaddr
, segdata
->p_memsz
);
112 #ifndef __dl_loadaddr_unmap
113 static __always_inline
void
114 __dl_loadaddr_unmap(struct elf32_fdpic_loadaddr loadaddr
,
115 struct funcdesc_ht
*funcdesc_ht
)
119 for (i
= 0; i
< loadaddr
.map
->nsegs
; i
++)
120 _dl_munmap((void *)loadaddr
.map
->segs
[i
].addr
,
121 loadaddr
.map
->segs
[i
].p_memsz
);
124 * _dl_unmap is only called for dlopen()ed libraries, for which
125 * calling free() is safe, or before we've completed the initial
126 * relocation, in which case calling free() is probably pointless,
129 _dl_free(loadaddr
.map
);
131 htab_delete(funcdesc_ht
);
135 /* Figure out whether the given address is in one of the mapped segments. */
136 static __always_inline
int
137 __dl_addr_in_loadaddr(void *p
, struct elf32_fdpic_loadaddr loadaddr
)
139 struct elf32_fdpic_loadmap
*map
= loadaddr
.map
;
142 for (c
= 0; c
< map
->nsegs
; c
++)
143 if ((void *)map
->segs
[c
].addr
<= p
&&
144 (char *)p
< (char *)map
->segs
[c
].addr
+ map
->segs
[c
].p_memsz
)
151 hash_pointer(void *p
)
153 return (int) ((long)p
>> 3);
157 eq_pointer(void *p
, void *q
)
159 struct funcdesc_value
*entry
= p
;
161 return entry
->entry_point
== q
;
164 static __always_inline
void *
165 _dl_funcdesc_for (void *entry_point
, void *got_value
)
167 struct elf_resolve
*tpnt
= ((void**)got_value
)[2];
168 struct funcdesc_ht
*ht
= tpnt
->funcdesc_ht
;
169 struct funcdesc_value
**entry
;
171 _dl_assert(got_value
== tpnt
->loadaddr
.got_value
);
177 tpnt
->funcdesc_ht
= ht
;
180 entry
= htab_find_slot(ht
, entry_point
, 1, hash_pointer
, eq_pointer
);
186 _dl_assert((*entry
)->entry_point
== entry_point
);
187 return _dl_stabilize_funcdesc(*entry
);
190 *entry
= _dl_malloc(sizeof(**entry
));
191 (*entry
)->entry_point
= entry_point
;
192 (*entry
)->got_value
= got_value
;
194 return _dl_stabilize_funcdesc(*entry
);
197 static __always_inline
void const *
198 _dl_lookup_address(void const *address
)
200 struct elf_resolve
*rpnt
;
201 struct funcdesc_value
const *fd
;
203 /* Make sure we don't make assumptions about its alignment. */
204 __asm__ ("" : "+r" (address
));
206 if ((Elf32_Addr
)address
& 7)
207 /* It's not a function descriptor. */
212 for (rpnt
= _dl_loaded_modules
; rpnt
; rpnt
= rpnt
->next
) {
213 if (!rpnt
->funcdesc_ht
)
216 if (fd
->got_value
!= rpnt
->loadaddr
.got_value
)
219 address
= htab_find_slot(rpnt
->funcdesc_ht
, (void *)fd
->entry_point
, 0,
220 hash_pointer
, eq_pointer
);
222 if (address
&& *(struct funcdesc_value
*const*)address
== fd
) {
223 address
= (*(struct funcdesc_value
*const*)address
)->entry_point
;