Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/* reloc_ia64.S - position independent IA-64 ELF shared object relocator
Copyright (C) 1999 Hewlett-Packard Co.
Contributed by David Mosberger <davidm@hpl.hp.com>.
This file is part of GNU-EFI, the GNU EFI development environment.
GNU EFI is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU EFI is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU EFI; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/*
* This is written in assembly because the entire code needs to be position
* independent. Note that the compiler does not generate code that's position
* independent by itself because it relies on the global offset table being
* relocated.
*/
.text
.psr abi64
.psr lsb
.lsb
/*
* This constant determines how many R_IA64_FPTR64LSB relocations we
* can deal with. If you get EFI_BUFFER_TOO_SMALL errors, you may
* need to increase this number.
*/
#define MAX_FUNCTION_DESCRIPTORS 750
#define ST_VALUE_OFF 8 /* offset of st_value in elf sym */
#define EFI_SUCCESS 0
#define EFI_LOAD_ERROR 1
#define EFI_BUFFER_TOO_SMALL 5
#define DT_NULL 0 /* Marks end of dynamic section */
#define DT_RELA 7 /* Address of Rela relocs */
#define DT_RELASZ 8 /* Total size of Rela relocs */
#define DT_RELAENT 9 /* Size of one Rela reloc */
#define DT_SYMTAB 6 /* Address of symbol table */
#define DT_SYMENT 11 /* Size of one symbol table entry */
#define R_IA64_NONE 0
#define R_IA64_REL64MSB 0x6e
#define R_IA64_REL64LSB 0x6f
#define R_IA64_DIR64MSB 0x26
#define R_IA64_DIR64LSB 0x27
#define R_IA64_FPTR64MSB 0x46
#define R_IA64_FPTR64LSB 0x47
#define ldbase in0 /* load address (address of .text) */
#define dyn in1 /* address of _DYNAMIC */
#define d_tag r16
#define d_val r17
#define rela r18
#define relasz r19
#define relaent r20
#define addr r21
#define r_info r22
#define r_offset r23
#define r_addend r24
#define r_type r25
#define r_sym r25 /* alias of r_type ! */
#define fptr r26
#define fptr_limit r27
#define symtab f8
#define syment f9
#define ftmp f10
#define target r16
#define val r17
#define NLOC 0
#define Pnull p6
#define Prela p7
#define Prelasz p8
#define Prelaent p9
#define Psymtab p10
#define Psyment p11
#define Pnone p6
#define Prel p7
#define Pfptr p8
#define Pmore p6
#define Poom p6 /* out-of-memory */
.global _relocate
.proc _relocate
_relocate:
alloc r2=ar.pfs,2,0,0,0
movl fptr = @gprel(fptr_mem_base)
;;
add fptr = fptr, gp
movl fptr_limit = @gprel(fptr_mem_limit)
;;
add fptr_limit = fptr_limit, gp
search_dynamic:
ld8 d_tag = [dyn],8
;;
ld8 d_val = [dyn],8
cmp.eq Pnull,p0 = DT_NULL,d_tag
(Pnull) br.cond.sptk.few apply_relocs
cmp.eq Prela,p0 = DT_RELA,d_tag
cmp.eq Prelasz,p0 = DT_RELASZ,d_tag
cmp.eq Psymtab,p0 = DT_SYMTAB,d_tag
cmp.eq Psyment,p0 = DT_SYMENT,d_tag
cmp.eq Prelaent,p0 = DT_RELAENT,d_tag
;;
(Prela) add rela = d_val, ldbase
(Prelasz) mov relasz = d_val
(Prelaent) mov relaent = d_val
(Psymtab) add val = d_val, ldbase
(Psyment) setf.sig syment = d_val
;;
(Psymtab) setf.sig symtab = val
br.sptk.few search_dynamic
apply_loop:
ld8 r_offset = [rela]
add addr = 8,rela
sub relasz = relasz,relaent
;;
ld8 r_info = [addr],8
;;
ld8 r_addend = [addr]
add target = ldbase, r_offset
add rela = rela,relaent
extr.u r_type = r_info, 0, 32
;;
cmp.eq Pnone,p0 = R_IA64_NONE,r_type
cmp.eq Prel,p0 = R_IA64_REL64LSB,r_type
cmp.eq Pfptr,p0 = R_IA64_FPTR64LSB,r_type
(Prel) br.cond.sptk.few apply_REL64
;;
cmp.eq Prel,p0 = R_IA64_DIR64LSB,r_type // treat DIR64 just like REL64
(Pnone) br.cond.sptk.few apply_relocs
(Prel) br.cond.sptk.few apply_REL64
(Pfptr) br.cond.sptk.few apply_FPTR64
mov r8 = EFI_LOAD_ERROR
br.ret.sptk.few rp
apply_relocs:
cmp.ltu Pmore,p0=0,relasz
(Pmore) br.cond.sptk.few apply_loop
mov r8 = EFI_SUCCESS
br.ret.sptk.few rp
apply_REL64:
ld8 val = [target]
;;
add val = val,ldbase
;;
st8 [target] = val
br.cond.sptk.few apply_relocs
// FPTR relocs are a bit more interesting: we need to lookup
// the symbol's value in symtab, allocate 16 bytes of memory,
// store the value in [target] in the first and the gp in the
// second dword.
apply_FPTR64:
st8 [target] = fptr
extr.u r_sym = r_info,32,32
add target = 8,fptr
;;
setf.sig ftmp = r_sym
mov r8=EFI_BUFFER_TOO_SMALL
;;
cmp.geu Poom,p0 = fptr,fptr_limit
xma.lu ftmp = ftmp,syment,symtab
(Poom) br.ret.sptk.few rp
;;
getf.sig addr = ftmp
st8 [target] = gp
;;
add addr = ST_VALUE_OFF, addr
;;
ld8 val = [addr]
;;
add val = val,ldbase
;;
st8 [fptr] = val,16
br.cond.sptk.few apply_relocs
.endp _relocate
.data
.align 16
fptr_mem_base:
.space MAX_FUNCTION_DESCRIPTORS*16
fptr_mem_limit: