Imported Upstream version 3.0
[platform/upstream/gnu-efi.git] / gnuefi / reloc_ia64.S
1 /* reloc_ia64.S - position independent IA-64 ELF shared object relocator
2    Copyright (C) 1999 Hewlett-Packard Co.
3         Contributed by David Mosberger <davidm@hpl.hp.com>.
4
5     All rights reserved.
6
7     Redistribution and use in source and binary forms, with or without
8     modification, are permitted provided that the following conditions
9     are met:
10
11     * Redistributions of source code must retain the above copyright
12       notice, this list of conditions and the following disclaimer.
13     * Redistributions in binary form must reproduce the above
14       copyright notice, this list of conditions and the following
15       disclaimer in the documentation and/or other materials
16       provided with the distribution.
17     * Neither the name of Hewlett-Packard Co. nor the names of its
18       contributors may be used to endorse or promote products derived
19       from this software without specific prior written permission.
20
21     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
23     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
26     BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27     OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28     PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29     PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31     TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
32     THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33     SUCH DAMAGE.
34 */
35
36 /*
37  * This is written in assembly because the entire code needs to be position
38  * independent.  Note that the compiler does not generate code that's position
39  * independent by itself because it relies on the global offset table being
40  * relocated.
41  */
42         .text
43         .psr abi64
44         .psr lsb
45         .lsb
46
47 /*
48  * This constant determines how many R_IA64_FPTR64LSB relocations we
49  * can deal with.  If you get EFI_BUFFER_TOO_SMALL errors, you may
50  * need to increase this number.
51  */
52 #define MAX_FUNCTION_DESCRIPTORS        750
53
54 #define ST_VALUE_OFF    8               /* offset of st_value in elf sym */
55
56 #define EFI_SUCCESS             0
57 #define EFI_LOAD_ERROR          1
58 #define EFI_BUFFER_TOO_SMALL    5
59
60 #define DT_NULL         0               /* Marks end of dynamic section */
61 #define DT_RELA         7               /* Address of Rela relocs */
62 #define DT_RELASZ       8               /* Total size of Rela relocs */
63 #define DT_RELAENT      9               /* Size of one Rela reloc */
64 #define DT_SYMTAB       6               /* Address of symbol table */
65 #define DT_SYMENT       11              /* Size of one symbol table entry */
66
67 #define R_IA64_NONE             0
68 #define R_IA64_REL64MSB         0x6e
69 #define R_IA64_REL64LSB         0x6f
70 #define R_IA64_DIR64MSB         0x26
71 #define R_IA64_DIR64LSB         0x27
72 #define R_IA64_FPTR64MSB        0x46
73 #define R_IA64_FPTR64LSB        0x47
74
75 #define ldbase  in0     /* load address (address of .text) */
76 #define dyn     in1     /* address of _DYNAMIC */
77
78 #define d_tag   r16
79 #define d_val   r17
80 #define rela    r18
81 #define relasz  r19
82 #define relaent r20
83 #define addr    r21
84 #define r_info  r22
85 #define r_offset r23
86 #define r_addend r24
87 #define r_type  r25
88 #define r_sym   r25     /* alias of r_type ! */
89 #define fptr    r26
90 #define fptr_limit r27
91 #define symtab  f8
92 #define syment  f9
93 #define ftmp    f10
94
95 #define target  r16
96 #define val     r17
97
98 #define NLOC    0
99
100 #define Pnull           p6
101 #define Prela           p7
102 #define Prelasz         p8
103 #define Prelaent        p9
104 #define Psymtab         p10
105 #define Psyment         p11
106
107 #define Pnone           p6
108 #define Prel            p7
109 #define Pfptr           p8
110
111 #define Pmore           p6
112
113 #define Poom            p6      /* out-of-memory */
114
115         .global _relocate
116         .proc _relocate
117 _relocate:
118         alloc r2=ar.pfs,2,0,0,0
119         movl    fptr = @gprel(fptr_mem_base)
120         ;;
121         add     fptr = fptr, gp
122         movl    fptr_limit = @gprel(fptr_mem_limit)
123         ;;
124         add     fptr_limit = fptr_limit, gp
125
126 search_dynamic:
127         ld8     d_tag = [dyn],8
128         ;;
129         ld8     d_val = [dyn],8
130         cmp.eq  Pnull,p0 = DT_NULL,d_tag
131 (Pnull) br.cond.sptk.few apply_relocs
132         cmp.eq  Prela,p0 = DT_RELA,d_tag
133         cmp.eq  Prelasz,p0 = DT_RELASZ,d_tag
134         cmp.eq  Psymtab,p0 = DT_SYMTAB,d_tag
135         cmp.eq  Psyment,p0 = DT_SYMENT,d_tag
136         cmp.eq  Prelaent,p0 = DT_RELAENT,d_tag
137         ;;
138 (Prela) add rela = d_val, ldbase
139 (Prelasz) mov relasz = d_val
140 (Prelaent) mov relaent = d_val
141 (Psymtab) add val = d_val, ldbase
142         ;;
143 (Psyment) setf.sig syment = d_val
144         ;;
145 (Psymtab) setf.sig symtab = val
146         br.sptk.few search_dynamic
147
148 apply_loop:
149         ld8     r_offset = [rela]
150         add     addr = 8,rela
151         sub     relasz = relasz,relaent
152         ;;
153
154         ld8     r_info = [addr],8
155         ;;
156         ld8     r_addend = [addr]
157         add     target = ldbase, r_offset
158
159         add     rela = rela,relaent
160         extr.u  r_type = r_info, 0, 32
161         ;;
162         cmp.eq  Pnone,p0 = R_IA64_NONE,r_type
163         cmp.eq  Prel,p0 = R_IA64_REL64LSB,r_type
164         cmp.eq  Pfptr,p0 = R_IA64_FPTR64LSB,r_type
165 (Prel)  br.cond.sptk.few apply_REL64
166         ;;
167         cmp.eq  Prel,p0 = R_IA64_DIR64LSB,r_type // treat DIR64 just like REL64
168
169 (Pnone) br.cond.sptk.few apply_relocs
170 (Prel)  br.cond.sptk.few apply_REL64
171 (Pfptr) br.cond.sptk.few apply_FPTR64
172
173         mov     r8 = EFI_LOAD_ERROR
174         br.ret.sptk.few rp
175
176 apply_relocs:
177         cmp.ltu Pmore,p0=0,relasz
178 (Pmore) br.cond.sptk.few apply_loop
179
180         mov     r8 = EFI_SUCCESS
181         br.ret.sptk.few rp
182
183 apply_REL64:
184         ld8 val = [target]
185         ;;
186         add val = val,ldbase
187         ;;
188         st8 [target] = val
189         br.cond.sptk.few apply_relocs
190
191         // FPTR relocs are a bit more interesting: we need to lookup
192         // the symbol's value in symtab, allocate 16 bytes of memory,
193         // store the value in [target] in the first and the gp in the
194         // second dword.
195 apply_FPTR64:
196         st8     [target] = fptr
197         extr.u  r_sym = r_info,32,32
198         add     target = 8,fptr
199         ;;
200
201         setf.sig ftmp = r_sym
202         mov     r8=EFI_BUFFER_TOO_SMALL
203         ;;
204         cmp.geu Poom,p0 = fptr,fptr_limit
205
206         xma.lu  ftmp = ftmp,syment,symtab
207 (Poom)  br.ret.sptk.few rp
208         ;;
209         getf.sig addr = ftmp
210         st8     [target] = gp
211         ;;
212         add     addr = ST_VALUE_OFF, addr
213         ;;
214         ld8     val = [addr]
215         ;;
216         add     val = val,ldbase
217         ;;
218         st8     [fptr] = val,16
219         br.cond.sptk.few apply_relocs
220
221         .endp _relocate
222
223         .data
224         .align 16
225 fptr_mem_base:
226         .space  MAX_FUNCTION_DESCRIPTORS*16
227 fptr_mem_limit: