@@ -432,44 +432,83 @@ static uint64_t roundUp(uint64_t n, uint64_t m)
432432
433433
434434template <ElfFileParams>
435- void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, Elf_Addr startPage )
435+ void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, size_t startOffset )
436436{
437- /* Move the entire contents of the file 'extraPages' pages
438- further. */
437+ assert (startOffset >= sizeof (Elf_Ehdr));
438+
439439 unsigned int oldSize = fileContents->size ();
440+ assert (oldSize > startOffset);
441+
442+ /* Move the entire contents of the file after 'startOffset' by 'extraPages' pages further. */
440443 unsigned int shift = extraPages * getPageSize ();
441444 fileContents->resize (oldSize + shift, 0 );
442- memmove (fileContents->data () + shift, fileContents->data (), oldSize);
443- memset (fileContents->data () + sizeof (Elf_Ehdr) , 0 , shift - sizeof (Elf_Ehdr) );
445+ memmove (fileContents->data () + startOffset + shift, fileContents->data () + startOffset , oldSize - startOffset );
446+ memset (fileContents->data () + startOffset , 0 , shift);
444447
445448 /* Adjust the ELF header. */
446449 wri (hdr ()->e_phoff , sizeof (Elf_Ehdr));
447- wri (hdr ()->e_shoff , rdi (hdr ()->e_shoff ) + shift);
450+ if (rdi (hdr ()->e_shoff ) >= startOffset)
451+ wri (hdr ()->e_shoff , rdi (hdr ()->e_shoff ) + shift);
448452
449453 /* Update the offsets in the section headers. */
450- for (int i = 1 ; i < rdi (hdr ()->e_shnum ); ++i)
451- wri (shdrs.at (i).sh_offset , rdi (shdrs.at (i).sh_offset ) + shift);
454+ for (int i = 1 ; i < rdi (hdr ()->e_shnum ); ++i) {
455+ size_t sh_offset = rdi (shdrs.at (i).sh_offset );
456+ if (sh_offset >= startOffset)
457+ wri (shdrs.at (i).sh_offset , sh_offset + shift);
458+ }
459+
460+ int splitIndex = -1 ;
461+ size_t splitShift = 0 ;
452462
453463 /* Update the offsets in the program headers. */
454464 for (int i = 0 ; i < rdi (hdr ()->e_phnum ); ++i) {
455- wri (phdrs.at (i).p_offset , rdi (phdrs.at (i).p_offset ) + shift);
456- if (rdi (phdrs.at (i).p_align ) != 0 &&
457- (rdi (phdrs.at (i).p_vaddr ) - rdi (phdrs.at (i).p_offset )) % rdi (phdrs.at (i).p_align ) != 0 ) {
458- debug (" changing alignment of program header %d from %d to %d\n " , i,
459- rdi (phdrs.at (i).p_align ), getPageSize ());
460- wri (phdrs.at (i).p_align , getPageSize ());
465+ Elf_Off p_start = rdi (phdrs.at (i).p_offset );
466+
467+ if (p_start <= startOffset && p_start + rdi (phdrs.at (i).p_filesz ) > startOffset && rdi (phdrs.at (i).p_type ) == PT_LOAD) {
468+ assert (splitIndex == -1 );
469+
470+ splitIndex = i;
471+ splitShift = startOffset - p_start;
472+
473+ /* This is the load segment we're currently extending within, so we split it. */
474+ wri (phdrs.at (i).p_offset , startOffset);
475+ wri (phdrs.at (i).p_memsz , rdi (phdrs.at (i).p_memsz ) - splitShift);
476+ wri (phdrs.at (i).p_filesz , rdi (phdrs.at (i).p_filesz ) - splitShift);
477+ wri (phdrs.at (i).p_paddr , rdi (phdrs.at (i).p_paddr ) + splitShift);
478+ wri (phdrs.at (i).p_vaddr , rdi (phdrs.at (i).p_vaddr ) + splitShift);
479+
480+ p_start = startOffset;
481+ }
482+
483+ if (p_start >= startOffset) {
484+ wri (phdrs.at (i).p_offset , p_start + shift);
485+ if (rdi (phdrs.at (i).p_align ) != 0 &&
486+ (rdi (phdrs.at (i).p_vaddr ) - rdi (phdrs.at (i).p_offset )) % rdi (phdrs.at (i).p_align ) != 0 ) {
487+ debug (" changing alignment of program header %d from %d to %d\n " , i,
488+ rdi (phdrs.at (i).p_align ), getPageSize ());
489+ wri (phdrs.at (i).p_align , getPageSize ());
490+ }
491+ } else {
492+ /* If we're not physically shifting, shift back virtual memory. */
493+ if (rdi (phdrs.at (i).p_paddr ) >= shift)
494+ wri (phdrs.at (i).p_paddr , rdi (phdrs.at (i).p_paddr ) - shift);
495+ if (rdi (phdrs.at (i).p_vaddr ) >= shift)
496+ wri (phdrs.at (i).p_vaddr , rdi (phdrs.at (i).p_vaddr ) - shift);
461497 }
462498 }
463499
500+ assert (splitIndex != -1 );
501+
464502 /* Add a segment that maps the new program/section headers and
465503 PT_INTERP segment into memory. Otherwise glibc will choke. */
466504 phdrs.resize (rdi (hdr ()->e_phnum ) + 1 );
467505 wri (hdr ()->e_phnum , rdi (hdr ()->e_phnum ) + 1 );
468506 Elf_Phdr & phdr = phdrs.at (rdi (hdr ()->e_phnum ) - 1 );
469507 wri (phdr.p_type , PT_LOAD);
470- wri (phdr.p_offset , 0 );
471- wri (phdr.p_vaddr , wri (phdr.p_paddr , startPage));
472- wri (phdr.p_filesz , wri (phdr.p_memsz , shift));
508+ wri (phdr.p_offset , phdrs.at (splitIndex).p_offset - splitShift - shift);
509+ wri (phdr.p_paddr , phdrs.at (splitIndex).p_paddr - splitShift - shift);
510+ wri (phdr.p_vaddr , phdrs.at (splitIndex).p_vaddr - splitShift - shift);
511+ wri (phdr.p_filesz , wri (phdr.p_memsz , splitShift + shift));
473512 wri (phdr.p_flags , PF_R | PF_W);
474513 wri (phdr.p_align , getPageSize ());
475514}
@@ -855,7 +894,6 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
855894 file by the minimum number of pages and adjust internal
856895 offsets. */
857896 if (neededSpace > startOffset) {
858-
859897 /* We also need an additional program header, so adjust for that. */
860898 neededSpace += sizeof (Elf_Phdr);
861899 debug (" needed space is %d\n " , neededSpace);
@@ -865,10 +903,10 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
865903 if (neededPages * getPageSize () > firstPage)
866904 error (" virtual address space underrun!" );
867905
906+ shiftFile (neededPages, startOffset);
907+
868908 firstPage -= neededPages * getPageSize ();
869909 startOffset += neededPages * getPageSize ();
870-
871- shiftFile (neededPages, firstPage);
872910 }
873911
874912
0 commit comments