2020-01-18 09:38:21 +01:00
/*
2020-02-01 17:57:12 -07:00
* Copyright ( c ) 2019 - 2020 , Andrew Kaster < andrewdkaster @ gmail . com >
2020-10-10 18:17:49 +03:00
* Copyright ( c ) 2020 , Itamar S . < itamar8910 @ gmail . com >
2020-01-18 09:38:21 +01:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-01-03 23:31:51 -05:00
# include <AK/StringBuilder.h>
2020-04-11 12:24:07 -06:00
# include <LibELF/DynamicLoader.h>
2020-04-11 12:34:00 -06:00
# include <LibELF/Validation.h>
2020-01-03 23:31:51 -05:00
# include <assert.h>
# include <dlfcn.h>
# include <stdio.h>
# include <stdlib.h>
2020-03-08 12:05:14 +01:00
# include <string.h>
2020-08-08 22:45:20 -04:00
# include <sys/mman.h>
2020-01-03 23:31:51 -05:00
2020-08-27 00:34:59 +02:00
# ifndef DYNAMIC_LOAD_DEBUG
# define DYNAMIC_LOAD_DEBUG
# endif
2020-10-10 18:17:49 +03:00
// #define DYNAMIC_LOAD_VERBOSE
2020-01-03 23:31:51 -05:00
# ifdef DYNAMIC_LOAD_VERBOSE
# define VERBOSE(fmt, ...) dbgprintf(fmt, ##__VA_ARGS__)
# else
# define VERBOSE(fmt, ...) \
do { \
} while ( 0 )
# endif
2020-08-08 22:45:20 -04:00
# ifndef __serenity__
static void * mmap_with_name ( void * addr , size_t length , int prot , int flags , int fd , off_t offset , const char * )
{
return mmap ( addr , length , prot , flags , fd , offset ) ;
}
# endif
2020-04-11 12:24:07 -06:00
namespace ELF {
2020-10-17 14:39:36 +03:00
static bool s_always_bind_now = false ;
2020-01-03 23:31:51 -05:00
2020-04-11 12:24:07 -06:00
NonnullRefPtr < DynamicLoader > DynamicLoader : : construct ( const char * filename , int fd , size_t size )
2020-01-03 23:31:51 -05:00
{
2020-04-11 12:24:07 -06:00
return adopt ( * new DynamicLoader ( filename , fd , size ) ) ;
2020-01-03 23:31:51 -05:00
}
2020-10-10 18:17:49 +03:00
void * DynamicLoader : : do_mmap ( int fd , size_t size , const String & name )
{
if ( size < sizeof ( Elf32_Ehdr ) )
return MAP_FAILED ;
String file_mmap_name = String : : format ( " ELF_DYN: %s " , name . characters ( ) ) ;
return mmap_with_name ( nullptr , size , PROT_READ , MAP_PRIVATE , fd , 0 , file_mmap_name . characters ( ) ) ;
}
2020-04-11 12:24:07 -06:00
DynamicLoader : : DynamicLoader ( const char * filename , int fd , size_t size )
2020-01-03 23:31:51 -05:00
: m_filename ( filename )
, m_file_size ( size )
, m_image_fd ( fd )
2020-10-10 18:17:49 +03:00
, m_file_mapping ( do_mmap ( m_image_fd , m_file_size , m_filename ) )
, m_elf_image ( ( u8 * ) m_file_mapping , m_file_size )
2020-01-03 23:31:51 -05:00
{
2020-10-10 18:17:49 +03:00
if ( m_file_mapping = = MAP_FAILED ) {
2020-04-11 12:34:00 -06:00
m_valid = false ;
return ;
}
2020-10-10 18:17:49 +03:00
m_tls_size = calculate_tls_size ( ) ;
2020-01-03 23:31:51 -05:00
2020-10-17 14:39:36 +03:00
m_valid = validate ( ) ;
2020-10-10 18:17:49 +03:00
}
RefPtr < DynamicObject > DynamicLoader : : dynamic_object_from_image ( ) const
{
VirtualAddress dynamic_section_address ;
2020-04-11 12:34:00 -06:00
2020-10-10 18:17:49 +03:00
m_elf_image . for_each_program_header ( [ & dynamic_section_address ] ( auto program_header ) {
if ( program_header . type ( ) = = PT_DYNAMIC ) {
dynamic_section_address = VirtualAddress ( program_header . raw_data ( ) ) ;
}
2020-12-25 14:42:42 +01:00
return IterationDecision : : Continue ;
2020-10-10 18:17:49 +03:00
} ) ;
ASSERT ( ! dynamic_section_address . is_null ( ) ) ;
return ELF : : DynamicObject : : construct ( VirtualAddress ( m_elf_image . base_address ( ) ) , dynamic_section_address ) ;
}
size_t DynamicLoader : : calculate_tls_size ( ) const
{
size_t tls_size = 0 ;
m_elf_image . for_each_program_header ( [ & tls_size ] ( auto program_header ) {
if ( program_header . type ( ) = = PT_TLS ) {
tls_size = program_header . size_in_memory ( ) ;
}
2020-12-25 14:42:42 +01:00
return IterationDecision : : Continue ;
2020-10-10 18:17:49 +03:00
} ) ;
return tls_size ;
}
bool DynamicLoader : : validate ( )
{
2020-04-11 12:34:00 -06:00
auto * elf_header = ( Elf32_Ehdr * ) m_file_mapping ;
2020-10-17 14:39:36 +03:00
return validate_elf_header ( * elf_header , m_file_size ) & & validate_program_headers ( * elf_header , m_file_size , ( u8 * ) m_file_mapping , m_file_size , & m_program_interpreter ) ;
2020-01-03 23:31:51 -05:00
}
2020-04-11 12:24:07 -06:00
DynamicLoader : : ~ DynamicLoader ( )
2020-01-03 23:31:51 -05:00
{
if ( MAP_FAILED ! = m_file_mapping )
munmap ( m_file_mapping , m_file_size ) ;
2020-10-17 14:39:36 +03:00
close ( m_image_fd ) ;
2020-01-03 23:31:51 -05:00
}
2020-04-11 12:24:07 -06:00
void * DynamicLoader : : symbol_for_name ( const char * name )
2020-01-03 23:31:51 -05:00
{
auto symbol = m_dynamic_object - > hash_section ( ) . lookup_symbol ( name ) ;
if ( symbol . is_undefined ( ) )
return nullptr ;
return m_dynamic_object - > base_address ( ) . offset ( symbol . value ( ) ) . as_ptr ( ) ;
}
2020-10-10 18:17:49 +03:00
RefPtr < DynamicObject > DynamicLoader : : load_from_image ( unsigned flags , size_t total_tls_size )
2020-01-03 23:31:51 -05:00
{
2020-12-18 15:59:22 +02:00
m_valid = m_elf_image . is_valid ( ) ;
2020-01-03 23:31:51 -05:00
if ( ! m_valid ) {
2020-12-18 15:59:22 +02:00
dbgprintf ( " DynamicLoader::load_from_image failed: image is invalid \n " ) ;
2020-10-10 18:17:49 +03:00
return nullptr ;
2020-01-03 23:31:51 -05:00
}
# ifdef DYNAMIC_LOAD_VERBOSE
2020-10-10 18:17:49 +03:00
// m_image->dump();
2020-01-03 23:31:51 -05:00
# endif
2020-10-10 18:17:49 +03:00
load_program_headers ( ) ;
2020-02-28 22:47:39 -07:00
2020-10-10 18:17:49 +03:00
m_dynamic_object = DynamicObject : : construct ( m_text_segment_load_address , m_dynamic_section_address ) ;
m_dynamic_object - > set_tls_offset ( m_tls_offset ) ;
m_dynamic_object - > set_tls_size ( m_tls_size ) ;
2020-10-17 14:39:36 +03:00
ASSERT ( m_global_symbol_lookup_func ) ;
m_dynamic_object - > m_global_symbol_lookup_func = m_global_symbol_lookup_func ;
2020-01-03 23:31:51 -05:00
2020-10-10 18:17:49 +03:00
auto rc = load_stage_2 ( flags , total_tls_size ) ;
2020-12-18 15:59:22 +02:00
if ( ! rc ) {
dbgprintf ( " DynamicLoader::load_from_image failed at load_stage_2 \n " ) ;
2020-10-10 18:17:49 +03:00
return nullptr ;
2020-12-18 15:59:22 +02:00
}
2020-10-10 18:17:49 +03:00
return m_dynamic_object ;
2020-01-03 23:31:51 -05:00
}
2020-10-10 18:17:49 +03:00
bool DynamicLoader : : load_stage_2 ( unsigned flags , size_t total_tls_size )
2020-01-03 23:31:51 -05:00
{
ASSERT ( flags & RTLD_GLOBAL ) ;
# ifdef DYNAMIC_LOAD_DEBUG
m_dynamic_object - > dump ( ) ;
# endif
if ( m_dynamic_object - > has_text_relocations ( ) ) {
2020-10-17 14:39:36 +03:00
// dbg() << "Someone linked non -fPIC code into " << m_filename << " :(";
2020-01-03 23:31:51 -05:00
ASSERT ( m_text_segment_load_address . get ( ) ! = 0 ) ;
if ( 0 > mprotect ( m_text_segment_load_address . as_ptr ( ) , m_text_segment_size , PROT_READ | PROT_WRITE ) ) {
2020-01-08 21:38:05 -07:00
perror ( " mprotect .text: PROT_READ | PROT_WRITE " ) ; // FIXME: dlerror?
2020-01-03 23:31:51 -05:00
return false ;
}
}
2020-10-10 18:17:49 +03:00
do_relocations ( total_tls_size ) ;
if ( flags & RTLD_LAZY ) {
setup_plt_trampoline ( ) ;
}
2020-01-03 23:31:51 -05:00
// Clean up our setting of .text to PROT_READ | PROT_WRITE
if ( m_dynamic_object - > has_text_relocations ( ) ) {
if ( 0 > mprotect ( m_text_segment_load_address . as_ptr ( ) , m_text_segment_size , PROT_READ | PROT_EXEC ) ) {
2020-01-08 21:38:05 -07:00
perror ( " mprotect .text: PROT_READ | PROT_EXEC " ) ; // FIXME: dlerror?
2020-01-03 23:31:51 -05:00
return false ;
}
}
call_object_init_functions ( ) ;
2020-10-17 14:39:36 +03:00
VERBOSE ( " Loaded %s \n " , m_filename . characters ( ) ) ;
2020-01-03 23:31:51 -05:00
return true ;
}
2020-10-10 18:17:49 +03:00
void DynamicLoader : : load_program_headers ( )
2020-01-03 23:31:51 -05:00
{
Vector < ProgramHeaderRegion > program_headers ;
ProgramHeaderRegion * text_region_ptr = nullptr ;
ProgramHeaderRegion * data_region_ptr = nullptr ;
ProgramHeaderRegion * tls_region_ptr = nullptr ;
2020-01-08 21:38:05 -07:00
VirtualAddress dynamic_region_desired_vaddr ;
2020-01-03 23:31:51 -05:00
2020-10-10 18:17:49 +03:00
m_elf_image . for_each_program_header ( [ & ] ( const Image : : ProgramHeader & program_header ) {
2020-01-03 23:31:51 -05:00
ProgramHeaderRegion new_region ;
new_region . set_program_header ( program_header . raw_header ( ) ) ;
program_headers . append ( move ( new_region ) ) ;
auto & region = program_headers . last ( ) ;
if ( region . is_tls_template ( ) )
tls_region_ptr = & region ;
else if ( region . is_load ( ) ) {
if ( region . is_executable ( ) )
text_region_ptr = & region ;
else
data_region_ptr = & region ;
2020-03-08 12:05:14 +01:00
} else if ( region . is_dynamic ( ) ) {
2020-01-08 21:38:05 -07:00
dynamic_region_desired_vaddr = region . desired_load_address ( ) ;
}
2020-12-25 14:42:42 +01:00
return IterationDecision : : Continue ;
2020-01-03 23:31:51 -05:00
} ) ;
ASSERT ( text_region_ptr & & data_region_ptr ) ;
// Process regions in order: .text, .data, .tls
auto * region = text_region_ptr ;
2020-12-18 15:59:22 +02:00
void * requested_load_address = m_elf_image . is_dynamic ( ) ? nullptr : region - > desired_load_address ( ) . as_ptr ( ) ;
void * text_segment_begin = mmap_with_name (
requested_load_address ,
2020-10-17 14:39:36 +03:00
region - > required_load_size ( ) ,
region - > mmap_prot ( ) ,
MAP_PRIVATE ,
m_image_fd ,
region - > offset ( ) ,
String : : format ( " %s: .text " , m_filename . characters ( ) ) . characters ( ) ) ;
2020-01-03 23:31:51 -05:00
if ( MAP_FAILED = = text_segment_begin ) {
ASSERT_NOT_REACHED ( ) ;
}
2020-12-18 15:59:22 +02:00
ASSERT ( requested_load_address = = nullptr | | requested_load_address = = text_segment_begin ) ;
2020-01-03 23:31:51 -05:00
m_text_segment_size = region - > required_load_size ( ) ;
2020-08-08 23:13:31 -04:00
m_text_segment_load_address = VirtualAddress { ( FlatPtr ) text_segment_begin } ;
2020-01-08 21:38:05 -07:00
2020-12-18 15:59:22 +02:00
if ( m_elf_image . is_dynamic ( ) )
m_dynamic_section_address = dynamic_region_desired_vaddr . offset ( m_text_segment_load_address . get ( ) ) ;
else
m_dynamic_section_address = dynamic_region_desired_vaddr ;
2020-01-03 23:31:51 -05:00
region = data_region_ptr ;
2020-12-18 15:59:22 +02:00
void * data_segment_begin = mmap_with_name (
( u8 * ) text_segment_begin + m_text_segment_size ,
2020-10-17 14:39:36 +03:00
region - > required_load_size ( ) ,
region - > mmap_prot ( ) ,
MAP_ANONYMOUS | MAP_PRIVATE ,
0 ,
0 ,
String : : format ( " %s: .data " , m_filename . characters ( ) ) . characters ( ) ) ;
2020-01-03 23:31:51 -05:00
if ( MAP_FAILED = = data_segment_begin ) {
ASSERT_NOT_REACHED ( ) ;
}
2020-12-18 15:59:22 +02:00
VirtualAddress data_segment_actual_addr ;
if ( m_elf_image . is_dynamic ( ) ) {
data_segment_actual_addr = region - > desired_load_address ( ) . offset ( ( FlatPtr ) text_segment_begin ) ;
} else {
data_segment_actual_addr = region - > desired_load_address ( ) ;
}
2020-01-03 23:31:51 -05:00
memcpy ( data_segment_actual_addr . as_ptr ( ) , ( u8 * ) m_file_mapping + region - > offset ( ) , region - > size_in_image ( ) ) ;
2020-12-18 15:59:22 +02:00
// FIXME: Initialize the values in the TLS section. Currently, it is zeroed.
2020-01-03 23:31:51 -05:00
}
2020-10-10 18:17:49 +03:00
void DynamicLoader : : do_relocations ( size_t total_tls_size )
2020-01-03 23:31:51 -05:00
{
auto main_relocation_section = m_dynamic_object - > relocation_section ( ) ;
2020-10-10 18:17:49 +03:00
main_relocation_section . for_each_relocation ( [ & ] ( ELF : : DynamicObject : : Relocation relocation ) {
VERBOSE ( " Relocation symbol: %s, type: %d \n " , relocation . symbol ( ) . name ( ) , relocation . type ( ) ) ;
2020-12-18 15:59:22 +02:00
FlatPtr * patch_ptr = nullptr ;
if ( is_dynamic ( ) )
patch_ptr = ( FlatPtr * ) ( m_dynamic_object - > base_address ( ) . as_ptr ( ) + relocation . offset ( ) ) ;
else
patch_ptr = ( FlatPtr * ) ( FlatPtr ) relocation . offset ( ) ;
2020-10-10 18:17:49 +03:00
// VERBOSE("dynamic object name: %s\n", dynamic_object.object_name());
VERBOSE ( " dynamic object base address: %p \n " , m_dynamic_object - > base_address ( ) ) ;
VERBOSE ( " relocation offset: 0x%x \n " , relocation . offset ( ) ) ;
VERBOSE ( " patch_ptr: %p \n " , patch_ptr ) ;
2020-01-03 23:31:51 -05:00
switch ( relocation . type ( ) ) {
case R_386_NONE :
// Apparently most loaders will just skip these?
// Seems if the 'link editor' generates one something is funky with your code
VERBOSE ( " None relocation. No symbol, no nothin. \n " ) ;
break ;
case R_386_32 : {
auto symbol = relocation . symbol ( ) ;
VERBOSE ( " Absolute relocation: name: '%s', value: %p \n " , symbol . name ( ) , symbol . value ( ) ) ;
2020-10-10 18:17:49 +03:00
auto res = lookup_symbol ( symbol ) ;
2020-10-17 14:39:36 +03:00
if ( ! res . found ) {
dbgln ( " ERROR: symbol not found: {} " , symbol . name ( ) ) ;
ASSERT_NOT_REACHED ( ) ;
}
2020-10-10 18:17:49 +03:00
u32 symbol_address = res . address ;
2020-01-03 23:31:51 -05:00
* patch_ptr + = symbol_address ;
VERBOSE ( " Symbol address: %p \n " , * patch_ptr ) ;
break ;
}
case R_386_PC32 : {
auto symbol = relocation . symbol ( ) ;
VERBOSE ( " PC-relative relocation: '%s', value: %p \n " , symbol . name ( ) , symbol . value ( ) ) ;
2020-10-10 18:17:49 +03:00
auto res = lookup_symbol ( symbol ) ;
ASSERT ( res . found ) ;
u32 relative_offset = ( res . address - ( FlatPtr ) ( m_dynamic_object - > base_address ( ) . as_ptr ( ) + relocation . offset ( ) ) ) ;
2020-01-03 23:31:51 -05:00
* patch_ptr + = relative_offset ;
VERBOSE ( " Symbol address: %p \n " , * patch_ptr ) ;
break ;
}
case R_386_GLOB_DAT : {
auto symbol = relocation . symbol ( ) ;
VERBOSE ( " Global data relocation: '%s', value: %p \n " , symbol . name ( ) , symbol . value ( ) ) ;
2020-10-10 18:17:49 +03:00
auto res = lookup_symbol ( symbol ) ;
2020-12-20 22:32:10 +02:00
if ( ! res . found ) {
// We do not support these
// TODO: Can we tell gcc not to generate the piece of code that uses these?
// (--disable-tm-clone-registry flag in gcc conifugraion?)
if ( ! strcmp ( symbol . name ( ) , " __deregister_frame_info " ) | | ! strcmp ( symbol . name ( ) , " _ITM_registerTMCloneTable " )
| | ! strcmp ( symbol . name ( ) , " _ITM_deregisterTMCloneTable " ) | | ! strcmp ( symbol . name ( ) , " __register_frame_info " ) ) {
break ;
}
// The "__do_global_dtors_aux" function in libgcc_s.so needs this symbol,
// but we do not use that function so we don't actually need to resolve this symbol.
// The reason we can't resolve it here is that the symbol is defined in libc.so,
// but there's a circular dependecy between libgcc_s.so and libc.so,
// we deal with it by first loading libgcc_s and then libc.
// So we cannot find this symbol at this time (libc is not yet loaded).
if ( m_filename = = " libgcc_s.so " & & ! strcmp ( symbol . name ( ) , " __cxa_finalize " ) ) {
break ;
}
// Symbol not found
ASSERT_NOT_REACHED ( ) ;
}
2020-10-10 18:17:49 +03:00
VERBOSE ( " was symbol found? %d, address: 0x%x \n " , res . found , res . address ) ;
2020-12-20 22:32:10 +02:00
VERBOSE ( " object: %s \n " , m_filename . characters ( ) ) ;
2020-10-10 18:17:49 +03:00
if ( ! res . found ) {
// TODO this is a hack
ASSERT ( ! strcmp ( symbol . name ( ) , " __deregister_frame_info " ) | | ! strcmp ( symbol . name ( ) , " _ITM_registerTMCloneTable " )
| | ! strcmp ( symbol . name ( ) , " _ITM_deregisterTMCloneTable " ) | | ! strcmp ( symbol . name ( ) , " __register_frame_info " ) ) ;
ASSERT_NOT_REACHED ( ) ;
return IterationDecision : : Continue ;
}
// ASSERT(res.found);
u32 symbol_location = res . address ;
ASSERT ( symbol_location ! = ( FlatPtr ) m_dynamic_object - > base_address ( ) . as_ptr ( ) ) ;
2020-01-03 23:31:51 -05:00
* patch_ptr = symbol_location ;
VERBOSE ( " Symbol address: %p \n " , * patch_ptr ) ;
break ;
}
case R_386_RELATIVE : {
// FIXME: According to the spec, R_386_relative ones must be done first.
// We could explicitly do them first using m_number_of_relocatoins from DT_RELCOUNT
// However, our compiler is nice enough to put them at the front of the relocations for us :)
VERBOSE ( " Load address relocation at offset %X \n " , relocation . offset ( ) ) ;
2020-10-10 18:17:49 +03:00
VERBOSE ( " patch ptr == %p, adding load base address (%p) to it and storing %p \n " , * patch_ptr , m_dynamic_object - > base_address ( ) . as_ptr ( ) , * patch_ptr + m_dynamic_object - > base_address ( ) . as_ptr ( ) ) ;
* patch_ptr + = ( FlatPtr ) m_dynamic_object - > base_address ( ) . as_ptr ( ) ; // + addend for RelA (addend for Rel is stored at addr)
2020-01-03 23:31:51 -05:00
break ;
}
2020-10-10 18:17:49 +03:00
case R_386_TLS_TPOFF32 :
2020-01-03 23:31:51 -05:00
case R_386_TLS_TPOFF : {
2020-10-17 14:39:36 +03:00
VERBOSE ( " Relocation type: R_386_TLS_TPOFF at offset %X \n " , relocation . offset ( ) ) ;
2020-10-10 18:17:49 +03:00
auto symbol = relocation . symbol ( ) ;
// For some reason, LibC has a R_386_TLS_TPOFF that referes to the undefined symbol.. huh
if ( relocation . symbol_index ( ) = = 0 )
break ;
2020-10-17 14:39:36 +03:00
VERBOSE ( " Symbol index: %d \n " , symbol . index ( ) ) ;
VERBOSE ( " Symbol is_undefined?: %d \n " , symbol . is_undefined ( ) ) ;
VERBOSE ( " TLS relocation: '%s', value: %p \n " , symbol . name ( ) , symbol . value ( ) ) ;
2020-10-10 18:17:49 +03:00
auto res = lookup_symbol ( symbol ) ;
if ( ! res . found )
break ;
ASSERT ( res . found ) ;
u32 symbol_value = res . value ;
2020-10-17 14:39:36 +03:00
VERBOSE ( " symbol value: %d \n " , symbol_value ) ;
2020-10-10 18:17:49 +03:00
const auto dynamic_object_of_symbol = res . dynamic_object ;
ASSERT ( dynamic_object_of_symbol ) ;
size_t offset_of_tls_end = dynamic_object_of_symbol - > tls_offset ( ) . value ( ) + dynamic_object_of_symbol - > tls_size ( ) . value ( ) ;
// size_t offset_of_tls_end = tls_offset() + tls_size();
2020-10-17 14:39:36 +03:00
VERBOSE ( " patch ptr: 0x%x \n " , patch_ptr ) ;
VERBOSE ( " tls end offset: %d, total tls size: %d \n " , offset_of_tls_end , total_tls_size ) ;
2020-10-10 18:17:49 +03:00
* patch_ptr = ( offset_of_tls_end - total_tls_size - symbol_value - sizeof ( Elf32_Addr ) ) ;
2020-10-17 14:39:36 +03:00
VERBOSE ( " *patch ptr: %d \n " , ( i32 ) * patch_ptr ) ;
2020-01-03 23:31:51 -05:00
break ;
}
default :
// Raise the alarm! Someone needs to implement this relocation type
2020-10-10 18:17:49 +03:00
VERBOSE ( " Found a new exciting relocation type %d \n " , relocation . type ( ) ) ;
// printf("DynamicLoader: Found unknown relocation type %d\n", relocation.type());
2020-01-03 23:31:51 -05:00
ASSERT_NOT_REACHED ( ) ;
break ;
}
return IterationDecision : : Continue ;
} ) ;
2020-10-10 18:17:49 +03:00
VERBOSE ( " plt relocations: 0x%x " , m_dynamic_object - > plt_relocation_section ( ) . address ( ) ) ;
VERBOSE ( " plt relocation count: 0x%x " , m_dynamic_object - > plt_relocation_section ( ) . address ( ) ) ;
VERBOSE ( " plt size: %d \n " , m_dynamic_object - > plt_relocation_section ( ) . size ( ) ) ;
VERBOSE ( " plt entry size: 0x%x \n " , m_dynamic_object - > plt_relocation_section ( ) . entry_size ( ) ) ;
2020-01-03 23:31:51 -05:00
// Handle PLT Global offset table relocations.
2020-04-11 12:24:07 -06:00
m_dynamic_object - > plt_relocation_section ( ) . for_each_relocation ( [ & ] ( const DynamicObject : : Relocation & relocation ) {
2020-01-03 23:31:51 -05:00
// FIXME: Or BIND_NOW flag passed in?
if ( m_dynamic_object - > must_bind_now ( ) | | s_always_bind_now ) {
// Eagerly BIND_NOW the PLT entries, doing all the symbol looking goodness
// The patch method returns the address for the LAZY fixup path, but we don't need it here
2020-10-17 14:39:36 +03:00
VERBOSE ( " patching plt reloaction: 0x%x \n " , relocation . offset_in_section ( ) ) ;
2020-12-20 16:09:48 -07:00
[[maybe_unused]] auto rc = m_dynamic_object - > patch_plt_entry ( relocation . offset_in_section ( ) ) ;
2020-01-03 23:31:51 -05:00
} else {
ASSERT ( relocation . type ( ) = = R_386_JMP_SLOT ) ;
u8 * relocation_address = relocation . address ( ) . as_ptr ( ) ;
2020-12-18 15:59:22 +02:00
if ( m_elf_image . is_dynamic ( ) )
* ( u32 * ) relocation_address + = ( FlatPtr ) m_dynamic_object - > base_address ( ) . as_ptr ( ) ;
2020-01-03 23:31:51 -05:00
}
return IterationDecision : : Continue ;
} ) ;
2020-10-17 14:39:36 +03:00
VERBOSE ( " Done relocating! \n " ) ;
2020-01-03 23:31:51 -05:00
}
// Defined in <arch>/plt_trampoline.S
2020-12-20 16:09:48 -07:00
extern " C " void _plt_trampoline ( ) __attribute__ ( ( visibility ( " hidden " ) ) ) ;
2020-01-03 23:31:51 -05:00
2020-04-11 12:24:07 -06:00
void DynamicLoader : : setup_plt_trampoline ( )
2020-01-03 23:31:51 -05:00
{
2020-10-17 14:39:36 +03:00
ASSERT ( m_dynamic_object ) ;
2020-01-03 23:31:51 -05:00
VirtualAddress got_address = m_dynamic_object - > plt_got_base_address ( ) ;
2020-08-08 23:13:31 -04:00
FlatPtr * got_ptr = ( FlatPtr * ) got_address . as_ptr ( ) ;
2020-10-17 14:39:36 +03:00
got_ptr [ 1 ] = ( FlatPtr ) m_dynamic_object . ptr ( ) ;
2020-08-08 23:13:31 -04:00
got_ptr [ 2 ] = ( FlatPtr ) & _plt_trampoline ;
2020-01-03 23:31:51 -05:00
2020-10-17 14:39:36 +03:00
VERBOSE ( " Set GOT PLT entries at %p: [0] = %p [1] = %p, [2] = %p \n " , got_ptr , ( void * ) got_ptr [ 0 ] , ( void * ) got_ptr [ 1 ] , ( void * ) got_ptr [ 2 ] ) ;
2020-01-03 23:31:51 -05:00
}
2020-08-11 23:53:54 +02:00
// Called from our ASM routine _plt_trampoline.
// Tell the compiler that it might be called from other places:
2020-10-17 14:39:36 +03:00
extern " C " Elf32_Addr _fixup_plt_entry ( DynamicObject * object , u32 relocation_offset ) ;
extern " C " Elf32_Addr _fixup_plt_entry ( DynamicObject * object , u32 relocation_offset )
2020-01-03 23:31:51 -05:00
{
return object - > patch_plt_entry ( relocation_offset ) ;
}
2020-04-11 12:24:07 -06:00
void DynamicLoader : : call_object_init_functions ( )
2020-01-03 23:31:51 -05:00
{
typedef void ( * InitFunc ) ( ) ;
2020-10-10 18:17:49 +03:00
if ( m_dynamic_object - > has_init_section ( ) ) {
auto init_function = ( InitFunc ) ( m_dynamic_object - > init_section ( ) . address ( ) . as_ptr ( ) ) ;
2020-01-03 23:31:51 -05:00
2020-10-17 14:39:36 +03:00
VERBOSE ( " Calling DT_INIT at %p \n " , init_function ) ;
2020-10-10 18:17:49 +03:00
( init_function ) ( ) ;
}
2020-01-03 23:31:51 -05:00
2020-10-10 18:17:49 +03:00
if ( m_dynamic_object - > has_init_array_section ( ) ) {
auto init_array_section = m_dynamic_object - > init_array_section ( ) ;
InitFunc * init_begin = ( InitFunc * ) ( init_array_section . address ( ) . as_ptr ( ) ) ;
InitFunc * init_end = init_begin + init_array_section . entry_count ( ) ;
while ( init_begin ! = init_end ) {
// Android sources claim that these can be -1, to be ignored.
// 0 definitely shows up. Apparently 0/-1 are valid? Confusing.
if ( ! * init_begin | | ( ( FlatPtr ) * init_begin = = ( FlatPtr ) - 1 ) )
continue ;
2020-10-17 14:39:36 +03:00
VERBOSE ( " Calling DT_INITARRAY entry at %p \n " , * init_begin ) ;
2020-10-10 18:17:49 +03:00
( * init_begin ) ( ) ;
+ + init_begin ;
}
2020-01-03 23:31:51 -05:00
}
}
2020-04-11 12:24:07 -06:00
u32 DynamicLoader : : ProgramHeaderRegion : : mmap_prot ( ) const
2020-01-03 23:31:51 -05:00
{
int prot = 0 ;
prot | = is_executable ( ) ? PROT_EXEC : 0 ;
prot | = is_readable ( ) ? PROT_READ : 0 ;
prot | = is_writable ( ) ? PROT_WRITE : 0 ;
return prot ;
}
2020-04-11 12:24:07 -06:00
2020-10-10 18:17:49 +03:00
DynamicObject : : SymbolLookupResult DynamicLoader : : lookup_symbol ( const ELF : : DynamicObject : : Symbol & symbol ) const
{
2020-10-17 14:39:36 +03:00
return m_dynamic_object - > lookup_symbol ( symbol ) ;
2020-10-10 18:17:49 +03:00
}
2020-04-11 12:24:07 -06:00
} // end namespace ELF