Home | History | Annotate | Download | only in gnuefi
      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 (at) 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 
    126 search_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 
    148 apply_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 
    176 apply_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 
    183 apply_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.
    195 apply_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
    225 fptr_mem_base:
    226 	.space  MAX_FUNCTION_DESCRIPTORS*16
    227 fptr_mem_limit:
    228