.
[glibc.git] / sysdeps / i386 / dl-runtime.c
blob5e4a2890318267f8dd634598aa4cdfae68d930ec
1 /* On-demand PLT fixup for shared objects. i386 version.
2 Copyright (C) 1995 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA. */
20 #include <link.h>
21 #include "dynamic-link.h"
23 /* This function is not called in the normal way. The PLT jumps here, not
24 using a call. The stack looks like this:
26 -->8(%esp) address to return to the caller of the function in the PLT
27 4(%esp) relocation offset for this PLT entry
28 0(%esp) identifier for this shared object (struct link_map *)
30 The user expects the real function the PLT refers to to be entered
31 with 8(%esp) as the top of stack. */
33 void
34 _dl_runtime_resolve (Elf32_Word reloc_offset)
36 __label__ return_insn;
37 struct link_map *l = (void *) (&reloc_offset)[-1];
39 const Elf32_Sym *const symtab
40 = (const Elf32_Sym *) (l->l_addr + l->l_info[DT_SYMTAB]->d_un.d_ptr);
41 const char *strtab =
42 (const char *) (l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
44 const Elf32_Rel *const reloc
45 = (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr +
46 reloc_offset);
48 const Elf32_Sym *definer;
49 Elf32_Addr loadbase;
50 struct link_map *scope, *real_next;
52 /* Look up the symbol's run-time value. */
54 real_next = l->l_next;
55 if (l->l_info[DT_SYMBOLIC])
57 l->l_next = _dl_loaded;
58 if (l->l_prev)
59 l->l_prev->l_next = real_next;
60 scope = l;
62 else
63 scope = _dl_loaded;
65 definer = &symtab[ELF32_R_SYM (reloc->r_info)];
66 loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer,
67 scope, l->l_name, 0);
69 /* Restore list frobnication done above for DT_SYMBOLIC. */
70 l->l_next = real_next;
71 if (l->l_prev)
72 l->l_prev->l_next = l;
74 /* Apply the relocation with that value. */
75 elf_machine_rel (l, reloc, loadbase, definer);
77 /* The top of the stack is the word we set L from; but this location
78 holds the address we will return to. Store there the address of a
79 "ret" instruction, which will pop the stack and run the code at the
80 address in the next stack word. */
81 (&reloc_offset)[-1] = (Elf32_Word) &&return_insn;
83 /* The next stack word is our argument RELOC_OFFSET; but that "ret" will
84 pop and jump to this location, and the next stack word is the user's
85 return address. So store here the resolved address of the function
86 referred to by this PLT entry; once "ret" pops this address, the
87 function in the shared object will run with the stack arranged just as
88 when the user entered the PLT. */
89 (&reloc_offset)[0] = *(Elf32_Word *) (l->l_addr + reloc->r_offset);
91 return;
93 return_insn: asm volatile ("ret");