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 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 126search_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 148apply_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 176apply_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 183apply_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. 195apply_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 225fptr_mem_base: 226 .space MAX_FUNCTION_DESCRIPTORS*16 227fptr_mem_limit: 228 229#if defined(__ELF__) && defined(__linux__) 230 .section .note.GNU-stack,"",%progbits 231#endif 232