@@ -555,8 +555,7 @@ void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, size_t start
555
555
556
556
assert (splitIndex != -1 );
557
557
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. */
560
559
phdrs.resize (rdi (hdr ()->e_phnum ) + 1 );
561
560
wri (hdr ()->e_phnum , rdi (hdr ()->e_phnum ) + 1 );
562
561
Elf_Phdr & phdr = phdrs.at (rdi (hdr ()->e_phnum ) - 1 );
@@ -823,28 +822,16 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
823
822
unsigned int num_notes = std::count_if (shdrs.begin (), shdrs.end (),
824
823
[this ](Elf_Shdr shdr) { return rdi (shdr.sh_type ) == SHT_NOTE; });
825
824
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;
839
831
840
- /* Compute the total space needed for the replaced sections */
841
- off_t neededSpace = 0 ;
842
832
for (auto & s : replacedSections)
843
833
neededSpace += roundUp (s.second .size (), sectionAlignment);
844
834
845
- off_t headerTableSpace = roundUp (rdi (hdr ()->e_shnum ) * rdi (hdr ()->e_shentsize ), sectionAlignment);
846
- if (moveHeaderTableToTheEnd)
847
- neededSpace += headerTableSpace;
848
835
debug (" needed space is %d\n " , neededSpace);
849
836
850
837
Elf_Off startOffset = roundUp (fileContents->size (), alignStartPage);
@@ -853,45 +840,32 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
853
840
// section segment is strictly smaller than the file (and not same size).
854
841
// By making it one byte larger, we don't break readelf.
855
842
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
- }
876
843
877
- wri ( hdr ()-> e_phoff , sizeof (Elf_Ehdr) );
844
+ fileContents-> resize (startOffset + neededSpace + binutilsQuirkPadding, 0 );
878
845
879
- bool needNewSegment = true ;
846
+ Elf_Addr phdrAddress = 0 ;
880
847
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 */
882
851
if (!phdrs.empty () &&
883
852
rdi (lastSeg.p_type ) == PT_LOAD &&
884
853
rdi (lastSeg.p_flags ) == (PF_R | PF_W) &&
885
854
rdi (lastSeg.p_align ) == alignStartPage) {
886
855
auto segEnd = roundUp (rdi (lastSeg.p_offset ) + rdi (lastSeg.p_memsz ), alignStartPage);
856
+
887
857
if (segEnd == startOffset) {
888
858
auto newSz = startOffset + neededSpace - rdi (lastSeg.p_offset );
859
+
889
860
wri (lastSeg.p_filesz , wri (lastSeg.p_memsz , newSz));
890
- needNewSegment = false ;
861
+
862
+ phdrAddress = rdi (lastSeg.p_vaddr ) + newSz - neededSpace;
891
863
}
892
864
}
893
865
894
- if (needNewSegment) {
866
+ if (phdrAddress == 0 ) {
867
+ debug (" allocating new PT_LOAD segment for pht\n " );
868
+
895
869
/* Add a segment that maps the replaced sections into memory. */
896
870
phdrs.resize (rdi (hdr ()->e_phnum ) + 1 );
897
871
wri (hdr ()->e_phnum , rdi (hdr ()->e_phnum ) + 1 );
@@ -903,25 +877,37 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
903
877
wri (phdr.p_flags , PF_R | PF_W);
904
878
wri (phdr.p_align , alignStartPage);
905
879
assert (startPage % alignStartPage == startOffset % alignStartPage);
880
+
881
+ phdrAddress = startPage;
906
882
}
907
883
908
884
normalizeNoteSegments ();
909
885
910
-
911
886
/* Write out the replaced sections. */
912
887
Elf_Off curOff = startOffset;
913
888
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);
919
899
900
+ wri (hdr ()->e_shoff , curOff);
901
+ curOff += shtSize;
902
+
903
+ // ---
904
+
905
+ /* Write out the replaced sections. */
920
906
writeReplacedSections (curOff, startPage, startOffset);
921
907
assert (curOff == startOffset + neededSpace);
922
908
923
909
/* Write out the updated program and section headers */
924
- rewriteHeaders (firstPage + rdi ( hdr ()-> e_phoff ) );
910
+ rewriteHeaders (phdrAddress );
925
911
}
926
912
927
913
static bool noSort = false ;
@@ -1035,32 +1021,35 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
1035
1021
1036
1022
firstPage -= neededPages * getPageSize ();
1037
1023
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
- }
1050
1024
}
1051
1025
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
+ }
1052
1043
1053
1044
/* Clear out the free space. */
1054
- Elf_Off curOff = sizeof (Elf_Ehdr) + phdrs.size () * sizeof (Elf_Phdr);
1055
1045
debug (" clearing first %d bytes\n " , startOffset - curOff);
1056
1046
memset (fileContents->data () + curOff, 0 , startOffset - curOff);
1057
1047
1058
-
1059
1048
/* Write out the replaced sections. */
1060
1049
writeReplacedSections (curOff, firstPage, 0 );
1061
1050
assert (curOff == neededSpace);
1062
1051
1063
-
1052
+ /* Write out the updated program and section headers */
1064
1053
rewriteHeaders (firstPage + rdi (hdr ()->e_phoff ));
1065
1054
}
1066
1055
0 commit comments