Subversion Repositories HelenOS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2726 vana 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
   This file is part of GNU-EFI, the GNU EFI development environment.
6
 
7
   GNU EFI is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 2, or (at your option)
10
   any later version.
11
 
12
   GNU EFI is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
 
17
   You should have received a copy of the GNU General Public License
18
   along with GNU EFI; see the file COPYING.  If not, write to the Free
19
   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20
   02111-1307, USA. */
21
 
22
/*
23
 * This is written in assembly because the entire code needs to be position
24
 * independent.  Note that the compiler does not generate code that's position
25
 * independent by itself because it relies on the global offset table being
26
 * relocated.
27
 */
28
	.text
29
	.psr abi64
30
	.psr lsb
31
	.lsb
32
 
33
/*
34
 * This constant determines how many R_IA64_FPTR64LSB relocations we
35
 * can deal with.  If you get EFI_BUFFER_TOO_SMALL errors, you may
36
 * need to increase this number.
37
 */
38
#define MAX_FUNCTION_DESCRIPTORS	750
39
 
40
#define ST_VALUE_OFF	8		/* offset of st_value in elf sym */
41
 
42
#define EFI_SUCCESS		0
43
#define EFI_LOAD_ERROR		1
44
#define EFI_BUFFER_TOO_SMALL	5
45
 
46
#define DT_NULL		0		/* Marks end of dynamic section */
47
#define DT_RELA		7		/* Address of Rela relocs */
48
#define DT_RELASZ	8		/* Total size of Rela relocs */
49
#define DT_RELAENT	9		/* Size of one Rela reloc */
50
#define DT_SYMTAB	6		/* Address of symbol table */
51
#define DT_SYMENT	11		/* Size of one symbol table entry */
52
 
53
#define R_IA64_NONE		0
54
#define R_IA64_REL64MSB		0x6e
55
#define R_IA64_REL64LSB		0x6f
56
#define R_IA64_DIR64MSB		0x26
57
#define R_IA64_DIR64LSB		0x27
58
#define R_IA64_FPTR64MSB	0x46
59
#define R_IA64_FPTR64LSB	0x47
60
 
61
#define	ldbase	in0	/* load address (address of .text) */
62
#define	dyn	in1	/* address of _DYNAMIC */
63
 
64
#define d_tag	r16
65
#define d_val	r17
66
#define rela	r18
67
#define relasz	r19
68
#define relaent	r20
69
#define addr	r21
70
#define r_info	r22
71
#define r_offset r23
72
#define r_addend r24
73
#define r_type	r25
74
#define r_sym	r25	/* alias of r_type ! */
75
#define fptr	r26
76
#define fptr_limit r27
77
#define symtab	f8
78
#define syment	f9
79
#define ftmp	f10
80
 
81
#define	target	r16
82
#define val	r17
83
 
84
#define NLOC	0
85
 
86
#define Pnull		p6
87
#define Prela		p7
88
#define Prelasz		p8
89
#define Prelaent	p9
90
#define Psymtab		p10
91
#define Psyment		p11
92
 
93
#define Pnone		p6
94
#define Prel		p7
95
#define Pfptr		p8
96
 
97
#define Pmore		p6
98
 
99
#define Poom		p6	/* out-of-memory */
100
 
101
	.global _relocate
102
	.proc _relocate
103
_relocate:
104
	alloc r2=ar.pfs,2,0,0,0
105
	movl	fptr = @gprel(fptr_mem_base)
106
	;;
107
	add	fptr = fptr, gp
108
	movl	fptr_limit = @gprel(fptr_mem_limit)
109
	;;
110
	add	fptr_limit = fptr_limit, gp
111
 
112
search_dynamic:
113
	ld8	d_tag = [dyn],8
114
	;;
115
	ld8	d_val = [dyn],8
116
	cmp.eq	Pnull,p0 = DT_NULL,d_tag
117
(Pnull)	br.cond.sptk.few apply_relocs
118
	cmp.eq	Prela,p0 = DT_RELA,d_tag
119
	cmp.eq	Prelasz,p0 = DT_RELASZ,d_tag
120
	cmp.eq	Psymtab,p0 = DT_SYMTAB,d_tag
121
	cmp.eq	Psyment,p0 = DT_SYMENT,d_tag
122
	cmp.eq	Prelaent,p0 = DT_RELAENT,d_tag
123
	;;
124
(Prela)	add rela = d_val, ldbase
125
(Prelasz) mov relasz = d_val
126
(Prelaent) mov relaent = d_val
127
(Psymtab) add val = d_val, ldbase
128
(Psyment) setf.sig syment = d_val
129
	;;
130
(Psymtab) setf.sig symtab = val
131
	br.sptk.few search_dynamic
132
 
133
apply_loop:
134
	ld8	r_offset = [rela]
135
	add	addr = 8,rela
136
	sub	relasz = relasz,relaent
137
	;;
138
 
139
	ld8	r_info = [addr],8
140
	;;
141
	ld8	r_addend = [addr]
142
	add	target = ldbase, r_offset
143
 
144
	add	rela = rela,relaent
145
	extr.u	r_type = r_info, 0, 32
146
	;;
147
	cmp.eq	Pnone,p0 = R_IA64_NONE,r_type
148
	cmp.eq	Prel,p0 = R_IA64_REL64LSB,r_type
149
	cmp.eq	Pfptr,p0 = R_IA64_FPTR64LSB,r_type
150
(Prel)	br.cond.sptk.few apply_REL64
151
	;;
152
	cmp.eq	Prel,p0 = R_IA64_DIR64LSB,r_type // treat DIR64 just like REL64
153
 
154
(Pnone)	br.cond.sptk.few apply_relocs
155
(Prel)	br.cond.sptk.few apply_REL64
156
(Pfptr)	br.cond.sptk.few apply_FPTR64
157
 
158
	mov	r8 = EFI_LOAD_ERROR
159
	br.ret.sptk.few rp
160
 
161
apply_relocs:
162
	cmp.ltu	Pmore,p0=0,relasz
163
(Pmore)	br.cond.sptk.few apply_loop
164
 
165
	mov	r8 = EFI_SUCCESS
166
	br.ret.sptk.few rp
167
 
168
apply_REL64:
169
	ld8 val = [target]
170
	;;
171
	add val = val,ldbase
172
	;;
173
	st8 [target] = val
174
	br.cond.sptk.few apply_relocs
175
 
176
	// FPTR relocs are a bit more interesting: we need to lookup
177
	// the symbol's value in symtab, allocate 16 bytes of memory,
178
	// store the value in [target] in the first and the gp in the
179
	// second dword.
180
apply_FPTR64:
181
	st8	[target] = fptr
182
	extr.u	r_sym = r_info,32,32
183
	add	target = 8,fptr
184
	;;
185
 
186
	setf.sig ftmp = r_sym
187
	mov	r8=EFI_BUFFER_TOO_SMALL
188
	;;
189
	cmp.geu	Poom,p0 = fptr,fptr_limit
190
 
191
	xma.lu	ftmp = ftmp,syment,symtab
192
(Poom)	br.ret.sptk.few rp
193
	;;
194
	getf.sig addr = ftmp
195
	st8	[target] = gp
196
	;;
197
	add	addr = ST_VALUE_OFF, addr
198
	;;
199
	ld8	val = [addr]
200
	;;
201
	add	val = val,ldbase
202
	;;
203
	st8	[fptr] = val,16
204
	br.cond.sptk.few apply_relocs
205
 
206
	.endp _relocate
207
 
208
	.data
209
	.align 16
210
fptr_mem_base:
211
	.space  MAX_FUNCTION_DESCRIPTORS*16
212
fptr_mem_limit: