mirror of
https://github.com/serge1/ELFIO.git
synced 2025-04-17 08:44:25 +00:00
special support for PHDR segments and segments which include the elf header
Only elf files with strange GNU_RELRO segments fail the load, save, cycle. It would maybe a good idea to separate the layout functionality from the current save. The current coupling of layout and save make it impossible to build layouts which contain the elf header via the public API.
This commit is contained in:
parent
755b92c580
commit
b91a43b378
@ -291,8 +291,22 @@ void checkExeAreEqual( std::string file_name1, std::string file_name2 )
|
||||
BOOST_REQUIRE_EQUAL( file2.load( file_name2 ), true );
|
||||
|
||||
for (int i = 0; i < file1.segments.size(); ++i ) {
|
||||
BOOST_REQUIRE_NE( file1.segments[i]->get_data(), (const char*)0 );
|
||||
BOOST_REQUIRE_NE( file2.segments[i]->get_data(), (const char*)0 );
|
||||
BOOST_CHECK_EQUAL( file1.segments[i]->get_align(),
|
||||
file2.segments[i]->get_align() );
|
||||
BOOST_CHECK_EQUAL( file1.segments[i]->get_file_size(),
|
||||
file2.segments[i]->get_file_size() );
|
||||
BOOST_CHECK_EQUAL( file1.segments[i]->get_memory_size(),
|
||||
file2.segments[i]->get_memory_size() );
|
||||
BOOST_CHECK_EQUAL( file1.segments[i]->get_type(),
|
||||
file2.segments[i]->get_type() );
|
||||
|
||||
// skip data comparisons of the program header and of empty segments
|
||||
if( file1.segments[i]->get_type() == PT_PHDR || !file1.segments[i]->get_file_size() )
|
||||
continue;
|
||||
|
||||
BOOST_REQUIRE_NE( file1.segments[i]->get_data(), (const char*)0 );
|
||||
BOOST_REQUIRE_NE( file2.segments[i]->get_data(), (const char*)0 );
|
||||
|
||||
std::string pdata1( file1.segments[i]->get_data(),
|
||||
file1.segments[i]->get_data() +
|
||||
file1.segments[i]->get_file_size() );
|
||||
@ -300,10 +314,15 @@ void checkExeAreEqual( std::string file_name1, std::string file_name2 )
|
||||
file2.segments[i]->get_data() +
|
||||
file2.segments[i]->get_file_size() );
|
||||
|
||||
BOOST_CHECK_EQUAL( file1.segments[i]->get_file_size(),
|
||||
file2.segments[i]->get_file_size() );
|
||||
BOOST_CHECK_EQUAL( file1.segments[i]->get_memory_size(),
|
||||
file2.segments[i]->get_memory_size() );
|
||||
// truncate the data if the header and the segment table is
|
||||
// part of the segment
|
||||
Elf64_Off afterPHDR = file1.get_segments_offset() +
|
||||
file1.get_segment_entry_size() * file1.segments.size();
|
||||
if( file1.segments[i]->get_offset() < afterPHDR ) {
|
||||
pdata1 = pdata1.substr(afterPHDR);
|
||||
pdata2 = pdata2.substr(afterPHDR);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS( pdata1.begin(), pdata1.end(),
|
||||
pdata2.begin(), pdata2.end() );
|
||||
}
|
||||
@ -370,35 +389,44 @@ BOOST_AUTO_TEST_CASE( elf_exe_copy_64 )
|
||||
{
|
||||
checkExeAreEqual( "../elf_examples/64bitLOAD.elf",
|
||||
"../elf_examples/64bitLOAD_copy.elf" );
|
||||
// checkExeAreEqual( "../elf_examples/asm_64",
|
||||
// "../elf_examples/asm_64_copy" );
|
||||
// checkExeAreEqual( "../elf_examples/hello_64",
|
||||
// "../elf_examples/hello_64_copy" );
|
||||
// checkExeAreEqual( "../elf_examples/main",
|
||||
// "../elf_examples/main_copy" );
|
||||
checkExeAreEqual( "../elf_examples/asm64",
|
||||
"../elf_examples/asm64_copy" );
|
||||
checkExeAreEqual( "../elf_examples/hello_64",
|
||||
"../elf_examples/hello_64_copy" );
|
||||
|
||||
// The last segment (GNU_RELRO) is bigger than necessary.
|
||||
// I don't see why but it contains a few bits of the .got.plt section.
|
||||
// -> load, store, compare cycle fails
|
||||
// checkExeAreEqual( "../elf_examples/main",
|
||||
// "../elf_examples/main_copy" );
|
||||
// checkExeAreEqual( "../elf_examples/ls",
|
||||
// "../elf_examples/ls_copy" );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
BOOST_AUTO_TEST_CASE( elf_exe_copy_32 )
|
||||
{
|
||||
// checkExeAreEqual( "../elf_examples/asm",
|
||||
// "../elf_examples/asm_copy" );
|
||||
checkExeAreEqual( "../elf_examples/asm",
|
||||
"../elf_examples/asm_copy" );
|
||||
checkExeAreEqual( "../elf_examples/arm_v7m_test_debug.elf",
|
||||
"../elf_examples/arm_v7m_test_debug_copy.elf" );
|
||||
checkExeAreEqual( "../elf_examples/arm_v7m_test_release.elf",
|
||||
"../elf_examples/arm_v7m_test_release_copy.elf" );
|
||||
// checkExeAreEqual( "../elf_examples/hello_32",
|
||||
// "../elf_examples/hello_32_copy" );
|
||||
checkExeAreEqual( "../elf_examples/hello_32",
|
||||
"../elf_examples/hello_32_copy" );
|
||||
checkExeAreEqual( "../elf_examples/hello_arm",
|
||||
"../elf_examples/hello_arm_copy" );
|
||||
checkExeAreEqual( "../elf_examples/hello_arm_stripped",
|
||||
"../elf_examples/hello_arm_stripped_copy" );
|
||||
// checkExeAreEqual( "../elf_examples/ls",
|
||||
// "../elf_examples/ls_copy" );
|
||||
// checkExeAreEqual( "../elf_examples/main32",
|
||||
// "../elf_examples/main32_copy" );
|
||||
|
||||
// The last segment (GNU_RELRO) is bigger than necessary.
|
||||
// I don't see why but it contains a few bits of the .got.plt section.
|
||||
// -> load, store, compare cycle fails
|
||||
// checkExeAreEqual( "../elf_examples/main32",
|
||||
// "../elf_examples/main32_copy" );
|
||||
|
||||
checkExeAreEqual( "../elf_examples/read_write_arm_elf32_input",
|
||||
"../elf_examples/read_write_arm_elf32_input_copy" );
|
||||
// checkExeAreEqual( "../elf_examples/test_ppc",
|
||||
// "../elf_examples/test_ppc_copy" );
|
||||
checkExeAreEqual( "../elf_examples/test_ppc",
|
||||
"../elf_examples/test_ppc_copy" );
|
||||
}
|
||||
|
@ -412,15 +412,16 @@ class elfio
|
||||
|
||||
// SHF_ALLOC sections are matched based on the virtual address
|
||||
// otherwise the file offset is matched
|
||||
if(psec->get_flags() & SHF_ALLOC
|
||||
? (segVBaseAddr <= psec->get_address()
|
||||
&& psec->get_address() + psec->get_size()
|
||||
<= segVEndAddr)
|
||||
: (segBaseOffset <= psec->get_offset()
|
||||
&& psec->get_offset() + psec->get_size()
|
||||
<= segEndOffset)) {
|
||||
seg->add_section_index( psec->get_index(),
|
||||
psec->get_addr_align() );
|
||||
if( psec->get_type() != SHT_NULL
|
||||
&& (psec->get_flags() & SHF_ALLOC
|
||||
? (segVBaseAddr <= psec->get_address()
|
||||
&& psec->get_address() + psec->get_size()
|
||||
<= segVEndAddr)
|
||||
: (segBaseOffset <= psec->get_offset()
|
||||
&& psec->get_offset() + psec->get_size()
|
||||
<= segEndOffset))) {
|
||||
seg->add_section_index( psec->get_index(),
|
||||
psec->get_addr_align() );
|
||||
}
|
||||
}
|
||||
|
||||
@ -508,6 +509,16 @@ class elfio
|
||||
std::copy( segments_.begin(), segments_.end(),
|
||||
std::back_inserter( worklist )) ;
|
||||
|
||||
// bring the segments which start at address 0 to the front
|
||||
size_t nextSlot = 0;
|
||||
for( size_t i = 0; i < worklist.size(); ++i ) {
|
||||
if( i != nextSlot && worklist[i]->is_offset_initialized()
|
||||
&& worklist[i]->get_offset() == 0 ) {
|
||||
std::swap(worklist[i],worklist[nextSlot]);
|
||||
++nextSlot;
|
||||
}
|
||||
}
|
||||
|
||||
while ( !worklist.empty() ) {
|
||||
segment *seg = worklist.front();
|
||||
worklist.pop_front();
|
||||
@ -573,12 +584,26 @@ class elfio
|
||||
Elf_Xword seg_start_pos = 0;
|
||||
segment* seg = worklist[i];
|
||||
|
||||
// special case: PHDR segments
|
||||
// this segment contains the program headers but no sections
|
||||
if( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) {
|
||||
seg_start_pos = header->get_segments_offset();
|
||||
segment_memory = segment_filesize =
|
||||
header->get_segment_entry_size() * header->get_segments_num();
|
||||
// special case: segments with offset 0
|
||||
} else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) {
|
||||
seg_start_pos = 0;
|
||||
if( seg->get_sections_num() )
|
||||
segment_memory = segment_filesize = current_file_pos;
|
||||
// new segments (no sections or not generated sections)
|
||||
// have to be aligned
|
||||
if( !seg->get_sections_num()
|
||||
} else if( !seg->get_sections_num()
|
||||
|| ( seg->get_sections_num()
|
||||
&& !section_generated[seg->get_section_index_at( 0 )] )) {
|
||||
Elf64_Off error = current_file_pos % seg->get_align();
|
||||
|
||||
// this alignment seems to be optional
|
||||
// many of the input files are not aligned in the elf file...
|
||||
current_file_pos += ( seg->get_align() - error ) % seg->get_align();
|
||||
seg_start_pos = current_file_pos;
|
||||
} else {
|
||||
@ -593,7 +618,7 @@ class elfio
|
||||
|
||||
Elf_Xword secAlign = 0;
|
||||
// fix up the alignment
|
||||
if ( j != 0 && sec->is_address_initialized()
|
||||
if ( !section_generated[index] && sec->is_address_initialized()
|
||||
&& SHT_NOBITS != sec->get_type()
|
||||
&& SHT_NULL != sec->get_type() ) {
|
||||
// align the sections based on the virtual addresses
|
||||
@ -601,11 +626,14 @@ class elfio
|
||||
Elf64_Off req_offset = sec->get_address() - seg->get_virtual_address();
|
||||
Elf64_Off cur_offset = current_file_pos - seg_start_pos;
|
||||
secAlign = req_offset - cur_offset;
|
||||
} else if (j != 0) {
|
||||
} else if (!section_generated[index]) {
|
||||
// if no address has been specified then only the section
|
||||
// alignment constraint has to be matched
|
||||
Elf64_Off error = current_file_pos % sec->get_addr_align();
|
||||
secAlign = ( sec->get_addr_align() - error ) % sec->get_addr_align();
|
||||
} else {
|
||||
// alignment for already generated sections
|
||||
secAlign = sec->get_offset() - seg_start_pos - segment_filesize;
|
||||
}
|
||||
|
||||
// determine the segment file and memory sizes
|
||||
|
@ -42,15 +42,17 @@ class segment
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address );
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size );
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size );
|
||||
ELFIO_GET_ACCESS_DECL( Elf64_Off, offset );
|
||||
|
||||
virtual const char* get_data() const = 0;
|
||||
|
||||
virtual Elf_Half add_section_index( Elf_Half index, Elf_Xword addr_align ) = 0;
|
||||
virtual Elf_Half get_sections_num() const = 0;
|
||||
virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0;
|
||||
virtual bool is_offset_initialized() const = 0;
|
||||
|
||||
protected:
|
||||
ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, offset );
|
||||
ELFIO_SET_ACCESS_DECL( Elf64_Off, offset );
|
||||
ELFIO_SET_ACCESS_DECL( Elf_Half, index );
|
||||
|
||||
virtual const std::vector<Elf_Half>& get_sections() const = 0;
|
||||
@ -69,6 +71,7 @@ class segment_impl : public segment
|
||||
segment_impl( endianess_convertor* convertor_ ) :
|
||||
convertor( convertor_ )
|
||||
{
|
||||
is_offset_set = false;
|
||||
std::fill_n( reinterpret_cast<char*>( &ph ), sizeof( ph ), '\0' );
|
||||
data = 0;
|
||||
}
|
||||
@ -88,6 +91,7 @@ class segment_impl : public segment
|
||||
ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr );
|
||||
ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz );
|
||||
ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz );
|
||||
ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset );
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Elf_Half
|
||||
@ -136,10 +140,26 @@ class segment_impl : public segment
|
||||
//------------------------------------------------------------------------------
|
||||
protected:
|
||||
//------------------------------------------------------------------------------
|
||||
ELFIO_GET_SET_ACCESS( Elf64_Off, offset, ph.p_offset );
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const std::vector<Elf_Half>& get_sections() const
|
||||
void
|
||||
set_offset( Elf64_Off value )
|
||||
{
|
||||
ph.p_offset = value;
|
||||
ph.p_offset = (*convertor)( ph.p_offset );
|
||||
is_offset_set = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool
|
||||
is_offset_initialized() const
|
||||
{
|
||||
return is_offset_set;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const std::vector<Elf_Half>&
|
||||
get_sections() const
|
||||
{
|
||||
return sections;
|
||||
}
|
||||
@ -158,6 +178,7 @@ class segment_impl : public segment
|
||||
{
|
||||
stream.seekg( header_offset );
|
||||
stream.read( reinterpret_cast<char*>( &ph ), sizeof( ph ) );
|
||||
is_offset_set = true;
|
||||
|
||||
if ( PT_NULL != get_type() && 0 != get_file_size() ) {
|
||||
stream.seekg( (*convertor)( ph.p_offset ) );
|
||||
@ -187,6 +208,7 @@ class segment_impl : public segment
|
||||
char* data;
|
||||
std::vector<Elf_Half> sections;
|
||||
endianess_convertor* convertor;
|
||||
bool is_offset_set;
|
||||
};
|
||||
|
||||
} // namespace ELFIO
|
||||
|
Loading…
x
Reference in New Issue
Block a user