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
126search_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
148apply_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
176apply_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
183apply_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.
195apply_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
225fptr_mem_base:
226	.space  MAX_FUNCTION_DESCRIPTORS*16
227fptr_mem_limit:
228