@@ -555,8 +555,7 @@ void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, size_t start
555555
556556 assert (splitIndex != -1 );
557557
558- /* Add a segment that maps the new program/section headers and
559- PT_INTERP segment into memory. Otherwise glibc will choke. */
558+ /* Add another PT_LOAD segment loading the data we've split above. */
560559 phdrs.resize (rdi (hdr ()->e_phnum ) + 1 );
561560 wri (hdr ()->e_phnum , rdi (hdr ()->e_phnum ) + 1 );
562561 Elf_Phdr & phdr = phdrs.at (rdi (hdr ()->e_phnum ) - 1 );
@@ -823,28 +822,16 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
823822 unsigned int num_notes = std::count_if (shdrs.begin (), shdrs.end (),
824823 [this ](Elf_Shdr shdr) { return rdi (shdr.sh_type ) == SHT_NOTE; });
825824
826- /* Because we're adding a new section header, we're necessarily increasing
827- the size of the program header table. This can cause the first section
828- to overlap the program header table in memory; we need to shift the first
829- few segments to someplace else. */
830- /* Some sections may already be replaced so account for that */
831- unsigned int i = 1 ;
832- Elf_Addr pht_size = sizeof (Elf_Ehdr) + (phdrs.size () + num_notes + 1 )*sizeof (Elf_Phdr);
833- while ( i < rdi (hdr ()->e_shnum ) && rdi (shdrs.at (i).sh_offset ) <= pht_size ) {
834- if (not haveReplacedSection (getSectionName (shdrs.at (i))))
835- replaceSection (getSectionName (shdrs.at (i)), rdi (shdrs.at (i).sh_size ));
836- i++;
837- }
838- bool moveHeaderTableToTheEnd = rdi (hdr ()->e_shoff ) < pht_size;
825+ /* Compute the total space needed for the replaced sections, pessimistically
826+ assuming we're going to need one more to account for new PT_LOAD covering
827+ relocated PHDR */
828+ off_t phtSize = roundUp ((phdrs.size () + num_notes + 1 ) * sizeof (Elf_Phdr), sectionAlignment);
829+ off_t shtSize = roundUp (rdi (hdr ()->e_shnum ) * rdi (hdr ()->e_shentsize ), sectionAlignment);
830+ off_t neededSpace = phtSize + shtSize;
839831
840- /* Compute the total space needed for the replaced sections */
841- off_t neededSpace = 0 ;
842832 for (auto & s : replacedSections)
843833 neededSpace += roundUp (s.second .size (), sectionAlignment);
844834
845- off_t headerTableSpace = roundUp (rdi (hdr ()->e_shnum ) * rdi (hdr ()->e_shentsize ), sectionAlignment);
846- if (moveHeaderTableToTheEnd)
847- neededSpace += headerTableSpace;
848835 debug (" needed space is %d\n " , neededSpace);
849836
850837 Elf_Off startOffset = roundUp (fileContents->size (), alignStartPage);
@@ -853,45 +840,32 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
853840 // section segment is strictly smaller than the file (and not same size).
854841 // By making it one byte larger, we don't break readelf.
855842 off_t binutilsQuirkPadding = 1 ;
856- fileContents->resize (startOffset + neededSpace + binutilsQuirkPadding, 0 );
857-
858- /* Even though this file is of type ET_DYN, it could actually be
859- an executable. For instance, Gold produces executables marked
860- ET_DYN as does LD when linking with pie. If we move PT_PHDR, it
861- has to stay in the first PT_LOAD segment or any subsequent ones
862- if they're continuous in memory due to linux kernel constraints
863- (see BUGS). Since the end of the file would be after bss, we can't
864- move PHDR there, we therefore choose to leave PT_PHDR where it is but
865- move enough following sections such that we can add the extra PT_LOAD
866- section to it. This PT_LOAD segment ensures the sections at the end of
867- the file are mapped into memory for ld.so to process.
868- We can't use the approach in rewriteSectionsExecutable()
869- since DYN executables tend to start at virtual address 0, so
870- rewriteSectionsExecutable() won't work because it doesn't have
871- any virtual address space to grow downwards into. */
872- if (isExecutable && startOffset > startPage) {
873- debug (" shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n " , startOffset - startPage);
874- startPage = startOffset;
875- }
876843
877- wri ( hdr ()-> e_phoff , sizeof (Elf_Ehdr) );
844+ fileContents-> resize (startOffset + neededSpace + binutilsQuirkPadding, 0 );
878845
879- bool needNewSegment = true ;
846+ Elf_Addr phdrAddress = 0 ;
880847 auto & lastSeg = phdrs.back ();
881- /* Try to extend the last segment to include replaced sections */
848+
849+ /* As an optimization, instead of allocating a new PT_LOAD segment, try
850+ expanding the last one */
882851 if (!phdrs.empty () &&
883852 rdi (lastSeg.p_type ) == PT_LOAD &&
884853 rdi (lastSeg.p_flags ) == (PF_R | PF_W) &&
885854 rdi (lastSeg.p_align ) == alignStartPage) {
886855 auto segEnd = roundUp (rdi (lastSeg.p_offset ) + rdi (lastSeg.p_memsz ), alignStartPage);
856+
887857 if (segEnd == startOffset) {
888858 auto newSz = startOffset + neededSpace - rdi (lastSeg.p_offset );
859+
889860 wri (lastSeg.p_filesz , wri (lastSeg.p_memsz , newSz));
890- needNewSegment = false ;
861+
862+ phdrAddress = rdi (lastSeg.p_vaddr ) + newSz - neededSpace;
891863 }
892864 }
893865
894- if (needNewSegment) {
866+ if (phdrAddress == 0 ) {
867+ debug (" allocating new PT_LOAD segment for pht\n " );
868+
895869 /* Add a segment that maps the replaced sections into memory. */
896870 phdrs.resize (rdi (hdr ()->e_phnum ) + 1 );
897871 wri (hdr ()->e_phnum , rdi (hdr ()->e_phnum ) + 1 );
@@ -903,25 +877,37 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
903877 wri (phdr.p_flags , PF_R | PF_W);
904878 wri (phdr.p_align , alignStartPage);
905879 assert (startPage % alignStartPage == startOffset % alignStartPage);
880+
881+ phdrAddress = startPage;
906882 }
907883
908884 normalizeNoteSegments ();
909885
910-
911886 /* Write out the replaced sections. */
912887 Elf_Off curOff = startOffset;
913888
914- if (moveHeaderTableToTheEnd) {
915- debug (" Moving the shtable to offset %d\n " , curOff);
916- wri (hdr ()->e_shoff , curOff);
917- curOff += headerTableSpace;
918- }
889+ debug (" rewriting pht from offset 0x%x to offset 0x%x (size %d)\n " ,
890+ rdi (hdr ()->e_phoff ), curOff, phtSize);
891+
892+ wri (hdr ()->e_phoff , curOff);
893+ curOff += phtSize;
894+
895+ // ---
896+
897+ debug (" rewriting sht from offset 0x%x to offset 0x%x (size %d)\n " ,
898+ rdi (hdr ()->e_shoff ), curOff, shtSize);
919899
900+ wri (hdr ()->e_shoff , curOff);
901+ curOff += shtSize;
902+
903+ // ---
904+
905+ /* Write out the replaced sections. */
920906 writeReplacedSections (curOff, startPage, startOffset);
921907 assert (curOff == startOffset + neededSpace);
922908
923909 /* Write out the updated program and section headers */
924- rewriteHeaders (firstPage + rdi ( hdr ()-> e_phoff ) );
910+ rewriteHeaders (phdrAddress );
925911}
926912
927913static bool noSort = false ;
@@ -1035,32 +1021,35 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
10351021
10361022 firstPage -= neededPages * getPageSize ();
10371023 startOffset += neededPages * getPageSize ();
1038- } else {
1039- Elf_Off rewrittenSectionsOffset = sizeof (Elf_Ehdr) + phdrs.size () * sizeof (Elf_Phdr);
1040- for (auto & phdr : phdrs)
1041- if (rdi (phdr.p_type ) == PT_LOAD &&
1042- rdi (phdr.p_offset ) <= rewrittenSectionsOffset &&
1043- rdi (phdr.p_offset ) + rdi (phdr.p_filesz ) > rewrittenSectionsOffset &&
1044- rdi (phdr.p_filesz ) < neededSpace)
1045- {
1046- wri (phdr.p_filesz , neededSpace);
1047- wri (phdr.p_memsz , neededSpace);
1048- break ;
1049- }
10501024 }
10511025
1026+ Elf_Off curOff = sizeof (Elf_Ehdr) + phdrs.size () * sizeof (Elf_Phdr);
1027+
1028+ /* Ensure PHDR is covered by a LOAD segment.
1029+
1030+ Because PHDR is supposed to have been covered by such section before, in
1031+ here we assume that we don't have to create any new section, but rather
1032+ extend the existing one. */
1033+ for (auto & phdr : phdrs)
1034+ if (rdi (phdr.p_type ) == PT_LOAD &&
1035+ rdi (phdr.p_offset ) <= curOff &&
1036+ rdi (phdr.p_offset ) + rdi (phdr.p_filesz ) > curOff &&
1037+ rdi (phdr.p_filesz ) < neededSpace)
1038+ {
1039+ wri (phdr.p_filesz , neededSpace);
1040+ wri (phdr.p_memsz , neededSpace);
1041+ break ;
1042+ }
10521043
10531044 /* Clear out the free space. */
1054- Elf_Off curOff = sizeof (Elf_Ehdr) + phdrs.size () * sizeof (Elf_Phdr);
10551045 debug (" clearing first %d bytes\n " , startOffset - curOff);
10561046 memset (fileContents->data () + curOff, 0 , startOffset - curOff);
10571047
1058-
10591048 /* Write out the replaced sections. */
10601049 writeReplacedSections (curOff, firstPage, 0 );
10611050 assert (curOff == neededSpace);
10621051
1063-
1052+ /* Write out the updated program and section headers */
10641053 rewriteHeaders (firstPage + rdi (hdr ()->e_phoff ));
10651054}
10661055
0 commit comments