Home | History | Annotate | Line # | Download | only in gnuefi
      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 (at) 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 
    128 search_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 
    150 apply_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 
    178 apply_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 
    185 apply_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.
    197 apply_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
    227 fptr_mem_base:
    228 	.space  MAX_FUNCTION_DESCRIPTORS*16
    229 fptr_mem_limit:
    230