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