OSDN Git Service

ARC: ldso: Use @pcl syntax.
[uclinux-h8/uClibc.git] / ldso / ldso / arc / dl-sysdep.h
1 /*
2  * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
3  *
4  * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
5  */
6
7 #include "elf.h"
8
9 /*
10  * Define this if the system uses RELOCA.
11  */
12 #define ELF_USES_RELOCA
13
14 /*
15  * Dynamic Linking ABI for ARCompact ISA
16  *
17  *                      PLT
18  *        --------------------------------
19  *        |  ld r11, [pcl, off-to-GOT[1] |  0   (20 bytes)
20  *        |                              |  4
21  * plt0   |  ld r10, [pcl, off-to-GOT[2] |  8
22  *        |                              | 12
23  *        |  j [r10]                     | 16
24  *        --------------------------------
25  *        |    Base address of GOT       | 20
26  *        --------------------------------
27  *        |  ld r12, [pcl, off-to-GOT[3] | 24   (12 bytes each)
28  * plt1   |                              |
29  *        |  j_s.d  [r12]                | 32
30  *        |  mov_s  r12, pcl             | 34
31  *        --------------------------------
32  *        |                              | 36
33  *        ~                              ~
34  *        ~                              ~
35  *        |                              |
36  *        --------------------------------
37  *
38  *             GOT
39  *        --------------
40  *        |    [0]     |
41  *        --------------
42  *        |    [1]     |  Module info - setup by ldso
43  *        --------------
44  *        |    [2]     |  resolver entry point
45  *        --------------
46  *        |    [3]     |
47  *        |    ...     |  Runtime address for function symbols
48  *        |    [f]     |
49  *        --------------
50  *        |    [f+1]   |
51  *        |    ...     |  Runtime address for data symbols
52  *        |    [last]  |
53  *        --------------
54  */
55
56 /*
57  * Initialization sequence for a GOT.
58  * Caller elf_resolve() seeds @GOT_BASE from DT_PLTGOT - which essentially is
59  * pointer to first PLT entry. The actual GOT base is 5th word in PLT
60  *
61  */
62 #define INIT_GOT(GOT_BASE,MODULE)                                       \
63 do {                                                                    \
64         unsigned long *__plt_base = (unsigned long *)GOT_BASE;          \
65         GOT_BASE = (unsigned long *)(__plt_base[5] +                    \
66                                      (unsigned long)MODULE->loadaddr);  \
67         GOT_BASE[1] = (unsigned long) MODULE;                           \
68         GOT_BASE[2] = (unsigned long) _dl_linux_resolve;                \
69 } while(0)
70
71 /* Here we define the magic numbers that this dynamic loader should accept */
72 #define MAGIC1 EM_ARCOMPACT
73 #undef  MAGIC2
74
75 /* Used for error messages */
76 #define ELF_TARGET "ARC"
77
78 struct elf_resolve;
79 extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt,
80                                          unsigned int plt_pc);
81
82 extern unsigned __udivmodsi4(unsigned, unsigned) attribute_hidden;
83
84 #define do_rem(result, n, base)  ((result) =                            \
85                                                                         \
86         __builtin_constant_p (base) ? (n) % (unsigned) (base) :         \
87         __extension__ ({                                                \
88                 register unsigned r1 __asm__ ("r1") = (base);           \
89                                                                         \
90                 __asm__("bl.d @__udivmodsi4` mov r0,%1"                 \
91                 : "=r" (r1)                                             \
92                 : "r" (n), "r" (r1)                                     \
93                 : "r0", "r2", "r3", "r4", "lp_count", "blink", "cc");   \
94                                                                         \
95                 r1;                                                     \
96         })                                                              \
97 )
98
99 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
100    PLT entries should not be allowed to define the value.
101    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
102    of the main executable's symbols, as for a COPY reloc.  */
103 #define elf_machine_type_class(type) \
104   ((((type) == R_ARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)   \
105    | (((type) == R_ARC_COPY) * ELF_RTYPE_CLASS_COPY))
106
107 /*
108  * Get the runtime address of GOT[0]
109  */
110 static __always_inline Elf32_Addr elf_machine_dynamic(void)
111 {
112         Elf32_Addr dyn;
113
114         __asm__("ld %0,[pcl,_DYNAMIC@gotpc]\n\t" : "=r" (dyn));
115         return dyn;
116
117 /*
118  * Another way would have been to simply return GP, which due to some
119  * PIC reference would be automatically setup by gcc in caller
120  *      register Elf32_Addr *got __asm__ ("gp"); return *got;
121  */
122 }
123
124 /* Return the run-time load address of the shared object.  */
125 static __always_inline Elf32_Addr elf_machine_load_address(void)
126 {
127     /* To find the loadaddr we subtract the runtime addr of a non-local symbol
128      * say _DYNAMIC from it's build-time addr.
129      * N.B., gotpc loads get optimized by the linker if it finds the symbol
130      * is resolved locally.
131      * A more robust - and efficient - solution would be to use a symbol
132      * set by the linker.  To make it actually save space, we'd have to
133      * suppress the unwanted text relocation in the linked dso, though.
134      * (I.e. in ldso.so.*, though it's just another dso as far as bfd/ld
135      * are concerned.)
136      */
137         Elf32_Addr addr, tmp;
138         __asm__ (
139         "ld  %1, [pcl, _DYNAMIC@gotpc] ;build addr of _DYNAMIC"   "\n"
140         "add %0, pcl, _DYNAMIC@pcl     ;runtime addr of _DYNAMIC" "\n"
141         "sub %0, %0, %1                ;delta"                    "\n"
142         : "=&r" (addr), "=r"(tmp)
143     );
144         return addr;
145 }
146
147 static __always_inline void
148 elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
149                       Elf32_Word relative_count)
150 {
151          Elf32_Rel * rpnt = (void *) rel_addr;
152         --rpnt;
153         do {
154                 Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset);
155                 *reloc_addr += load_off;
156         } while (--relative_count);
157 }