xref: /DragonStub/gnuefi/reloc_ia64.S (revision 803b49c40bb0b720b90d9c31d372911f1b946aa7)
1530d68baSNigel Croxon/* reloc_ia64.S - position independent IA-64 ELF shared object relocator
2530d68baSNigel Croxon   Copyright (C) 1999 Hewlett-Packard Co.
3530d68baSNigel Croxon	Contributed by David Mosberger <davidm@hpl.hp.com>.
4530d68baSNigel Croxon
5530d68baSNigel Croxon    All rights reserved.
6530d68baSNigel Croxon
7530d68baSNigel Croxon    Redistribution and use in source and binary forms, with or without
8530d68baSNigel Croxon    modification, are permitted provided that the following conditions
9530d68baSNigel Croxon    are met:
10530d68baSNigel Croxon
11530d68baSNigel Croxon    * Redistributions of source code must retain the above copyright
12530d68baSNigel Croxon      notice, this list of conditions and the following disclaimer.
13530d68baSNigel Croxon    * Redistributions in binary form must reproduce the above
14530d68baSNigel Croxon      copyright notice, this list of conditions and the following
15530d68baSNigel Croxon      disclaimer in the documentation and/or other materials
16530d68baSNigel Croxon      provided with the distribution.
17530d68baSNigel Croxon    * Neither the name of Hewlett-Packard Co. nor the names of its
18530d68baSNigel Croxon      contributors may be used to endorse or promote products derived
19530d68baSNigel Croxon      from this software without specific prior written permission.
20530d68baSNigel Croxon
21530d68baSNigel Croxon    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
22530d68baSNigel Croxon    CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
23530d68baSNigel Croxon    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24530d68baSNigel Croxon    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25530d68baSNigel Croxon    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
26530d68baSNigel Croxon    BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27530d68baSNigel Croxon    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28530d68baSNigel Croxon    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29530d68baSNigel Croxon    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30530d68baSNigel Croxon    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
31530d68baSNigel Croxon    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
32530d68baSNigel Croxon    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33530d68baSNigel Croxon    SUCH DAMAGE.
34530d68baSNigel Croxon*/
35530d68baSNigel Croxon
36530d68baSNigel Croxon/*
37530d68baSNigel Croxon * This is written in assembly because the entire code needs to be position
38530d68baSNigel Croxon * independent.  Note that the compiler does not generate code that's position
39530d68baSNigel Croxon * independent by itself because it relies on the global offset table being
40530d68baSNigel Croxon * relocated.
41530d68baSNigel Croxon */
42530d68baSNigel Croxon	.text
43530d68baSNigel Croxon	.psr abi64
44530d68baSNigel Croxon	.psr lsb
45530d68baSNigel Croxon	.lsb
46530d68baSNigel Croxon
47530d68baSNigel Croxon/*
48530d68baSNigel Croxon * This constant determines how many R_IA64_FPTR64LSB relocations we
49530d68baSNigel Croxon * can deal with.  If you get EFI_BUFFER_TOO_SMALL errors, you may
50530d68baSNigel Croxon * need to increase this number.
51530d68baSNigel Croxon */
52530d68baSNigel Croxon#define MAX_FUNCTION_DESCRIPTORS	750
53530d68baSNigel Croxon
54530d68baSNigel Croxon#define ST_VALUE_OFF	8		/* offset of st_value in elf sym */
55530d68baSNigel Croxon
56530d68baSNigel Croxon#define EFI_SUCCESS		0
57530d68baSNigel Croxon#define EFI_LOAD_ERROR		1
58530d68baSNigel Croxon#define EFI_BUFFER_TOO_SMALL	5
59530d68baSNigel Croxon
60530d68baSNigel Croxon#define DT_NULL		0		/* Marks end of dynamic section */
61530d68baSNigel Croxon#define DT_RELA		7		/* Address of Rela relocs */
62530d68baSNigel Croxon#define DT_RELASZ	8		/* Total size of Rela relocs */
63530d68baSNigel Croxon#define DT_RELAENT	9		/* Size of one Rela reloc */
64530d68baSNigel Croxon#define DT_SYMTAB	6		/* Address of symbol table */
65530d68baSNigel Croxon#define DT_SYMENT	11		/* Size of one symbol table entry */
66530d68baSNigel Croxon
67530d68baSNigel Croxon#define R_IA64_NONE		0
68530d68baSNigel Croxon#define R_IA64_REL64MSB		0x6e
69530d68baSNigel Croxon#define R_IA64_REL64LSB		0x6f
70530d68baSNigel Croxon#define R_IA64_DIR64MSB		0x26
71530d68baSNigel Croxon#define R_IA64_DIR64LSB		0x27
72530d68baSNigel Croxon#define R_IA64_FPTR64MSB	0x46
73530d68baSNigel Croxon#define R_IA64_FPTR64LSB	0x47
74530d68baSNigel Croxon
75530d68baSNigel Croxon#define	ldbase	in0	/* load address (address of .text) */
76530d68baSNigel Croxon#define	dyn	in1	/* address of _DYNAMIC */
77530d68baSNigel Croxon
78530d68baSNigel Croxon#define d_tag	r16
79530d68baSNigel Croxon#define d_val	r17
80530d68baSNigel Croxon#define rela	r18
81530d68baSNigel Croxon#define relasz	r19
82530d68baSNigel Croxon#define relaent	r20
83530d68baSNigel Croxon#define addr	r21
84530d68baSNigel Croxon#define r_info	r22
85530d68baSNigel Croxon#define r_offset r23
86530d68baSNigel Croxon#define r_addend r24
87530d68baSNigel Croxon#define r_type	r25
88530d68baSNigel Croxon#define r_sym	r25	/* alias of r_type ! */
89530d68baSNigel Croxon#define fptr	r26
90530d68baSNigel Croxon#define fptr_limit r27
91530d68baSNigel Croxon#define symtab	f8
92530d68baSNigel Croxon#define syment	f9
93530d68baSNigel Croxon#define ftmp	f10
94530d68baSNigel Croxon
95530d68baSNigel Croxon#define	target	r16
96530d68baSNigel Croxon#define val	r17
97530d68baSNigel Croxon
98530d68baSNigel Croxon#define NLOC	0
99530d68baSNigel Croxon
100530d68baSNigel Croxon#define Pnull		p6
101530d68baSNigel Croxon#define Prela		p7
102530d68baSNigel Croxon#define Prelasz		p8
103530d68baSNigel Croxon#define Prelaent	p9
104530d68baSNigel Croxon#define Psymtab		p10
105530d68baSNigel Croxon#define Psyment		p11
106530d68baSNigel Croxon
107530d68baSNigel Croxon#define Pnone		p6
108530d68baSNigel Croxon#define Prel		p7
109530d68baSNigel Croxon#define Pfptr		p8
110530d68baSNigel Croxon
111530d68baSNigel Croxon#define Pmore		p6
112530d68baSNigel Croxon
113530d68baSNigel Croxon#define Poom		p6	/* out-of-memory */
114530d68baSNigel Croxon
115530d68baSNigel Croxon	.global _relocate
116530d68baSNigel Croxon	.proc _relocate
117530d68baSNigel Croxon_relocate:
118530d68baSNigel Croxon	alloc r2=ar.pfs,2,0,0,0
119530d68baSNigel Croxon	movl	fptr = @gprel(fptr_mem_base)
120530d68baSNigel Croxon	;;
121530d68baSNigel Croxon	add	fptr = fptr, gp
122530d68baSNigel Croxon	movl	fptr_limit = @gprel(fptr_mem_limit)
123530d68baSNigel Croxon	;;
124530d68baSNigel Croxon	add	fptr_limit = fptr_limit, gp
125530d68baSNigel Croxon
126530d68baSNigel Croxonsearch_dynamic:
127530d68baSNigel Croxon	ld8	d_tag = [dyn],8
128530d68baSNigel Croxon	;;
129530d68baSNigel Croxon	ld8	d_val = [dyn],8
130530d68baSNigel Croxon	cmp.eq	Pnull,p0 = DT_NULL,d_tag
131530d68baSNigel Croxon(Pnull)	br.cond.sptk.few apply_relocs
132530d68baSNigel Croxon	cmp.eq	Prela,p0 = DT_RELA,d_tag
133530d68baSNigel Croxon	cmp.eq	Prelasz,p0 = DT_RELASZ,d_tag
134530d68baSNigel Croxon	cmp.eq	Psymtab,p0 = DT_SYMTAB,d_tag
135530d68baSNigel Croxon	cmp.eq	Psyment,p0 = DT_SYMENT,d_tag
136530d68baSNigel Croxon	cmp.eq	Prelaent,p0 = DT_RELAENT,d_tag
137530d68baSNigel Croxon	;;
138530d68baSNigel Croxon(Prela)	add rela = d_val, ldbase
139530d68baSNigel Croxon(Prelasz) mov relasz = d_val
140530d68baSNigel Croxon(Prelaent) mov relaent = d_val
141530d68baSNigel Croxon(Psymtab) add val = d_val, ldbase
142530d68baSNigel Croxon	;;
143530d68baSNigel Croxon(Psyment) setf.sig syment = d_val
144530d68baSNigel Croxon	;;
145530d68baSNigel Croxon(Psymtab) setf.sig symtab = val
146530d68baSNigel Croxon	br.sptk.few search_dynamic
147530d68baSNigel Croxon
148530d68baSNigel Croxonapply_loop:
149530d68baSNigel Croxon	ld8	r_offset = [rela]
150530d68baSNigel Croxon	add	addr = 8,rela
151530d68baSNigel Croxon	sub	relasz = relasz,relaent
152530d68baSNigel Croxon	;;
153530d68baSNigel Croxon
154530d68baSNigel Croxon	ld8	r_info = [addr],8
155530d68baSNigel Croxon	;;
156530d68baSNigel Croxon	ld8	r_addend = [addr]
157530d68baSNigel Croxon	add	target = ldbase, r_offset
158530d68baSNigel Croxon
159530d68baSNigel Croxon	add	rela = rela,relaent
160530d68baSNigel Croxon	extr.u	r_type = r_info, 0, 32
161530d68baSNigel Croxon	;;
162530d68baSNigel Croxon	cmp.eq	Pnone,p0 = R_IA64_NONE,r_type
163530d68baSNigel Croxon	cmp.eq	Prel,p0 = R_IA64_REL64LSB,r_type
164530d68baSNigel Croxon	cmp.eq	Pfptr,p0 = R_IA64_FPTR64LSB,r_type
165530d68baSNigel Croxon(Prel)	br.cond.sptk.few apply_REL64
166530d68baSNigel Croxon	;;
167530d68baSNigel Croxon	cmp.eq	Prel,p0 = R_IA64_DIR64LSB,r_type // treat DIR64 just like REL64
168530d68baSNigel Croxon
169530d68baSNigel Croxon(Pnone)	br.cond.sptk.few apply_relocs
170530d68baSNigel Croxon(Prel)	br.cond.sptk.few apply_REL64
171530d68baSNigel Croxon(Pfptr)	br.cond.sptk.few apply_FPTR64
172530d68baSNigel Croxon
173530d68baSNigel Croxon	mov	r8 = EFI_LOAD_ERROR
174530d68baSNigel Croxon	br.ret.sptk.few rp
175530d68baSNigel Croxon
176530d68baSNigel Croxonapply_relocs:
177530d68baSNigel Croxon	cmp.ltu	Pmore,p0=0,relasz
178530d68baSNigel Croxon(Pmore)	br.cond.sptk.few apply_loop
179530d68baSNigel Croxon
180530d68baSNigel Croxon	mov	r8 = EFI_SUCCESS
181530d68baSNigel Croxon	br.ret.sptk.few rp
182530d68baSNigel Croxon
183530d68baSNigel Croxonapply_REL64:
184530d68baSNigel Croxon	ld8 val = [target]
185530d68baSNigel Croxon	;;
186530d68baSNigel Croxon	add val = val,ldbase
187530d68baSNigel Croxon	;;
188530d68baSNigel Croxon	st8 [target] = val
189530d68baSNigel Croxon	br.cond.sptk.few apply_relocs
190530d68baSNigel Croxon
191530d68baSNigel Croxon	// FPTR relocs are a bit more interesting: we need to lookup
192530d68baSNigel Croxon	// the symbol's value in symtab, allocate 16 bytes of memory,
193530d68baSNigel Croxon	// store the value in [target] in the first and the gp in the
194530d68baSNigel Croxon	// second dword.
195530d68baSNigel Croxonapply_FPTR64:
196530d68baSNigel Croxon	st8	[target] = fptr
197530d68baSNigel Croxon	extr.u	r_sym = r_info,32,32
198530d68baSNigel Croxon	add	target = 8,fptr
199530d68baSNigel Croxon	;;
200530d68baSNigel Croxon
201530d68baSNigel Croxon	setf.sig ftmp = r_sym
202530d68baSNigel Croxon	mov	r8=EFI_BUFFER_TOO_SMALL
203530d68baSNigel Croxon	;;
204530d68baSNigel Croxon	cmp.geu	Poom,p0 = fptr,fptr_limit
205530d68baSNigel Croxon
206530d68baSNigel Croxon	xma.lu	ftmp = ftmp,syment,symtab
207530d68baSNigel Croxon(Poom)	br.ret.sptk.few rp
208530d68baSNigel Croxon	;;
209530d68baSNigel Croxon	getf.sig addr = ftmp
210530d68baSNigel Croxon	st8	[target] = gp
211530d68baSNigel Croxon	;;
212530d68baSNigel Croxon	add	addr = ST_VALUE_OFF, addr
213530d68baSNigel Croxon	;;
214530d68baSNigel Croxon	ld8	val = [addr]
215530d68baSNigel Croxon	;;
216530d68baSNigel Croxon	add	val = val,ldbase
217530d68baSNigel Croxon	;;
218530d68baSNigel Croxon	st8	[fptr] = val,16
219530d68baSNigel Croxon	br.cond.sptk.few apply_relocs
220530d68baSNigel Croxon
221530d68baSNigel Croxon	.endp _relocate
222530d68baSNigel Croxon
223530d68baSNigel Croxon	.data
224530d68baSNigel Croxon	.align 16
225530d68baSNigel Croxonfptr_mem_base:
226530d68baSNigel Croxon	.space  MAX_FUNCTION_DESCRIPTORS*16
227530d68baSNigel Croxonfptr_mem_limit:
228*803b49c4SSergei Trofimovich
229*803b49c4SSergei Trofimovich#if defined(__ELF__) && defined(__linux__)
230*803b49c4SSergei Trofimovich	.section .note.GNU-stack,"",%progbits
231*803b49c4SSergei Trofimovich#endif
232