]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/uclibc/lib/contrib/uclibc/ldso/ldso/sparc/dl-sysdep.h
Update
[l4.git] / l4 / pkg / l4re-core / uclibc / lib / contrib / uclibc / ldso / ldso / sparc / dl-sysdep.h
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Various assembly language/system dependent hacks that are required
4  * so that we can minimize the amount of platform specific code.
5  * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
6  */
7
8 /* Define this if the system uses RELOCA.  */
9 #define ELF_USES_RELOCA
10 #include <elf.h>
11 /*
12  * Initialization sequence for a GOT.  For the Sparc, this points to the
13  * PLT, and we need to initialize a couple of the slots.  The PLT should
14  * look like:
15  *
16  *              save %sp, -64, %sp
17  *              call _dl_linux_resolve
18  *              nop
19  *              .word implementation_dependent
20  */
21 #define INIT_GOT(GOT_BASE,MODULE) \
22 {                               \
23    GOT_BASE[0] = 0x9de3bfc0;  /* save %sp, -64, %sp */  \
24    GOT_BASE[1] = 0x40000000 | (((unsigned int) _dl_linux_resolve - (unsigned int) GOT_BASE - 4) >> 2);  \
25    GOT_BASE[2] = 0x01000000; /* nop */                  \
26    GOT_BASE[3] = (int) MODULE;                                  \
27 }
28
29 /* Here we define the magic numbers that this dynamic loader should accept
30  * Note that SPARCV9 doesn't use EM_SPARCV9 since the userland is still 32-bit.
31  */
32 #if defined(__sparc_v9__)
33 #define MAGIC1 EM_SPARC32PLUS
34 #else
35 #define MAGIC1 EM_SPARC
36 #endif
37
38 #undef  MAGIC2
39
40 /* Used for error messages */
41 #define ELF_TARGET "sparc"
42
43 /* Need bootstrap relocations */
44 #define ARCH_NEEDS_BOOTSTRAP_RELOCS
45
46 struct elf_resolve;
47 unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
48
49 /*
50  * Define this if you want a dynamic loader that works on Solaris.
51  */
52
53 #ifndef COMPILE_ASM
54 /* Cheap modulo implementation, taken from arm/ld_sysdep.h. */
55 static __always_inline unsigned long
56 sparc_mod(unsigned long m, unsigned long p)
57 {
58         unsigned long i, t, inc;
59
60         i = p;
61         t = 0;
62
63         while (!(i & (1 << 31))) {
64                 i <<= 1;
65                 t++;
66         }
67
68         t--;
69
70         for (inc = t; inc > 2; inc--) {
71                 i = p << inc;
72
73                 if (i & (1 << 31))
74                         break;
75
76                 while (m >= i) {
77                         m -= i;
78                         i <<= 1;
79                         if (i & (1 << 31))
80                                 break;
81                         if (i < p)
82                                 break;
83                 }
84         }
85
86         while (m >= p)
87                 m -= p;
88
89         return m;
90 }
91
92 #define do_rem(result, n, base) ((result) = sparc_mod(n, base))
93 #endif
94
95 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
96    PLT entries should not be allowed to define the value.
97    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
98    of the main executable's symbols, as for a COPY reloc.  */
99 #define elf_machine_type_class(type) \
100   ((((type) == R_SPARC_JMP_SLOT || (type) == R_SPARC_TLS_DTPMOD32 \
101      || (type) == R_SPARC_TLS_DTPOFF32 || (type) == R_SPARC_TLS_TPOFF32) \
102     * ELF_RTYPE_CLASS_PLT)                            \
103    | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
104
105 /* The SPARC overlaps DT_RELA and DT_PLTREL.  */
106 #define ELF_MACHINE_PLTREL_OVERLAP 1
107
108 /* We have to do this because elf_machine_{dynamic,load_address} can be
109    invoked from functions that have no GOT references, and thus the compiler
110    has no obligation to load the PIC register.  */
111 #define LOAD_PIC_REG(PIC_REG)   \
112 do {    register Elf32_Addr pc __asm__("o7"); \
113         __asm__("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \
114               "call 1f\n\t" \
115               "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n" \
116               "1:\tadd %1, %0, %1" \
117               : "=r" (pc), "=r" (PIC_REG)); \
118 } while (0)
119
120 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
121    first element of the GOT.  This must be inlined in a function which
122    uses global data.  */
123 static __always_inline Elf32_Addr
124 elf_machine_dynamic (void)
125 {
126         register Elf32_Addr *got __asm__ ("%l7");
127
128         LOAD_PIC_REG (got);
129
130         return *got;
131 }
132
133 /* Return the run-time load address of the shared object.  */
134 static __always_inline Elf32_Addr
135 elf_machine_load_address (void)
136 {
137         register Elf32_Addr *pc __asm__ ("%o7"), *got __asm__ ("%l7");
138
139         __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t"
140                "call 1f\n\t"
141                " add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t"
142                "call _DYNAMIC\n\t"
143                "call _GLOBAL_OFFSET_TABLE_\n"
144                "1:\tadd %1, %0, %1\n\t" : "=r" (pc), "=r" (got));
145
146         /* got is now l_addr + _GLOBAL_OFFSET_TABLE_
147          *got is _DYNAMIC
148          pc[2]*4 is l_addr + _DYNAMIC - (long)pc - 8
149          pc[3]*4 is l_addr + _GLOBAL_OFFSET_TABLE_ - (long)pc - 12  */
150         return (Elf32_Addr) got - *got + (pc[2] - pc[3]) * 4 - 4;
151 }
152
153 static __always_inline void
154 elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
155                       Elf32_Word relative_count)
156 {
157         Elf32_Rela * rpnt = (void *)rel_addr;
158         --rpnt;
159         do {
160                 Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset);
161
162                 *reloc_addr = load_off + rpnt->r_addend;
163         } while (--relative_count);
164 }