OSDN Git Service

7707cfcb9e5915e22f5d1bcdfbaebe55e2f18018
[uclinux-h8/uClibc.git] / ldso / ldso / sparc / dl-sysdep.h
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Various assmbly 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__) || defined(__sparc_v8__)
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 struct elf_resolve;
44 unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
45
46 /*
47  * Define this if you want a dynamic loader that works on Solaris.
48  */
49
50 #ifndef COMPILE_ASM
51 /* Cheap modulo implementation, taken from arm/ld_sysdep.h. */
52 static __inline__ unsigned long
53 sparc_mod(unsigned long m, unsigned long p)
54 {
55         unsigned long i, t, inc;
56
57         i = p;
58         t = 0;
59
60         while (!(i & (1 << 31))) {
61                 i <<= 1;
62                 t++;
63         }
64
65         t--;
66
67         for (inc = t; inc > 2; inc--) {
68                 i = p << inc;
69
70                 if (i & (1 << 31))
71                         break;
72
73                 while (m >= i) {
74                         m -= i;
75                         i <<= 1;
76                         if (i & (1 << 31))
77                                 break;
78                         if (i < p)
79                                 break;
80                 }
81         }
82
83         while (m >= p)
84                 m -= p;
85
86         return m;
87 }
88
89 #define do_rem(result, n, base) ((result) = sparc_mod(n, base))
90 #endif
91
92 /* 4096 bytes alignment */
93 #if defined(__sparc_v9__)
94 /* ...but 8192 is required for mmap() on sparc64 kernel */
95 #define PAGE_ALIGN 0xffffe000
96 #define ADDR_ALIGN 0x1fff
97 #define OFFS_ALIGN 0x7fffe000
98 #elif defined(__sparc_v8__)
99 #define PAGE_ALIGN 0xfffff000
100 #define ADDR_ALIGN 0xfff
101 #define OFFS_ALIGN 0x7ffff000
102 #endif
103
104 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
105    PLT entries should not be allowed to define the value.
106    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
107    of the main executable's symbols, as for a COPY reloc.  */
108 #define elf_machine_type_class(type) \
109   ((((type) == R_SPARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)                       \
110    | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
111
112 /* The SPARC overlaps DT_RELA and DT_PLTREL.  */
113 #define ELF_MACHINE_PLTREL_OVERLAP 1
114
115 /* We have to do this because elf_machine_{dynamic,load_address} can be
116    invoked from functions that have no GOT references, and thus the compiler
117    has no obligation to load the PIC register.  */
118 #define LOAD_PIC_REG(PIC_REG)   \
119 do {    register Elf32_Addr pc __asm__("o7"); \
120         __asm__("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \
121               "call 1f\n\t" \
122               "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n" \
123               "1:\tadd %1, %0, %1" \
124               : "=r" (pc), "=r" (PIC_REG)); \
125 } while (0)
126
127 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
128    first element of the GOT.  This must be inlined in a function which
129    uses global data.  */
130 static __inline__ Elf32_Addr
131 elf_machine_dynamic (void)
132 {
133         register Elf32_Addr *got __asm__ ("%l7");
134         
135         LOAD_PIC_REG (got);
136         
137         return *got;
138 }
139
140 /* Return the run-time load address of the shared object.  */
141 static __inline__ Elf32_Addr
142 elf_machine_load_address (void)
143 {
144         register Elf32_Addr *pc __asm__ ("%o7"), *got __asm ("%l7");
145         
146         __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t"
147                "call 1f\n\t"
148                " add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t"
149                "call _DYNAMIC\n\t"
150                "call _GLOBAL_OFFSET_TABLE_\n"
151                "1:\tadd %1, %0, %1\n\t" : "=r" (pc), "=r" (got));
152         
153         /* got is now l_addr + _GLOBAL_OFFSET_TABLE_
154          *got is _DYNAMIC
155          pc[2]*4 is l_addr + _DYNAMIC - (long)pc - 8
156          pc[3]*4 is l_addr + _GLOBAL_OFFSET_TABLE_ - (long)pc - 12  */
157         return (Elf32_Addr) got - *got + (pc[2] - pc[3]) * 4 - 4;
158 }
159
160 static __inline__ void
161 elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
162                       Elf32_Word relative_count)
163 {
164         Elf32_Rela * rpnt = (void *)rel_addr;
165         --rpnt;
166         do {
167                 Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset);
168
169                 *reloc_addr = load_off + rpnt->r_addend;
170         } while (--relative_count);
171 }