@@ -55,6 +55,8 @@ class ElfFile
55
55
56
56
bool changed;
57
57
58
+ bool isExecutable;
59
+
58
60
typedef string SectionName;
59
61
typedef map<SectionName, string> ReplacedSections;
60
62
@@ -245,6 +247,8 @@ static void checkPointer(void * p, unsigned int size)
245
247
template <ElfFileParams>
246
248
void ElfFile<ElfFileParamNames>::parse()
247
249
{
250
+ isExecutable = false ;
251
+
248
252
/* Check the ELF header for basic validity. */
249
253
if (fileSize < (off_t ) sizeof (Elf_Ehdr)) error (" missing ELF header" );
250
254
@@ -268,8 +272,10 @@ void ElfFile<ElfFileParamNames>::parse()
268
272
error (" program headers have wrong size" );
269
273
270
274
/* 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) {
272
276
phdrs.push_back (* ((Elf_Phdr *) (contents + rdi (hdr->e_phoff )) + i));
277
+ if (rdi (phdrs[i].p_type ) == PT_INTERP) isExecutable = true ;
278
+ }
273
279
274
280
for (int i = 0 ; i < rdi (hdr->e_shnum ); ++i)
275
281
shdrs.push_back (* ((Elf_Shdr *) (contents + rdi (hdr->e_shoff )) + i));
@@ -486,7 +492,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
486
492
{
487
493
string sectionName = i->first ;
488
494
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 " ,
490
496
sectionName.c_str (), rdi (shdr.sh_offset ), rdi (shdr.sh_size ), curOff, i->second .size ());
491
497
492
498
memcpy (contents + curOff, (unsigned char *) i->second .c_str (),
@@ -552,11 +558,40 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
552
558
debug (" needed space is %d\n " , neededSpace);
553
559
554
560
555
- off_t startOffset = roundUp (fileSize, pageSize);
561
+ size_t startOffset = roundUp (fileSize, pageSize);
556
562
557
563
growFile (startOffset + neededSpace);
558
564
559
565
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
+
560
595
/* Add a segment that maps the replaced sections and program
561
596
headers into memory. */
562
597
phdrs.resize (rdi (hdr->e_phnum ) + 1 );
@@ -610,7 +645,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
610
645
SHT_PROGBITS). These cannot be moved in virtual address space
611
646
since that would invalidate absolute references to them. */
612
647
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 );
614
649
Elf_Addr startAddr = rdi (shdrs[lastReplaced + 1 ].sh_addr );
615
650
string prevSection;
616
651
for (unsigned int i = 1 ; i <= lastReplaced; ++i) {
@@ -651,7 +686,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
651
686
652
687
/* Compute the total space needed for the replaced sections, the
653
688
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);
655
690
for (ReplacedSections::iterator i = replacedSections.begin ();
656
691
i != replacedSections.end (); ++i)
657
692
neededSpace += roundUp (i->second .size (), sectionAlignment);
0 commit comments