]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/uclibc/lib/contrib/uclibc/ldso/ldso/sh64/dl-sysdep.h
Update
[l4.git] / l4 / pkg / l4re-core / uclibc / lib / contrib / uclibc / ldso / ldso / sh64 / dl-sysdep.h
1 /* vi: set sw=8 ts=8: */
2 /*
3  * Various assembly language/system dependent hacks that are required
4  * so that we can minimize the amount of platform specific code.
5  */
6
7 /* Define this if the system uses RELOCA.  */
8 #define ELF_USES_RELOCA
9 #include <elf.h>
10 /*
11  * Initialization sequence for a GOT.
12  */
13 #define INIT_GOT(GOT_BASE,MODULE)                               \
14 {                                                               \
15         GOT_BASE[2] = (unsigned long)_dl_linux_resolve;         \
16         GOT_BASE[1] = (unsigned long)(MODULE);                  \
17 }
18
19 /* Here we define the magic numbers that this dynamic loader should accept */
20 #define MAGIC1 EM_SH
21 #undef  MAGIC2
22
23 /* Used for error messages */
24 #define ELF_TARGET "sh64"
25
26 /* Need bootstrap relocations */
27 #define ARCH_NEEDS_BOOTSTRAP_RELOCS
28
29 struct elf_resolve;
30 extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
31
32 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
33    TLS variable, so undefined references should not be allowed to
34    define the value.
35    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
36    of the main executable's symbols, as for a COPY reloc.  */
37 #define elf_machine_type_class(type) \
38   ((((type) == R_SH_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)    \
39    | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
40
41 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
42    first element of the GOT.  This must be inlined in a function which
43    uses global data.  */
44 static __always_inline Elf32_Addr elf_machine_dynamic(void)
45 {
46         register Elf32_Addr *got;
47
48         /*
49          * The toolchain adds 32768 to the GOT address, we compensate for
50          * that in the movi/sub pair.
51          *
52          * XXX: If this is cleaned up in the toolchain, we can end up
53          * saving 2 instructions and subsequently free up r1 from the
54          * clobber list..
55          */
56         __asm__ (
57                 "movi\t(((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ1-.)) >> 16) & 0xffff), r2\n\t"
58                 "shori\t((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ1-.)) & 0xffff), r2\n\t"
59                 ".LZZZ1:\tptrel/u r2, tr0\n\t"
60                 "movi\t32768, r1\n\t"
61                 "gettr\ttr0, r2\n\t"
62                 "sub\tr2, r1, %0\n\t"
63                 : "=r" (got)
64                 : /* no inputs */
65                 : "r1", "r2", "tr0"
66         );
67
68         return *got;
69 }
70
71 /* Return the run-time load address of the shared object.  */
72 static __always_inline Elf32_Addr elf_machine_load_address(void)
73 {
74         Elf32_Addr addr;
75
76         __asm__ (
77                 "movi\t(((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ2-.)) >> 16) & 0xffff), r0\n\t"
78                 "shori\t((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ2-.)) & 0xffff), r0\n\t"
79                 ".LZZZ2:\tptrel/u r0, tr0\n\t"
80                 "movi\t(((_dl_start@GOTOFF) >> 16) & 0xffff), r2\n\t"
81                 "shori\t((_dl_start@GOTOFF) & 0xffff), r2\n\t"
82                 "gettr\ttr0, r0\n\t"
83                 "add\tr2, r0, r2\n\t"
84                 "movi\t(((_dl_start@GOT) >> 16) & 0xffff), r1\n\t"
85                 "shori\t((_dl_start@GOT) & 0xffff), r1\n\t"
86                 "ldx.l\tr1, r0, r1\n\t"
87                 "sub\tr2, r1, %0\n\t"
88                 : "=r" (addr)
89                 : /* no inputs */
90                 : "r0", "r1", "r2", "tr0"
91         );
92
93         return addr;
94 }
95
96 /*
97  * XXX: As we don't need to worry about r25 clobbering, we could probably
98  * get away with inlining {st,ld}{x,}.l and friends here instead and
99  * forego gcc's idea of code generation.
100  */
101 #define COPY_UNALIGNED_WORD(swp, twp, align)            \
102 {                                                       \
103         void *__s = (swp), *__t = (twp);                \
104         unsigned char *__s1 = __s, *__t1 = __t;         \
105         unsigned short *__s2 = __s, *__t2 = __t;        \
106         unsigned long *__s4 = __s, *__t4 = __t;         \
107                                                         \
108         switch ((align)) {                              \
109         case 0:                                         \
110                 *__t4 = *__s4;                          \
111                 break;                                  \
112         case 2:                                         \
113                 *__t2++ = *__s2++;                      \
114                 *__t2 = *__s2;                          \
115                 break;                                  \
116         default:                                        \
117                 *__t1++ = *__s1++;                      \
118                 *__t1++ = *__s1++;                      \
119                 *__t1++ = *__s1++;                      \
120                 *__t1 = *__s1;                          \
121                 break;                                  \
122         }                                               \
123 }
124
125 static __always_inline void
126 elf_machine_relative(Elf32_Addr load_off, const Elf32_Addr rel_addr,
127                      Elf32_Word relative_count)
128 {
129         Elf32_Addr value, word;
130         Elf32_Rela *rpnt = (void *)rel_addr;
131         int reloc_type = ELF_R_TYPE(rpnt->r_info);
132
133         do {
134                 Elf32_Addr *const reloc_addr =
135                         (void *)(load_off + rpnt->r_offset);
136                 int align = (int)reloc_addr & 3;
137
138                 switch (reloc_type) {
139                 case R_SH_RELATIVE_LOW16:
140                         COPY_UNALIGNED_WORD(reloc_addr, &word, align);
141                         word &= ~0x3fffc00;
142                         value = (rpnt->r_addend + load_off);
143                         word |= (value & 0xffff) << 10;
144                         COPY_UNALIGNED_WORD(&word, reloc_addr, align);
145                         break;
146                 case R_SH_RELATIVE_MEDLOW16:
147                         COPY_UNALIGNED_WORD(reloc_addr, &word, align);
148                         word &= ~0x3fffc00;
149                         value = (rpnt->r_addend + load_off) >> 16;
150                         word |= (value & 0xffff) << 10;
151                         COPY_UNALIGNED_WORD(&word, reloc_addr, align);
152                         break;
153                 default:
154                         if (rpnt->r_addend) {
155                                 value = load_off + rpnt->r_addend;
156                         } else {
157                                 COPY_UNALIGNED_WORD(reloc_addr, &value, align);
158                                 value += load_off;
159                         }
160
161                         COPY_UNALIGNED_WORD(&value, reloc_addr, align);
162                         break;
163                 }
164
165                 rpnt++;
166         } while (--relative_count);
167 #undef COPY_UNALIGNED_WORD
168 }