@@ -171,6 +171,8 @@ class ElfFile
171171 std::string & replaceSection (const SectionName & sectionName,
172172 unsigned int size);
173173
174+ bool haveReplacedSection (const SectionName & sectionName);
175+
174176 void writeReplacedSections (Elf_Off & curOff,
175177 Elf_Addr startAddr, Elf_Off startOffset);
176178
@@ -579,6 +581,15 @@ unsigned int ElfFile<ElfFileParamNames>::findSection3(const SectionName & sectio
579581 return 0 ;
580582}
581583
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+ }
582593
583594template <ElfFileParams>
584595std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sectionName,
@@ -673,51 +684,51 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
673684
674685 debug (" last page is 0x%llx\n " , (unsigned long long ) startPage);
675686
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+ }
676699
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 ;
680702 for (auto & i : replacedSections)
681703 neededSpace += roundUp (i.second .size (), sectionAlignment);
682704 debug (" needed space is %d\n " , neededSpace);
683705
684-
685706 size_t startOffset = roundUp (fileContents->size (), getPageSize ());
686707
687708 growFile (fileContents, startOffset + neededSpace);
688709
689-
690710 /* Even though this file is of type ET_DYN, it could actually be
691711 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
695722 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. */
702724 if (isExecutable) {
703725 if (startOffset >= startPage) {
704726 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;
714727 }
715728 startPage = startOffset;
716729 }
717730
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. */
721732 phdrs.resize (rdi (hdr->e_phnum ) + 1 );
722733 wri (hdr->e_phnum , rdi (hdr->e_phnum ) + 1 );
723734 Elf_Phdr & phdr = phdrs[rdi (hdr->e_phnum ) - 1 ];
@@ -730,15 +741,12 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
730741
731742
732743 /* Write out the replaced sections. */
733- Elf_Off curOff = startOffset + phdrs. size () * sizeof (Elf_Phdr) ;
744+ Elf_Off curOff = startOffset;
734745 writeReplacedSections (curOff, startPage, startOffset);
735746 assert (curOff == startOffset + neededSpace);
736747
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 );
742750}
743751
744752
0 commit comments