2013-04-16 16:02:58 -07:00
/* This is included from relocs_32/64.c */
2009-12-14 13:55:20 -08:00
2013-04-12 13:13:42 -07:00
# define ElfW(type) _ElfW(ELF_BITS, type)
# define _ElfW(bits, type) __ElfW(bits, type)
# define __ElfW(bits, type) Elf##bits##_##type
2013-04-12 13:13:44 -07:00
# define Elf_Addr ElfW(Addr)
2013-04-12 13:13:42 -07:00
# define Elf_Ehdr ElfW(Ehdr)
# define Elf_Phdr ElfW(Phdr)
# define Elf_Shdr ElfW(Shdr)
# define Elf_Sym ElfW(Sym)
static Elf_Ehdr ehdr ;
2013-04-12 13:13:43 -07:00
struct relocs {
uint32_t * offset ;
unsigned long count ;
unsigned long size ;
} ;
static struct relocs relocs16 ;
static struct relocs relocs32 ;
2014-11-04 08:50:18 +00:00
# if ELF_BITS == 64
static struct relocs relocs32neg ;
2013-04-12 13:13:44 -07:00
static struct relocs relocs64 ;
2014-11-04 08:50:18 +00:00
# endif
2006-12-07 02:14:04 +01:00
2008-06-30 14:42:18 -07:00
struct section {
2013-04-12 13:13:42 -07:00
Elf_Shdr shdr ;
2008-06-30 14:42:18 -07:00
struct section * link ;
2013-04-12 13:13:42 -07:00
Elf_Sym * symtab ;
Elf_Rel * reltab ;
2008-06-30 14:42:18 -07:00
char * strtab ;
} ;
static struct section * secs ;
2012-05-08 21:22:24 +03:00
static const char * const sym_regex_kernel [ S_NSYMTYPES ] = {
2006-12-07 02:14:04 +01:00
/*
* Following symbols have been audited . There values are constant and do
* not change if bzImage is loaded at a different physical address than
* the address for which it has been compiled . Don ' t warn user about
* absolute relocations present w . r . t these symbols .
*/
2012-05-08 21:22:24 +03:00
[ S_ABS ] =
2009-12-14 13:55:20 -08:00
" ^(xen_irq_disable_direct_reloc$| "
" xen_save_fl_direct_reloc$| "
" VDSO| "
2012-05-08 21:22:24 +03:00
" __crc_) " ,
2006-12-07 02:14:04 +01:00
2009-12-14 13:55:20 -08:00
/*
* These symbols are known to be relative , even if the linker marks them
* as absolute ( typically defined outside any section in the linker script . )
*/
2012-05-08 21:22:24 +03:00
[ S_REL ] =
2012-05-18 00:24:09 -07:00
" ^(__init_(begin|end)| "
" __x86_cpu_dev_(start|end)| "
" (__parainstructions|__alt_instructions)(|_end)| "
" (__iommu_table|__apicdrivers|__smp_locks)(|_end)| "
2012-05-23 14:02:34 -07:00
" __(start|end)_pci_.*| "
" __(start|end)_builtin_fw| "
" __(start|stop)___ksymtab(|_gpl|_unused|_unused_gpl|_gpl_future)| "
" __(start|stop)___kcrctab(|_gpl|_unused|_unused_gpl|_gpl_future)| "
" __(start|stop)___param| "
" __(start|stop)___modver| "
" __(start|stop)___bug_table| "
" __tracedata_(start|end)| "
" __(start|stop)_notes| "
" __end_rodata| "
" __initramfs_start| "
2012-05-24 07:01:38 -07:00
" (jiffies|jiffies_64)| "
2013-04-16 16:02:58 -07:00
# if ELF_BITS == 64
2013-04-12 13:13:44 -07:00
" __per_cpu_load| "
" init_per_cpu__.*| "
" __end_rodata_hpage_align| "
# endif
2014-03-17 23:22:01 +01:00
" __vvar_page| "
2012-05-18 00:24:09 -07:00
" _end)$ "
2012-05-08 21:22:24 +03:00
} ;
static const char * const sym_regex_realmode [ S_NSYMTYPES ] = {
2012-05-08 21:22:31 +03:00
/*
* These symbols are known to be relative , even if the linker marks them
* as absolute ( typically defined outside any section in the linker script . )
*/
[ S_REL ] =
" ^pa_ " ,
2012-05-08 21:22:24 +03:00
/*
* These are 16 - bit segment symbols when compiling 16 - bit code .
*/
[ S_SEG ] =
" ^real_mode_seg$ " ,
/*
* These are offsets belonging to segments , as opposed to linear addresses ,
* when compiling 16 - bit code .
*/
[ S_LIN ] =
" ^pa_ " ,
} ;
static const char * const * sym_regex ;
static regex_t sym_regex_c [ S_NSYMTYPES ] ;
static int is_reloc ( enum symtype type , const char * sym_name )
2006-12-07 02:14:04 +01:00
{
2012-05-08 21:22:24 +03:00
return sym_regex [ type ] & &
! regexec ( & sym_regex_c [ type ] , sym_name , 0 , NULL , 0 ) ;
2009-12-14 13:55:20 -08:00
}
2006-12-07 02:14:04 +01:00
2012-05-08 21:22:24 +03:00
static void regex_init ( int use_real_mode )
2009-12-14 13:55:20 -08:00
{
char errbuf [ 128 ] ;
int err ;
2012-05-08 21:22:24 +03:00
int i ;
2009-12-14 13:55:20 -08:00
2012-05-08 21:22:24 +03:00
if ( use_real_mode )
sym_regex = sym_regex_realmode ;
else
sym_regex = sym_regex_kernel ;
for ( i = 0 ; i < S_NSYMTYPES ; i + + ) {
if ( ! sym_regex [ i ] )
continue ;
err = regcomp ( & sym_regex_c [ i ] , sym_regex [ i ] ,
REG_EXTENDED | REG_NOSUB ) ;
if ( err ) {
regerror ( err , & sym_regex_c [ i ] , errbuf , sizeof errbuf ) ;
die ( " %s " , errbuf ) ;
}
2009-12-14 13:55:20 -08:00
}
2006-12-07 02:14:04 +01:00
}
2006-12-07 02:14:04 +01:00
static const char * sym_type ( unsigned type )
{
static const char * type_name [ ] = {
# define SYM_TYPE(X) [X] = #X
SYM_TYPE ( STT_NOTYPE ) ,
SYM_TYPE ( STT_OBJECT ) ,
SYM_TYPE ( STT_FUNC ) ,
SYM_TYPE ( STT_SECTION ) ,
SYM_TYPE ( STT_FILE ) ,
SYM_TYPE ( STT_COMMON ) ,
SYM_TYPE ( STT_TLS ) ,
# undef SYM_TYPE
} ;
const char * name = " unknown sym type name " ;
2007-02-17 19:10:01 +01:00
if ( type < ARRAY_SIZE ( type_name ) ) {
2006-12-07 02:14:04 +01:00
name = type_name [ type ] ;
}
return name ;
}
static const char * sym_bind ( unsigned bind )
{
static const char * bind_name [ ] = {
# define SYM_BIND(X) [X] = #X
SYM_BIND ( STB_LOCAL ) ,
SYM_BIND ( STB_GLOBAL ) ,
SYM_BIND ( STB_WEAK ) ,
# undef SYM_BIND
} ;
const char * name = " unknown sym bind name " ;
2007-02-17 19:10:01 +01:00
if ( bind < ARRAY_SIZE ( bind_name ) ) {
2006-12-07 02:14:04 +01:00
name = bind_name [ bind ] ;
}
return name ;
}
static const char * sym_visibility ( unsigned visibility )
{
static const char * visibility_name [ ] = {
# define SYM_VISIBILITY(X) [X] = #X
SYM_VISIBILITY ( STV_DEFAULT ) ,
SYM_VISIBILITY ( STV_INTERNAL ) ,
SYM_VISIBILITY ( STV_HIDDEN ) ,
SYM_VISIBILITY ( STV_PROTECTED ) ,
# undef SYM_VISIBILITY
} ;
const char * name = " unknown sym visibility name " ;
2007-02-17 19:10:01 +01:00
if ( visibility < ARRAY_SIZE ( visibility_name ) ) {
2006-12-07 02:14:04 +01:00
name = visibility_name [ visibility ] ;
}
return name ;
}
static const char * rel_type ( unsigned type )
{
static const char * type_name [ ] = {
# define REL_TYPE(X) [X] = #X
2013-04-16 16:02:58 -07:00
# if ELF_BITS == 64
2013-04-12 13:13:44 -07:00
REL_TYPE ( R_X86_64_NONE ) ,
REL_TYPE ( R_X86_64_64 ) ,
REL_TYPE ( R_X86_64_PC32 ) ,
REL_TYPE ( R_X86_64_GOT32 ) ,
REL_TYPE ( R_X86_64_PLT32 ) ,
REL_TYPE ( R_X86_64_COPY ) ,
REL_TYPE ( R_X86_64_GLOB_DAT ) ,
REL_TYPE ( R_X86_64_JUMP_SLOT ) ,
REL_TYPE ( R_X86_64_RELATIVE ) ,
REL_TYPE ( R_X86_64_GOTPCREL ) ,
REL_TYPE ( R_X86_64_32 ) ,
REL_TYPE ( R_X86_64_32S ) ,
REL_TYPE ( R_X86_64_16 ) ,
REL_TYPE ( R_X86_64_PC16 ) ,
REL_TYPE ( R_X86_64_8 ) ,
REL_TYPE ( R_X86_64_PC8 ) ,
# else
2006-12-07 02:14:04 +01:00
REL_TYPE ( R_386_NONE ) ,
REL_TYPE ( R_386_32 ) ,
REL_TYPE ( R_386_PC32 ) ,
REL_TYPE ( R_386_GOT32 ) ,
REL_TYPE ( R_386_PLT32 ) ,
REL_TYPE ( R_386_COPY ) ,
REL_TYPE ( R_386_GLOB_DAT ) ,
REL_TYPE ( R_386_JMP_SLOT ) ,
REL_TYPE ( R_386_RELATIVE ) ,
REL_TYPE ( R_386_GOTOFF ) ,
REL_TYPE ( R_386_GOTPC ) ,
2012-05-08 21:22:24 +03:00
REL_TYPE ( R_386_8 ) ,
REL_TYPE ( R_386_PC8 ) ,
REL_TYPE ( R_386_16 ) ,
REL_TYPE ( R_386_PC16 ) ,
2013-04-12 13:13:44 -07:00
# endif
2006-12-07 02:14:04 +01:00
# undef REL_TYPE
} ;
const char * name = " unknown type rel type name " ;
2009-12-14 13:55:20 -08:00
if ( type < ARRAY_SIZE ( type_name ) & & type_name [ type ] ) {
2006-12-07 02:14:04 +01:00
name = type_name [ type ] ;
}
return name ;
}
static const char * sec_name ( unsigned shndx )
{
const char * sec_strtab ;
const char * name ;
2008-06-30 14:42:18 -07:00
sec_strtab = secs [ ehdr . e_shstrndx ] . strtab ;
2006-12-07 02:14:04 +01:00
name = " <noname> " ;
if ( shndx < ehdr . e_shnum ) {
2008-06-30 14:42:18 -07:00
name = sec_strtab + secs [ shndx ] . shdr . sh_name ;
2006-12-07 02:14:04 +01:00
}
else if ( shndx = = SHN_ABS ) {
name = " ABSOLUTE " ;
}
else if ( shndx = = SHN_COMMON ) {
name = " COMMON " ;
}
return name ;
}
2013-04-12 13:13:42 -07:00
static const char * sym_name ( const char * sym_strtab , Elf_Sym * sym )
2006-12-07 02:14:04 +01:00
{
const char * name ;
name = " <noname> " ;
if ( sym - > st_name ) {
name = sym_strtab + sym - > st_name ;
}
else {
2012-05-08 21:22:24 +03:00
name = sec_name ( sym - > st_shndx ) ;
2006-12-07 02:14:04 +01:00
}
return name ;
}
2013-04-12 13:13:44 -07:00
static Elf_Sym * sym_lookup ( const char * symname )
{
int i ;
for ( i = 0 ; i < ehdr . e_shnum ; i + + ) {
struct section * sec = & secs [ i ] ;
long nsyms ;
char * strtab ;
Elf_Sym * symtab ;
Elf_Sym * sym ;
2006-12-07 02:14:04 +01:00
2013-04-12 13:13:44 -07:00
if ( sec - > shdr . sh_type ! = SHT_SYMTAB )
continue ;
nsyms = sec - > shdr . sh_size / sizeof ( Elf_Sym ) ;
symtab = sec - > symtab ;
strtab = sec - > link - > strtab ;
for ( sym = symtab ; - - nsyms > = 0 ; sym + + ) {
if ( ! sym - > st_name )
continue ;
if ( strcmp ( symname , strtab + sym - > st_name ) = = 0 )
return sym ;
}
}
return 0 ;
}
2006-12-07 02:14:04 +01:00
2010-05-26 08:30:15 -07:00
# if BYTE_ORDER == LITTLE_ENDIAN
2006-12-07 02:14:04 +01:00
# define le16_to_cpu(val) (val)
# define le32_to_cpu(val) (val)
2013-04-12 13:13:44 -07:00
# define le64_to_cpu(val) (val)
2006-12-07 02:14:04 +01:00
# endif
2010-05-26 08:30:15 -07:00
# if BYTE_ORDER == BIG_ENDIAN
2006-12-07 02:14:04 +01:00
# define le16_to_cpu(val) bswap_16(val)
# define le32_to_cpu(val) bswap_32(val)
2013-04-12 13:13:44 -07:00
# define le64_to_cpu(val) bswap_64(val)
2006-12-07 02:14:04 +01:00
# endif
static uint16_t elf16_to_cpu ( uint16_t val )
{
return le16_to_cpu ( val ) ;
}
static uint32_t elf32_to_cpu ( uint32_t val )
{
return le32_to_cpu ( val ) ;
}
2013-04-12 13:13:42 -07:00
# define elf_half_to_cpu(x) elf16_to_cpu(x)
# define elf_word_to_cpu(x) elf32_to_cpu(x)
2013-04-12 13:13:44 -07:00
2013-04-16 16:02:58 -07:00
# if ELF_BITS == 64
2013-04-12 13:13:44 -07:00
static uint64_t elf64_to_cpu ( uint64_t val )
{
return le64_to_cpu ( val ) ;
}
# define elf_addr_to_cpu(x) elf64_to_cpu(x)
# define elf_off_to_cpu(x) elf64_to_cpu(x)
# define elf_xword_to_cpu(x) elf64_to_cpu(x)
# else
2013-04-12 13:13:42 -07:00
# define elf_addr_to_cpu(x) elf32_to_cpu(x)
# define elf_off_to_cpu(x) elf32_to_cpu(x)
# define elf_xword_to_cpu(x) elf32_to_cpu(x)
2013-04-12 13:13:44 -07:00
# endif
2013-04-12 13:13:42 -07:00
2006-12-07 02:14:04 +01:00
static void read_ehdr ( FILE * fp )
{
if ( fread ( & ehdr , sizeof ( ehdr ) , 1 , fp ) ! = 1 ) {
die ( " Cannot read ELF header: %s \n " ,
strerror ( errno ) ) ;
}
2008-05-03 14:18:03 +04:00
if ( memcmp ( ehdr . e_ident , ELFMAG , SELFMAG ) ! = 0 ) {
2006-12-07 02:14:04 +01:00
die ( " No ELF magic \n " ) ;
}
2013-04-12 13:13:42 -07:00
if ( ehdr . e_ident [ EI_CLASS ] ! = ELF_CLASS ) {
die ( " Not a %d bit executable \n " , ELF_BITS ) ;
2006-12-07 02:14:04 +01:00
}
if ( ehdr . e_ident [ EI_DATA ] ! = ELFDATA2LSB ) {
die ( " Not a LSB ELF executable \n " ) ;
}
if ( ehdr . e_ident [ EI_VERSION ] ! = EV_CURRENT ) {
die ( " Unknown ELF version \n " ) ;
}
/* Convert the fields to native endian */
2013-04-12 13:13:42 -07:00
ehdr . e_type = elf_half_to_cpu ( ehdr . e_type ) ;
ehdr . e_machine = elf_half_to_cpu ( ehdr . e_machine ) ;
ehdr . e_version = elf_word_to_cpu ( ehdr . e_version ) ;
ehdr . e_entry = elf_addr_to_cpu ( ehdr . e_entry ) ;
ehdr . e_phoff = elf_off_to_cpu ( ehdr . e_phoff ) ;
ehdr . e_shoff = elf_off_to_cpu ( ehdr . e_shoff ) ;
ehdr . e_flags = elf_word_to_cpu ( ehdr . e_flags ) ;
ehdr . e_ehsize = elf_half_to_cpu ( ehdr . e_ehsize ) ;
ehdr . e_phentsize = elf_half_to_cpu ( ehdr . e_phentsize ) ;
ehdr . e_phnum = elf_half_to_cpu ( ehdr . e_phnum ) ;
ehdr . e_shentsize = elf_half_to_cpu ( ehdr . e_shentsize ) ;
ehdr . e_shnum = elf_half_to_cpu ( ehdr . e_shnum ) ;
ehdr . e_shstrndx = elf_half_to_cpu ( ehdr . e_shstrndx ) ;
2006-12-07 02:14:04 +01:00
if ( ( ehdr . e_type ! = ET_EXEC ) & & ( ehdr . e_type ! = ET_DYN ) ) {
die ( " Unsupported ELF header type \n " ) ;
}
2013-04-12 13:13:42 -07:00
if ( ehdr . e_machine ! = ELF_MACHINE ) {
die ( " Not for %s \n " , ELF_MACHINE_NAME ) ;
2006-12-07 02:14:04 +01:00
}
if ( ehdr . e_version ! = EV_CURRENT ) {
die ( " Unknown ELF version \n " ) ;
}
2013-04-12 13:13:42 -07:00
if ( ehdr . e_ehsize ! = sizeof ( Elf_Ehdr ) ) {
2006-12-07 02:14:04 +01:00
die ( " Bad Elf header size \n " ) ;
}
2013-04-12 13:13:42 -07:00
if ( ehdr . e_phentsize ! = sizeof ( Elf_Phdr ) ) {
2006-12-07 02:14:04 +01:00
die ( " Bad program header entry \n " ) ;
}
2013-04-12 13:13:42 -07:00
if ( ehdr . e_shentsize ! = sizeof ( Elf_Shdr ) ) {
2006-12-07 02:14:04 +01:00
die ( " Bad section header entry \n " ) ;
}
if ( ehdr . e_shstrndx > = ehdr . e_shnum ) {
die ( " String table index out of bounds \n " ) ;
}
}
static void read_shdrs ( FILE * fp )
{
int i ;
2013-04-12 13:13:42 -07:00
Elf_Shdr shdr ;
2008-06-30 14:42:18 -07:00
secs = calloc ( ehdr . e_shnum , sizeof ( struct section ) ) ;
if ( ! secs ) {
die ( " Unable to allocate %d section headers \n " ,
ehdr . e_shnum ) ;
2006-12-07 02:14:04 +01:00
}
if ( fseek ( fp , ehdr . e_shoff , SEEK_SET ) < 0 ) {
die ( " Seek to %d failed: %s \n " ,
ehdr . e_shoff , strerror ( errno ) ) ;
}
2008-06-30 14:42:18 -07:00
for ( i = 0 ; i < ehdr . e_shnum ; i + + ) {
struct section * sec = & secs [ i ] ;
if ( fread ( & shdr , sizeof shdr , 1 , fp ) ! = 1 )
die ( " Cannot read ELF section headers %d/%d: %s \n " ,
i , ehdr . e_shnum , strerror ( errno ) ) ;
2013-04-12 13:13:42 -07:00
sec - > shdr . sh_name = elf_word_to_cpu ( shdr . sh_name ) ;
sec - > shdr . sh_type = elf_word_to_cpu ( shdr . sh_type ) ;
sec - > shdr . sh_flags = elf_xword_to_cpu ( shdr . sh_flags ) ;
sec - > shdr . sh_addr = elf_addr_to_cpu ( shdr . sh_addr ) ;
sec - > shdr . sh_offset = elf_off_to_cpu ( shdr . sh_offset ) ;
sec - > shdr . sh_size = elf_xword_to_cpu ( shdr . sh_size ) ;
sec - > shdr . sh_link = elf_word_to_cpu ( shdr . sh_link ) ;
sec - > shdr . sh_info = elf_word_to_cpu ( shdr . sh_info ) ;
sec - > shdr . sh_addralign = elf_xword_to_cpu ( shdr . sh_addralign ) ;
sec - > shdr . sh_entsize = elf_xword_to_cpu ( shdr . sh_entsize ) ;
2008-06-30 14:42:18 -07:00
if ( sec - > shdr . sh_link < ehdr . e_shnum )
sec - > link = & secs [ sec - > shdr . sh_link ] ;
2006-12-07 02:14:04 +01:00
}
}
static void read_strtabs ( FILE * fp )
{
int i ;
2008-06-30 14:42:18 -07:00
for ( i = 0 ; i < ehdr . e_shnum ; i + + ) {
struct section * sec = & secs [ i ] ;
if ( sec - > shdr . sh_type ! = SHT_STRTAB ) {
2006-12-07 02:14:04 +01:00
continue ;
}
2008-06-30 14:42:18 -07:00
sec - > strtab = malloc ( sec - > shdr . sh_size ) ;
if ( ! sec - > strtab ) {
2006-12-07 02:14:04 +01:00
die ( " malloc of %d bytes for strtab failed \n " ,
2008-06-30 14:42:18 -07:00
sec - > shdr . sh_size ) ;
2006-12-07 02:14:04 +01:00
}
2008-06-30 14:42:18 -07:00
if ( fseek ( fp , sec - > shdr . sh_offset , SEEK_SET ) < 0 ) {
2006-12-07 02:14:04 +01:00
die ( " Seek to %d failed: %s \n " ,
2008-06-30 14:42:18 -07:00
sec - > shdr . sh_offset , strerror ( errno ) ) ;
2006-12-07 02:14:04 +01:00
}
2008-06-30 14:42:18 -07:00
if ( fread ( sec - > strtab , 1 , sec - > shdr . sh_size , fp )
! = sec - > shdr . sh_size ) {
2006-12-07 02:14:04 +01:00
die ( " Cannot read symbol table: %s \n " ,
strerror ( errno ) ) ;
}
}
}
static void read_symtabs ( FILE * fp )
{
int i , j ;
2008-06-30 14:42:18 -07:00
for ( i = 0 ; i < ehdr . e_shnum ; i + + ) {
struct section * sec = & secs [ i ] ;
if ( sec - > shdr . sh_type ! = SHT_SYMTAB ) {
2006-12-07 02:14:04 +01:00
continue ;
}
2008-06-30 14:42:18 -07:00
sec - > symtab = malloc ( sec - > shdr . sh_size ) ;
if ( ! sec - > symtab ) {
2006-12-07 02:14:04 +01:00
die ( " malloc of %d bytes for symtab failed \n " ,
2008-06-30 14:42:18 -07:00
sec - > shdr . sh_size ) ;
2006-12-07 02:14:04 +01:00
}
2008-06-30 14:42:18 -07:00
if ( fseek ( fp , sec - > shdr . sh_offset , SEEK_SET ) < 0 ) {
2006-12-07 02:14:04 +01:00
die ( " Seek to %d failed: %s \n " ,
2008-06-30 14:42:18 -07:00
sec - > shdr . sh_offset , strerror ( errno ) ) ;
2006-12-07 02:14:04 +01:00
}
2008-06-30 14:42:18 -07:00
if ( fread ( sec - > symtab , 1 , sec - > shdr . sh_size , fp )
! = sec - > shdr . sh_size ) {
2006-12-07 02:14:04 +01:00
die ( " Cannot read symbol table: %s \n " ,
strerror ( errno ) ) ;
}
2013-04-12 13:13:42 -07:00
for ( j = 0 ; j < sec - > shdr . sh_size / sizeof ( Elf_Sym ) ; j + + ) {
Elf_Sym * sym = & sec - > symtab [ j ] ;
sym - > st_name = elf_word_to_cpu ( sym - > st_name ) ;
sym - > st_value = elf_addr_to_cpu ( sym - > st_value ) ;
sym - > st_size = elf_xword_to_cpu ( sym - > st_size ) ;
sym - > st_shndx = elf_half_to_cpu ( sym - > st_shndx ) ;
2006-12-07 02:14:04 +01:00
}
}
}
static void read_relocs ( FILE * fp )
{
int i , j ;
2008-06-30 14:42:18 -07:00
for ( i = 0 ; i < ehdr . e_shnum ; i + + ) {
struct section * sec = & secs [ i ] ;
2013-04-12 13:13:42 -07:00
if ( sec - > shdr . sh_type ! = SHT_REL_TYPE ) {
2006-12-07 02:14:04 +01:00
continue ;
}
2008-06-30 14:42:18 -07:00
sec - > reltab = malloc ( sec - > shdr . sh_size ) ;
if ( ! sec - > reltab ) {
2006-12-07 02:14:04 +01:00
die ( " malloc of %d bytes for relocs failed \n " ,
2008-06-30 14:42:18 -07:00
sec - > shdr . sh_size ) ;
2006-12-07 02:14:04 +01:00
}
2008-06-30 14:42:18 -07:00
if ( fseek ( fp , sec - > shdr . sh_offset , SEEK_SET ) < 0 ) {
2006-12-07 02:14:04 +01:00
die ( " Seek to %d failed: %s \n " ,
2008-06-30 14:42:18 -07:00
sec - > shdr . sh_offset , strerror ( errno ) ) ;
2006-12-07 02:14:04 +01:00
}
2008-06-30 14:42:18 -07:00
if ( fread ( sec - > reltab , 1 , sec - > shdr . sh_size , fp )
! = sec - > shdr . sh_size ) {
2006-12-07 02:14:04 +01:00
die ( " Cannot read symbol table: %s \n " ,
strerror ( errno ) ) ;
}
2013-04-12 13:13:42 -07:00
for ( j = 0 ; j < sec - > shdr . sh_size / sizeof ( Elf_Rel ) ; j + + ) {
Elf_Rel * rel = & sec - > reltab [ j ] ;
rel - > r_offset = elf_addr_to_cpu ( rel - > r_offset ) ;
rel - > r_info = elf_xword_to_cpu ( rel - > r_info ) ;
2013-04-12 13:13:44 -07:00
# if (SHT_REL_TYPE == SHT_RELA)
rel - > r_addend = elf_xword_to_cpu ( rel - > r_addend ) ;
# endif
2006-12-07 02:14:04 +01:00
}
}
}
static void print_absolute_symbols ( void )
{
int i ;
2013-04-12 13:13:44 -07:00
const char * format ;
2013-04-16 16:02:58 -07:00
if ( ELF_BITS = = 64 )
2013-04-12 13:13:44 -07:00
format = " %5d %016 " PRIx64 " %5 " PRId64 " %10s %10s %12s %s \n " ;
else
format = " %5d %08 " PRIx32 " %5 " PRId32 " %10s %10s %12s %s \n " ;
2006-12-07 02:14:04 +01:00
printf ( " Absolute symbols \n " ) ;
printf ( " Num: Value Size Type Bind Visibility Name \n " ) ;
2008-06-30 14:42:18 -07:00
for ( i = 0 ; i < ehdr . e_shnum ; i + + ) {
struct section * sec = & secs [ i ] ;
2006-12-07 02:14:04 +01:00
char * sym_strtab ;
int j ;
2008-06-30 14:42:18 -07:00
if ( sec - > shdr . sh_type ! = SHT_SYMTAB ) {
2006-12-07 02:14:04 +01:00
continue ;
}
2008-06-30 14:42:18 -07:00
sym_strtab = sec - > link - > strtab ;
2013-04-12 13:13:42 -07:00
for ( j = 0 ; j < sec - > shdr . sh_size / sizeof ( Elf_Sym ) ; j + + ) {
Elf_Sym * sym ;
2006-12-07 02:14:04 +01:00
const char * name ;
2008-06-30 14:42:18 -07:00
sym = & sec - > symtab [ j ] ;
2006-12-07 02:14:04 +01:00
name = sym_name ( sym_strtab , sym ) ;
if ( sym - > st_shndx ! = SHN_ABS ) {
continue ;
}
2013-04-12 13:13:44 -07:00
printf ( format ,
2006-12-07 02:14:04 +01:00
j , sym - > st_value , sym - > st_size ,
2013-04-12 13:13:42 -07:00
sym_type ( ELF_ST_TYPE ( sym - > st_info ) ) ,
sym_bind ( ELF_ST_BIND ( sym - > st_info ) ) ,
sym_visibility ( ELF_ST_VISIBILITY ( sym - > st_other ) ) ,
2006-12-07 02:14:04 +01:00
name ) ;
}
}
printf ( " \n " ) ;
}
static void print_absolute_relocs ( void )
{
2006-12-07 02:14:04 +01:00
int i , printed = 0 ;
2013-04-12 13:13:44 -07:00
const char * format ;
2013-04-16 16:02:58 -07:00
if ( ELF_BITS = = 64 )
2013-04-12 13:13:44 -07:00
format = " %016 " PRIx64 " %016 " PRIx64 " %10s %016 " PRIx64 " %s \n " ;
else
format = " %08 " PRIx32 " %08 " PRIx32 " %10s %08 " PRIx32 " %s \n " ;
2006-12-07 02:14:04 +01:00
2008-06-30 14:42:18 -07:00
for ( i = 0 ; i < ehdr . e_shnum ; i + + ) {
struct section * sec = & secs [ i ] ;
struct section * sec_applies , * sec_symtab ;
2006-12-07 02:14:04 +01:00
char * sym_strtab ;
2013-04-12 13:13:42 -07:00
Elf_Sym * sh_symtab ;
2006-12-07 02:14:04 +01:00
int j ;
2013-04-12 13:13:42 -07:00
if ( sec - > shdr . sh_type ! = SHT_REL_TYPE ) {
2006-12-07 02:14:04 +01:00
continue ;
}
2008-06-30 14:42:18 -07:00
sec_symtab = sec - > link ;
sec_applies = & secs [ sec - > shdr . sh_info ] ;
if ( ! ( sec_applies - > shdr . sh_flags & SHF_ALLOC ) ) {
2006-12-07 02:14:04 +01:00
continue ;
}
2008-06-30 14:42:18 -07:00
sh_symtab = sec_symtab - > symtab ;
sym_strtab = sec_symtab - > link - > strtab ;
2013-04-12 13:13:42 -07:00
for ( j = 0 ; j < sec - > shdr . sh_size / sizeof ( Elf_Rel ) ; j + + ) {
Elf_Rel * rel ;
Elf_Sym * sym ;
2006-12-07 02:14:04 +01:00
const char * name ;
2008-06-30 14:42:18 -07:00
rel = & sec - > reltab [ j ] ;
2013-04-12 13:13:42 -07:00
sym = & sh_symtab [ ELF_R_SYM ( rel - > r_info ) ] ;
2006-12-07 02:14:04 +01:00
name = sym_name ( sym_strtab , sym ) ;
if ( sym - > st_shndx ! = SHN_ABS ) {
continue ;
}
2006-12-07 02:14:04 +01:00
/* Absolute symbols are not relocated if bzImage is
* loaded at a non - compiled address . Display a warning
* to user at compile time about the absolute
* relocations present .
*
* User need to audit the code to make sure
* some symbols which should have been section
* relative have not become absolute because of some
* linker optimization or wrong programming usage .
*
* Before warning check if this absolute symbol
* relocation is harmless .
*/
2012-05-08 21:22:24 +03:00
if ( is_reloc ( S_ABS , name ) | | is_reloc ( S_REL , name ) )
2006-12-07 02:14:04 +01:00
continue ;
if ( ! printed ) {
printf ( " WARNING: Absolute relocations "
" present \n " ) ;
printf ( " Offset Info Type Sym.Value "
" Sym.Name \n " ) ;
printed = 1 ;
}
2013-04-12 13:13:44 -07:00
printf ( format ,
2006-12-07 02:14:04 +01:00
rel - > r_offset ,
rel - > r_info ,
2013-04-12 13:13:42 -07:00
rel_type ( ELF_R_TYPE ( rel - > r_info ) ) ,
2006-12-07 02:14:04 +01:00
sym - > st_value ,
name ) ;
}
}
2006-12-07 02:14:04 +01:00
if ( printed )
printf ( " \n " ) ;
2006-12-07 02:14:04 +01:00
}
2013-04-12 13:13:43 -07:00
static void add_reloc ( struct relocs * r , uint32_t offset )
{
if ( r - > count = = r - > size ) {
unsigned long newsize = r - > size + 50000 ;
void * mem = realloc ( r - > offset , newsize * sizeof ( r - > offset [ 0 ] ) ) ;
if ( ! mem )
die ( " realloc of %ld entries for relocs failed \n " ,
newsize ) ;
r - > offset = mem ;
r - > size = newsize ;
}
r - > offset [ r - > count + + ] = offset ;
}
static void walk_relocs ( int ( * process ) ( struct section * sec , Elf_Rel * rel ,
Elf_Sym * sym , const char * symname ) )
2006-12-07 02:14:04 +01:00
{
int i ;
/* Walk through the relocations */
2008-06-30 14:42:18 -07:00
for ( i = 0 ; i < ehdr . e_shnum ; i + + ) {
2006-12-07 02:14:04 +01:00
char * sym_strtab ;
2013-04-12 13:13:42 -07:00
Elf_Sym * sh_symtab ;
2008-06-30 14:42:18 -07:00
struct section * sec_applies , * sec_symtab ;
2006-12-07 02:14:04 +01:00
int j ;
2008-06-30 14:42:18 -07:00
struct section * sec = & secs [ i ] ;
2013-04-12 13:13:42 -07:00
if ( sec - > shdr . sh_type ! = SHT_REL_TYPE ) {
2006-12-07 02:14:04 +01:00
continue ;
}
2008-06-30 14:42:18 -07:00
sec_symtab = sec - > link ;
sec_applies = & secs [ sec - > shdr . sh_info ] ;
if ( ! ( sec_applies - > shdr . sh_flags & SHF_ALLOC ) ) {
2006-12-07 02:14:04 +01:00
continue ;
}
2008-06-30 14:42:18 -07:00
sh_symtab = sec_symtab - > symtab ;
2008-10-03 13:00:56 -07:00
sym_strtab = sec_symtab - > link - > strtab ;
2013-04-12 13:13:42 -07:00
for ( j = 0 ; j < sec - > shdr . sh_size / sizeof ( Elf_Rel ) ; j + + ) {
2013-04-12 13:13:43 -07:00
Elf_Rel * rel = & sec - > reltab [ j ] ;
Elf_Sym * sym = & sh_symtab [ ELF_R_SYM ( rel - > r_info ) ] ;
const char * symname = sym_name ( sym_strtab , sym ) ;
2012-05-18 09:52:01 -07:00
2013-04-12 13:13:43 -07:00
process ( sec , rel , sym , symname ) ;
}
}
}
2013-04-12 13:13:44 -07:00
/*
* The . data . . percpu section is a special case for x86_64 SMP kernels .
* It is used to initialize the actual per_cpu areas and to provide
* definitions for the per_cpu variables that correspond to their offsets
* within the percpu area . Since the values of all of the symbols need
* to be offsets from the start of the per_cpu area the virtual address
* ( sh_addr ) of . data . . percpu is 0 in SMP kernels .
*
* This means that :
*
* Relocations that reference symbols in the per_cpu area do not
* need further relocation ( since the value is an offset relative
* to the start of the per_cpu area that does not change ) .
*
* Relocations that apply to the per_cpu area need to have their
* offset adjusted by by the value of __per_cpu_load to make them
* point to the correct place in the loaded image ( because the
* virtual address of . data . . percpu is 0 ) .
*
* For non SMP kernels . data . . percpu is linked as part of the normal
* kernel data and does not require special treatment .
*
*/
static int per_cpu_shndx = - 1 ;
2014-09-24 13:30:12 +01:00
static Elf_Addr per_cpu_load_addr ;
2013-04-12 13:13:44 -07:00
static void percpu_init ( void )
{
int i ;
for ( i = 0 ; i < ehdr . e_shnum ; i + + ) {
ElfW ( Sym ) * sym ;
if ( strcmp ( sec_name ( i ) , " .data..percpu " ) )
continue ;
if ( secs [ i ] . shdr . sh_addr ! = 0 ) /* non SMP kernel */
return ;
sym = sym_lookup ( " __per_cpu_load " ) ;
if ( ! sym )
die ( " can't find __per_cpu_load \n " ) ;
per_cpu_shndx = i ;
per_cpu_load_addr = sym - > st_value ;
return ;
}
}
2013-04-16 16:02:58 -07:00
# if ELF_BITS == 64
2013-04-12 13:13:44 -07:00
/*
* Check to see if a symbol lies in the . data . . percpu section .
2013-10-10 18:39:54 -07:00
*
* The linker incorrectly associates some symbols with the
* . data . . percpu section so we also need to check the symbol
* name to make sure that we classify the symbol correctly .
*
* The GNU linker incorrectly associates :
* __init_begin
2013-10-15 23:43:14 -07:00
* __per_cpu_load
2013-10-10 18:39:54 -07:00
*
* The " gold " linker incorrectly associates :
* init_per_cpu__irq_stack_union
* init_per_cpu__gdt_page
2013-04-12 13:13:44 -07:00
*/
static int is_percpu_sym ( ElfW ( Sym ) * sym , const char * symname )
{
return ( sym - > st_shndx = = per_cpu_shndx ) & &
2013-10-10 18:39:54 -07:00
strcmp ( symname , " __init_begin " ) & &
2013-10-15 23:43:14 -07:00
strcmp ( symname , " __per_cpu_load " ) & &
2013-10-10 18:39:54 -07:00
strncmp ( symname , " init_per_cpu_ " , 13 ) ;
2013-04-12 13:13:44 -07:00
}
2013-04-16 16:02:58 -07:00
2013-04-12 13:13:44 -07:00
static int do_reloc64 ( struct section * sec , Elf_Rel * rel , ElfW ( Sym ) * sym ,
const char * symname )
{
unsigned r_type = ELF64_R_TYPE ( rel - > r_info ) ;
ElfW ( Addr ) offset = rel - > r_offset ;
int shn_abs = ( sym - > st_shndx = = SHN_ABS ) & & ! is_reloc ( S_REL , symname ) ;
if ( sym - > st_shndx = = SHN_UNDEF )
return 0 ;
/*
* Adjust the offset if this reloc applies to the percpu section .
*/
if ( sec - > shdr . sh_info = = per_cpu_shndx )
offset + = per_cpu_load_addr ;
switch ( r_type ) {
case R_X86_64_NONE :
2014-11-04 08:50:18 +00:00
/* NONE can be ignored. */
break ;
2013-04-12 13:13:44 -07:00
case R_X86_64_PC32 :
/*
2014-11-04 08:50:18 +00:00
* PC relative relocations don ' t need to be adjusted unless
* referencing a percpu symbol .
2013-04-12 13:13:44 -07:00
*/
2014-11-04 08:50:18 +00:00
if ( is_percpu_sym ( sym , symname ) )
add_reloc ( & relocs32neg , offset ) ;
2013-04-12 13:13:44 -07:00
break ;
case R_X86_64_32 :
case R_X86_64_32S :
case R_X86_64_64 :
/*
* References to the percpu area don ' t need to be adjusted .
*/
if ( is_percpu_sym ( sym , symname ) )
break ;
if ( shn_abs ) {
/*
* Whitelisted absolute symbols do not require
* relocation .
*/
if ( is_reloc ( S_ABS , symname ) )
break ;
die ( " Invalid absolute %s relocation: %s \n " ,
rel_type ( r_type ) , symname ) ;
break ;
}
/*
* Relocation offsets for 64 bit kernels are output
* as 32 bits and sign extended back to 64 bits when
* the relocations are processed .
* Make sure that the offset will fit .
*/
if ( ( int32_t ) offset ! = ( int64_t ) offset )
die ( " Relocation offset doesn't fit in 32 bits \n " ) ;
if ( r_type = = R_X86_64_64 )
add_reloc ( & relocs64 , offset ) ;
else
add_reloc ( & relocs32 , offset ) ;
break ;
default :
die ( " Unsupported relocation type: %s (%d) \n " ,
rel_type ( r_type ) , r_type ) ;
break ;
}
return 0 ;
}
2013-04-16 16:02:58 -07:00
# else
2013-04-12 13:13:44 -07:00
static int do_reloc32 ( struct section * sec , Elf_Rel * rel , Elf_Sym * sym ,
const char * symname )
2013-04-12 13:13:43 -07:00
{
unsigned r_type = ELF32_R_TYPE ( rel - > r_info ) ;
int shn_abs = ( sym - > st_shndx = = SHN_ABS ) & & ! is_reloc ( S_REL , symname ) ;
switch ( r_type ) {
case R_386_NONE :
case R_386_PC32 :
case R_386_PC16 :
case R_386_PC8 :
/*
* NONE can be ignored and PC relative relocations don ' t
* need to be adjusted .
*/
break ;
case R_386_32 :
if ( shn_abs ) {
/*
* Whitelisted absolute symbols do not require
* relocation .
*/
if ( is_reloc ( S_ABS , symname ) )
2009-12-14 13:55:20 -08:00
break ;
2012-05-08 21:22:24 +03:00
2013-04-12 13:13:43 -07:00
die ( " Invalid absolute %s relocation: %s \n " ,
rel_type ( r_type ) , symname ) ;
break ;
}
add_reloc ( & relocs32 , rel - > r_offset ) ;
break ;
default :
die ( " Unsupported relocation type: %s (%d) \n " ,
rel_type ( r_type ) , r_type ) ;
break ;
}
return 0 ;
}
static int do_reloc_real ( struct section * sec , Elf_Rel * rel , Elf_Sym * sym ,
const char * symname )
{
unsigned r_type = ELF32_R_TYPE ( rel - > r_info ) ;
int shn_abs = ( sym - > st_shndx = = SHN_ABS ) & & ! is_reloc ( S_REL , symname ) ;
switch ( r_type ) {
case R_386_NONE :
case R_386_PC32 :
case R_386_PC16 :
case R_386_PC8 :
/*
* NONE can be ignored and PC relative relocations don ' t
* need to be adjusted .
*/
break ;
case R_386_16 :
if ( shn_abs ) {
/*
* Whitelisted absolute symbols do not require
* relocation .
*/
if ( is_reloc ( S_ABS , symname ) )
2012-05-08 21:22:24 +03:00
break ;
2013-04-12 13:13:43 -07:00
if ( is_reloc ( S_SEG , symname ) ) {
add_reloc ( & relocs16 , rel - > r_offset ) ;
break ;
}
} else {
if ( ! is_reloc ( S_LIN , symname ) )
2009-12-14 13:55:20 -08:00
break ;
2013-04-12 13:13:43 -07:00
}
die ( " Invalid %s %s relocation: %s \n " ,
shn_abs ? " absolute " : " relative " ,
rel_type ( r_type ) , symname ) ;
break ;
case R_386_32 :
if ( shn_abs ) {
/*
* Whitelisted absolute symbols do not require
* relocation .
*/
if ( is_reloc ( S_ABS , symname ) )
break ;
if ( is_reloc ( S_REL , symname ) ) {
add_reloc ( & relocs32 , rel - > r_offset ) ;
2009-12-14 13:55:20 -08:00
break ;
2006-12-07 02:14:04 +01:00
}
2013-04-12 13:13:43 -07:00
} else {
if ( is_reloc ( S_LIN , symname ) )
add_reloc ( & relocs32 , rel - > r_offset ) ;
break ;
2006-12-07 02:14:04 +01:00
}
2013-04-12 13:13:43 -07:00
die ( " Invalid %s %s relocation: %s \n " ,
shn_abs ? " absolute " : " relative " ,
rel_type ( r_type ) , symname ) ;
break ;
2006-12-07 02:14:04 +01:00
2013-04-12 13:13:43 -07:00
default :
die ( " Unsupported relocation type: %s (%d) \n " ,
rel_type ( r_type ) , r_type ) ;
break ;
}
2006-12-07 02:14:04 +01:00
2013-04-12 13:13:43 -07:00
return 0 ;
2006-12-07 02:14:04 +01:00
}
2013-04-16 16:02:58 -07:00
# endif
2006-12-07 02:14:04 +01:00
static int cmp_relocs ( const void * va , const void * vb )
{
2013-04-12 13:13:43 -07:00
const uint32_t * a , * b ;
2006-12-07 02:14:04 +01:00
a = va ; b = vb ;
return ( * a = = * b ) ? 0 : ( * a > * b ) ? 1 : - 1 ;
}
2013-04-12 13:13:43 -07:00
static void sort_relocs ( struct relocs * r )
{
qsort ( r - > offset , r - > count , sizeof ( r - > offset [ 0 ] ) , cmp_relocs ) ;
}
static int write32 ( uint32_t v , FILE * f )
2012-05-08 21:22:24 +03:00
{
unsigned char buf [ 4 ] ;
put_unaligned_le32 ( v , buf ) ;
return fwrite ( buf , 1 , 4 , f ) = = 4 ? 0 : - 1 ;
}
2013-04-12 13:13:43 -07:00
static int write32_as_text ( uint32_t v , FILE * f )
{
return fprintf ( f , " \t .long 0x%08 " PRIx32 " \n " , v ) > 0 ? 0 : - 1 ;
}
2012-05-08 21:22:24 +03:00
static void emit_relocs ( int as_text , int use_real_mode )
2006-12-07 02:14:04 +01:00
{
int i ;
2013-04-12 13:13:43 -07:00
int ( * write_reloc ) ( uint32_t , FILE * ) = write32 ;
2013-04-12 13:13:44 -07:00
int ( * do_reloc ) ( struct section * sec , Elf_Rel * rel , Elf_Sym * sym ,
const char * symname ) ;
2013-04-16 16:02:58 -07:00
# if ELF_BITS == 64
if ( ! use_real_mode )
2013-04-12 13:13:44 -07:00
do_reloc = do_reloc64 ;
2013-04-16 16:02:58 -07:00
else
die ( " --realmode not valid for a 64-bit ELF file " ) ;
# else
if ( ! use_real_mode )
2013-04-12 13:13:44 -07:00
do_reloc = do_reloc32 ;
else
do_reloc = do_reloc_real ;
2013-04-16 16:02:58 -07:00
# endif
2012-05-08 21:22:24 +03:00
2006-12-07 02:14:04 +01:00
/* Collect up the relocations */
2013-04-12 13:13:44 -07:00
walk_relocs ( do_reloc ) ;
2012-05-08 21:22:24 +03:00
2013-04-12 13:13:43 -07:00
if ( relocs16 . count & & ! use_real_mode )
2012-05-08 21:22:24 +03:00
die ( " Segment relocations found but --realmode not specified \n " ) ;
2006-12-07 02:14:04 +01:00
/* Order the relocations for more efficient processing */
2013-04-12 13:13:43 -07:00
sort_relocs ( & relocs16 ) ;
sort_relocs ( & relocs32 ) ;
2014-11-04 08:50:18 +00:00
# if ELF_BITS == 64
sort_relocs ( & relocs32neg ) ;
2013-04-12 13:13:44 -07:00
sort_relocs ( & relocs64 ) ;
2014-11-04 08:50:18 +00:00
# endif
2006-12-07 02:14:04 +01:00
/* Print the relocations */
if ( as_text ) {
/* Print the relocations in a form suitable that
* gas will like .
*/
printf ( " .section \" .data.reloc \" , \" a \" \n " ) ;
printf ( " .balign 4 \n " ) ;
2013-04-12 13:13:43 -07:00
write_reloc = write32_as_text ;
2006-12-07 02:14:04 +01:00
}
2012-05-08 21:22:24 +03:00
2013-04-12 13:13:43 -07:00
if ( use_real_mode ) {
write_reloc ( relocs16 . count , stdout ) ;
for ( i = 0 ; i < relocs16 . count ; i + + )
write_reloc ( relocs16 . offset [ i ] , stdout ) ;
write_reloc ( relocs32 . count , stdout ) ;
for ( i = 0 ; i < relocs32 . count ; i + + )
write_reloc ( relocs32 . offset [ i ] , stdout ) ;
} else {
2014-11-04 08:50:18 +00:00
# if ELF_BITS == 64
/* Print a stop */
write_reloc ( 0 , stdout ) ;
2013-04-12 13:13:44 -07:00
2014-11-04 08:50:18 +00:00
/* Now print each relocation */
for ( i = 0 ; i < relocs64 . count ; i + + )
write_reloc ( relocs64 . offset [ i ] , stdout ) ;
/* Print a stop */
write_reloc ( 0 , stdout ) ;
/* Now print each inverse 32-bit relocation */
for ( i = 0 ; i < relocs32neg . count ; i + + )
write_reloc ( relocs32neg . offset [ i ] , stdout ) ;
# endif
2013-04-12 13:13:44 -07:00
2013-04-12 13:13:43 -07:00
/* Print a stop */
write_reloc ( 0 , stdout ) ;
/* Now print each relocation */
for ( i = 0 ; i < relocs32 . count ; i + + )
write_reloc ( relocs32 . offset [ i ] , stdout ) ;
2006-12-07 02:14:04 +01:00
}
}
2014-01-21 12:32:23 -08:00
/*
* As an aid to debugging problems with different linkers
* print summary information about the relocs .
* Since different linkers tend to emit the sections in
* different orders we use the section names in the output .
*/
static int do_reloc_info ( struct section * sec , Elf_Rel * rel , ElfW ( Sym ) * sym ,
const char * symname )
{
printf ( " %s \t %s \t %s \t %s \n " ,
sec_name ( sec - > shdr . sh_info ) ,
rel_type ( ELF_R_TYPE ( rel - > r_info ) ) ,
symname ,
sec_name ( sym - > st_shndx ) ) ;
return 0 ;
}
static void print_reloc_info ( void )
{
printf ( " reloc section \t reloc type \t symbol \t symbol section \n " ) ;
walk_relocs ( do_reloc_info ) ;
}
2013-04-16 16:02:58 -07:00
# if ELF_BITS == 64
# define process process_64
# else
# define process process_32
# endif
2006-12-07 02:14:04 +01:00
2013-04-16 16:02:58 -07:00
void process ( FILE * fp , int use_real_mode , int as_text ,
2014-01-21 12:32:23 -08:00
int show_absolute_syms , int show_absolute_relocs ,
int show_reloc_info )
2006-12-07 02:14:04 +01:00
{
2012-05-08 21:22:24 +03:00
regex_init ( use_real_mode ) ;
2006-12-07 02:14:04 +01:00
read_ehdr ( fp ) ;
read_shdrs ( fp ) ;
read_strtabs ( fp ) ;
read_symtabs ( fp ) ;
read_relocs ( fp ) ;
2013-04-16 16:02:58 -07:00
if ( ELF_BITS = = 64 )
2013-04-12 13:13:44 -07:00
percpu_init ( ) ;
2006-12-07 02:14:04 +01:00
if ( show_absolute_syms ) {
2006-12-07 02:14:04 +01:00
print_absolute_symbols ( ) ;
2013-04-16 16:02:58 -07:00
return ;
2006-12-07 02:14:04 +01:00
}
if ( show_absolute_relocs ) {
2006-12-07 02:14:04 +01:00
print_absolute_relocs ( ) ;
2013-04-16 16:02:58 -07:00
return ;
2006-12-07 02:14:04 +01:00
}
2014-01-21 12:32:23 -08:00
if ( show_reloc_info ) {
print_reloc_info ( ) ;
return ;
}
2012-05-08 21:22:24 +03:00
emit_relocs ( as_text , use_real_mode ) ;
2006-12-07 02:14:04 +01:00
}