@@ -171,6 +171,8 @@ class ElfFile
171
171
std::string & replaceSection (const SectionName & sectionName,
172
172
unsigned int size);
173
173
174
+ bool haveReplacedSection (const SectionName & sectionName);
175
+
174
176
void writeReplacedSections (Elf_Off & curOff,
175
177
Elf_Addr startAddr, Elf_Off startOffset);
176
178
@@ -579,6 +581,15 @@ unsigned int ElfFile<ElfFileParamNames>::findSection3(const SectionName & sectio
579
581
return 0 ;
580
582
}
581
583
584
+ template <ElfFileParams>
585
+ bool ElfFile<ElfFileParamNames>::haveReplacedSection(const SectionName & sectionName)
586
+ {
587
+ ReplacedSections::iterator i = replacedSections.find (sectionName);
588
+
589
+ if (i != replacedSections.end ())
590
+ return true ;
591
+ return false ;
592
+ }
582
593
583
594
template <ElfFileParams>
584
595
std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sectionName,
@@ -673,51 +684,51 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
673
684
674
685
debug (" last page is 0x%llx\n " , (unsigned long long ) startPage);
675
686
687
+ /* Because we're adding a new section header, we're necessarily increasing
688
+ the size of the program header table. This can cause the first section
689
+ to overlap the program header table in memory; we need to shift the first
690
+ few segments to someplace else. */
691
+ /* Some sections may already be replaced so account for that */
692
+ unsigned int i = 1 ;
693
+ Elf_Addr pht_size = sizeof (Elf_Ehdr) + (phdrs.size () + 1 )*sizeof (Elf_Phdr);
694
+ while ( shdrs[i].sh_addr <= pht_size && i < rdi (hdr->e_shnum ) ) {
695
+ if (not haveReplacedSection (getSectionName (shdrs[i])))
696
+ replaceSection (getSectionName (shdrs[i]), shdrs[i].sh_size );
697
+ i++;
698
+ }
676
699
677
- /* Compute the total space needed for the replaced sections and
678
- the program headers. */
679
- off_t neededSpace = (phdrs.size () + 1 ) * sizeof (Elf_Phdr);
700
+ /* Compute the total space needed for the replaced sections */
701
+ off_t neededSpace = 0 ;
680
702
for (auto & i : replacedSections)
681
703
neededSpace += roundUp (i.second .size (), sectionAlignment);
682
704
debug (" needed space is %d\n " , neededSpace);
683
705
684
-
685
706
size_t startOffset = roundUp (fileContents->size (), getPageSize ());
686
707
687
708
growFile (fileContents, startOffset + neededSpace);
688
709
689
-
690
710
/* Even though this file is of type ET_DYN, it could actually be
691
711
an executable. For instance, Gold produces executables marked
692
- ET_DYN. In that case we can still hit the kernel bug that
693
- necessitated rewriteSectionsExecutable(). However, such
694
- executables also tend to start at virtual address 0, so
712
+ ET_DYN as does LD when linking with pie. If we move PT_PHDR, it
713
+ has to stay in the first PT_LOAD segment or any subsequent ones
714
+ if they're continuous in memory due to linux kernel constraints
715
+ (see BUGS). Since the end of the file would be after bss, we can't
716
+ move PHDR there, we therefore choose to leave PT_PHDR where it is but
717
+ move enough following sections such that we can add the extra PT_LOAD
718
+ section to it. This PT_LOAD segment ensures the sections at the end of
719
+ the file are mapped into memory for ld.so to process.
720
+ We can't use the approach in rewriteSectionsExecutable()
721
+ since DYN executables tend to start at virtual address 0, so
695
722
rewriteSectionsExecutable() won't work because it doesn't have
696
- any virtual address space to grow downwards into. As a
697
- workaround, make sure that the virtual address of our new
698
- PT_LOAD segment relative to the first PT_LOAD segment is equal
699
- to its offset; otherwise we hit the kernel bug. This may
700
- require creating a hole in the executable. The bigger the size
701
- of the uninitialised data segment, the bigger the hole. */
723
+ any virtual address space to grow downwards into. */
702
724
if (isExecutable) {
703
725
if (startOffset >= startPage) {
704
726
debug (" shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n " , startOffset - startPage);
705
- } else {
706
- size_t hole = startPage - startOffset;
707
- /* Print a warning, because the hole could be very big. */
708
- fprintf (stderr, " warning: working around a Linux kernel bug by creating a hole of %zu bytes in '%s'\n " , hole, fileName.c_str ());
709
- assert (hole % getPageSize () == 0 );
710
- /* !!! We could create an actual hole in the file here,
711
- but it's probably not worth the effort. */
712
- growFile (fileContents, fileContents->size () + hole);
713
- startOffset += hole;
714
727
}
715
728
startPage = startOffset;
716
729
}
717
730
718
-
719
- /* Add a segment that maps the replaced sections and program
720
- headers into memory. */
731
+ /* Add a segment that maps the replaced sections into memory. */
721
732
phdrs.resize (rdi (hdr->e_phnum ) + 1 );
722
733
wri (hdr->e_phnum , rdi (hdr->e_phnum ) + 1 );
723
734
Elf_Phdr & phdr = phdrs[rdi (hdr->e_phnum ) - 1 ];
@@ -730,15 +741,12 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
730
741
731
742
732
743
/* Write out the replaced sections. */
733
- Elf_Off curOff = startOffset + phdrs. size () * sizeof (Elf_Phdr) ;
744
+ Elf_Off curOff = startOffset;
734
745
writeReplacedSections (curOff, startPage, startOffset);
735
746
assert (curOff == startOffset + neededSpace);
736
747
737
-
738
- /* Move the program header to the start of the new area. */
739
- wri (hdr->e_phoff , startOffset);
740
-
741
- rewriteHeaders (startPage);
748
+ /* Write out the updated program and section headers */
749
+ rewriteHeaders (hdr->e_phoff );
742
750
}
743
751
744
752
0 commit comments