@@ -55,6 +55,8 @@ class ElfFile
5555
5656 bool changed;
5757
58+ bool isExecutable;
59+
5860 typedef string SectionName;
5961 typedef map<SectionName, string> ReplacedSections;
6062
@@ -245,6 +247,8 @@ static void checkPointer(void * p, unsigned int size)
245247template <ElfFileParams>
246248void ElfFile<ElfFileParamNames>::parse()
247249{
250+ isExecutable = false ;
251+
248252 /* Check the ELF header for basic validity. */
249253 if (fileSize < (off_t ) sizeof (Elf_Ehdr)) error (" missing ELF header" );
250254
@@ -268,8 +272,10 @@ void ElfFile<ElfFileParamNames>::parse()
268272 error (" program headers have wrong size" );
269273
270274 /* Copy the program and section headers. */
271- for (int i = 0 ; i < rdi (hdr->e_phnum ); ++i)
275+ for (int i = 0 ; i < rdi (hdr->e_phnum ); ++i) {
272276 phdrs.push_back (* ((Elf_Phdr *) (contents + rdi (hdr->e_phoff )) + i));
277+ if (rdi (phdrs[i].p_type ) == PT_INTERP) isExecutable = true ;
278+ }
273279
274280 for (int i = 0 ; i < rdi (hdr->e_shnum ); ++i)
275281 shdrs.push_back (* ((Elf_Shdr *) (contents + rdi (hdr->e_shoff )) + i));
@@ -486,7 +492,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
486492 {
487493 string sectionName = i->first ;
488494 Elf_Shdr & shdr = findSection (sectionName);
489- debug (" rewriting section `%s' from offset %d (size %d) to offset %d (size %d)\n " ,
495+ debug (" rewriting section `%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n " ,
490496 sectionName.c_str (), rdi (shdr.sh_offset ), rdi (shdr.sh_size ), curOff, i->second .size ());
491497
492498 memcpy (contents + curOff, (unsigned char *) i->second .c_str (),
@@ -552,11 +558,40 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
552558 debug (" needed space is %d\n " , neededSpace);
553559
554560
555- off_t startOffset = roundUp (fileSize, pageSize);
561+ size_t startOffset = roundUp (fileSize, pageSize);
556562
557563 growFile (startOffset + neededSpace);
558564
559565
566+ /* Even though this file is of type ET_DYN, it could actually be
567+ an executable. For instance, Gold produces executables marked
568+ ET_DYN. In that case we can still hit the kernel bug that
569+ necessitated rewriteSectionsExecutable(). However, such
570+ executables also tend to start at virtual address 0, so
571+ rewriteSectionsExecutable() won't work because it doesn't have
572+ any virtual address space to grow downwards into. As a
573+ workaround, make sure that the virtual address of our new
574+ PT_LOAD segment relative to the first PT_LOAD segment is equal
575+ to its offset; otherwise we hit the kernel bug. This may
576+ require creating a hole in the executable. The bigger the size
577+ of the uninitialised data segment, the bigger the hole. */
578+ if (isExecutable) {
579+ if (startOffset >= startPage) {
580+ debug (" shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n " , startOffset - startPage);
581+ } else {
582+ size_t hole = startPage - startOffset;
583+ /* Print a warning, because the hole could be very big. */
584+ fprintf (stderr, " warning: working around a Linux kernel bug by creating a hole of %zu bytes in ‘%s’\n " , hole, fileName.c_str ());
585+ assert (hole % pageSize == 0 );
586+ /* !!! We could create an actual hole in the file here,
587+ but it's probably not worth the effort. */
588+ growFile (fileSize + hole);
589+ startOffset += hole;
590+ }
591+ startPage = startOffset;
592+ }
593+
594+
560595 /* Add a segment that maps the replaced sections and program
561596 headers into memory. */
562597 phdrs.resize (rdi (hdr->e_phnum ) + 1 );
@@ -610,7 +645,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
610645 SHT_PROGBITS). These cannot be moved in virtual address space
611646 since that would invalidate absolute references to them. */
612647 assert (lastReplaced + 1 < shdrs.size ()); /* !!! I'm lazy. */
613- off_t startOffset = rdi (shdrs[lastReplaced + 1 ].sh_offset );
648+ size_t startOffset = rdi (shdrs[lastReplaced + 1 ].sh_offset );
614649 Elf_Addr startAddr = rdi (shdrs[lastReplaced + 1 ].sh_addr );
615650 string prevSection;
616651 for (unsigned int i = 1 ; i <= lastReplaced; ++i) {
@@ -651,7 +686,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
651686
652687 /* Compute the total space needed for the replaced sections, the
653688 ELF header, and the program headers. */
654- off_t neededSpace = sizeof (Elf_Ehdr) + phdrs.size () * sizeof (Elf_Phdr);
689+ size_t neededSpace = sizeof (Elf_Ehdr) + phdrs.size () * sizeof (Elf_Phdr);
655690 for (ReplacedSections::iterator i = replacedSections.begin ();
656691 i != replacedSections.end (); ++i)
657692 neededSpace += roundUp (i->second .size (), sectionAlignment);
0 commit comments