@@ -547,9 +547,14 @@ Error RewriteInstance::discoverStorage() {
547547 NextAvailableOffset = std::max (NextAvailableOffset,
548548 Phdr.p_offset + Phdr.p_filesz );
549549
550- BC->SegmentMapInfo [Phdr.p_vaddr ] = SegmentInfo{
551- Phdr.p_vaddr , Phdr.p_memsz , Phdr.p_offset ,
552- Phdr.p_filesz , Phdr.p_align , ((Phdr.p_flags & ELF::PF_X) != 0 )};
550+ BC->SegmentMapInfo [Phdr.p_vaddr ] =
551+ SegmentInfo{Phdr.p_vaddr ,
552+ Phdr.p_memsz ,
553+ Phdr.p_offset ,
554+ Phdr.p_filesz ,
555+ Phdr.p_align ,
556+ (Phdr.p_flags & ELF::PF_X) != 0 ,
557+ (Phdr.p_flags & ELF::PF_W) != 0 };
553558 if (BC->TheTriple ->getArch () == llvm::Triple::x86_64 &&
554559 Phdr.p_vaddr >= BinaryContext::KernelStartX86_64)
555560 BC->IsLinuxKernel = true ;
@@ -4155,6 +4160,74 @@ void RewriteInstance::updateOutputValues(const BOLTLinker &Linker) {
41554160 Function->updateOutputValues (Linker);
41564161}
41574162
4163+ void RewriteInstance::updateSegmentInfo () {
4164+ // NOTE Currently .eh_frame_hdr appends to the last segment, recalculate
4165+ // last segments size based on the NextAvailableAddress variable.
4166+ if (!NewWritableSegmentSize) {
4167+ if (NewTextSegmentAddress)
4168+ NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress;
4169+ } else {
4170+ NewWritableSegmentSize = NextAvailableAddress - NewWritableSegmentAddress;
4171+ }
4172+
4173+ if (NewTextSegmentSize) {
4174+ SegmentInfo TextSegment = {NewTextSegmentAddress,
4175+ NewTextSegmentSize,
4176+ NewTextSegmentOffset,
4177+ NewTextSegmentSize,
4178+ BC->PageAlign ,
4179+ true ,
4180+ false };
4181+ if (!opts::Instrument) {
4182+ BC->NewSegments .push_back (TextSegment);
4183+ } else {
4184+ ErrorOr<BinarySection &> Sec =
4185+ BC->getUniqueSectionByName (" .bolt.instr.counters" );
4186+ assert (Sec && " expected one and only one `.bolt.instr.counters` section" );
4187+ const uint64_t Addr = Sec->getOutputAddress ();
4188+ const uint64_t Offset = Sec->getOutputFileOffset ();
4189+ const uint64_t Size = Sec->getOutputSize ();
4190+ assert (Addr > TextSegment.Address &&
4191+ Addr + Size < TextSegment.Address + TextSegment.Size &&
4192+ " `.bolt.instr.counters` section is expected to be included in the "
4193+ " new text segment" );
4194+
4195+ // Set correct size for the previous header since we are breaking the
4196+ // new text segment into three segments.
4197+ uint64_t Delta = Addr - TextSegment.Address ;
4198+ TextSegment.Size = Delta;
4199+ TextSegment.FileSize = Delta;
4200+ BC->NewSegments .push_back (TextSegment);
4201+
4202+ // Create RW segment that includes the `.bolt.instr.counters` section.
4203+ SegmentInfo RWSegment = {Addr, Size, Offset, Size, BC->RegularPageSize ,
4204+ false , true };
4205+ BC->NewSegments .push_back (RWSegment);
4206+
4207+ // Create RX segment that includes all RX sections from runtime library.
4208+ const uint64_t AddrRX = alignTo (Addr + Size, BC->RegularPageSize );
4209+ const uint64_t OffsetRX = alignTo (Offset + Size, BC->RegularPageSize );
4210+ const uint64_t SizeRX =
4211+ NewTextSegmentSize - (AddrRX - TextSegment.Address );
4212+ SegmentInfo RXSegment = {
4213+ AddrRX, SizeRX, OffsetRX, SizeRX, BC->RegularPageSize , true , false };
4214+ BC->NewSegments .push_back (RXSegment);
4215+ }
4216+ }
4217+
4218+ if (NewWritableSegmentSize) {
4219+ SegmentInfo DataSegmentInfo = {
4220+ NewWritableSegmentAddress,
4221+ NewWritableSegmentSize,
4222+ getFileOffsetForAddress (NewWritableSegmentAddress),
4223+ NewWritableSegmentSize,
4224+ BC->RegularPageSize ,
4225+ false ,
4226+ true };
4227+ BC->NewSegments .push_back (DataSegmentInfo);
4228+ }
4229+ }
4230+
41584231void RewriteInstance::patchELFPHDRTable () {
41594232 auto ELF64LEFile = cast<ELF64LEObjectFile>(InputFile);
41604233 const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile ();
@@ -4181,107 +4254,36 @@ void RewriteInstance::patchELFPHDRTable() {
41814254 if (opts::Instrument)
41824255 Phnum += 2 ;
41834256
4184- // NOTE Currently .eh_frame_hdr appends to the last segment, recalculate
4185- // last segments size based on the NextAvailableAddress variable.
4186- if (!NewWritableSegmentSize) {
4187- if (NewTextSegmentAddress)
4188- NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress;
4189- } else {
4190- NewWritableSegmentSize = NextAvailableAddress - NewWritableSegmentAddress;
4191- }
4192-
4193- if (!NewTextSegmentSize && !NewWritableSegmentSize) {
4257+ if (BC->NewSegments .empty ()) {
41944258 BC->outs () << " BOLT-INFO: not adding new segments\n " ;
41954259 return ;
41964260 }
41974261
41984262 const uint64_t SavedPos = OS.tell ();
41994263 OS.seek (PHDRTableOffset);
42004264
4201- auto createNewPhdrs = [&]() {
4202- SmallVector<ELF64LEPhdrTy, 3 > NewPhdrs;
4203- ELF64LEPhdrTy NewPhdr;
4204- NewPhdr.p_type = ELF::PT_LOAD;
4205- NewPhdr.p_offset = NewTextSegmentOffset;
4206- NewPhdr.p_vaddr = NewTextSegmentAddress;
4207- NewPhdr.p_paddr = NewTextSegmentAddress;
4208- NewPhdr.p_filesz = NewTextSegmentSize;
4209- NewPhdr.p_memsz = NewTextSegmentSize;
4210- NewPhdr.p_flags = ELF::PF_X | ELF::PF_R;
4211- NewPhdr.p_align = BC->PageAlign ;
4212-
4213- if (!opts::Instrument) {
4214- NewPhdrs.push_back (NewPhdr);
4215- } else {
4216- ErrorOr<BinarySection &> Sec =
4217- BC->getUniqueSectionByName (" .bolt.instr.counters" );
4218- assert (Sec && " expected one and only one `.bolt.instr.counters` section" );
4219- const uint64_t Addr = Sec->getOutputAddress ();
4220- const uint64_t Offset = Sec->getOutputFileOffset ();
4221- const uint64_t Size = Sec->getOutputSize ();
4222- assert (Addr > NewPhdr.p_vaddr &&
4223- Addr + Size < NewPhdr.p_vaddr + NewPhdr.p_memsz &&
4224- " `.bolt.instr.counters` section is expected to be included in the "
4225- " new text sgement" );
4226-
4227- // Set correct size for the previous header since we are breaking the
4228- // new text segment into three segments.
4229- uint64_t Delta = Addr - NewPhdr.p_vaddr ;
4230- NewPhdr.p_filesz = Delta;
4231- NewPhdr.p_memsz = Delta;
4232- NewPhdrs.push_back (NewPhdr);
4233-
4234- // Create a program header for a RW segment that includes the
4235- // `.bolt.instr.counters` section only.
4236- ELF64LEPhdrTy NewPhdrRWSegment;
4237- NewPhdrRWSegment.p_type = ELF::PT_LOAD;
4238- NewPhdrRWSegment.p_offset = Offset;
4239- NewPhdrRWSegment.p_vaddr = Addr;
4240- NewPhdrRWSegment.p_paddr = Addr;
4241- NewPhdrRWSegment.p_filesz = Size;
4242- NewPhdrRWSegment.p_memsz = Size;
4243- NewPhdrRWSegment.p_flags = ELF::PF_R | ELF::PF_W;
4244- NewPhdrRWSegment.p_align = BC->RegularPageSize ;
4245- NewPhdrs.push_back (NewPhdrRWSegment);
4246-
4247- // Create a program header for a RX segment that includes all the RX
4248- // sections from runtime library.
4249- ELF64LEPhdrTy NewPhdrRXSegment;
4250- NewPhdrRXSegment.p_type = ELF::PT_LOAD;
4251- const uint64_t AddrRX = alignTo (Addr + Size, BC->RegularPageSize );
4252- const uint64_t OffsetRX = alignTo (Offset + Size, BC->RegularPageSize );
4253- const uint64_t SizeRX = NewTextSegmentSize - (AddrRX - NewPhdr.p_paddr );
4254- NewPhdrRXSegment.p_offset = OffsetRX;
4255- NewPhdrRXSegment.p_vaddr = AddrRX;
4256- NewPhdrRXSegment.p_paddr = AddrRX;
4257- NewPhdrRXSegment.p_filesz = SizeRX;
4258- NewPhdrRXSegment.p_memsz = SizeRX;
4259- NewPhdrRXSegment.p_flags = ELF::PF_X | ELF::PF_R;
4260- NewPhdrRXSegment.p_align = BC->RegularPageSize ;
4261- NewPhdrs.push_back (NewPhdrRXSegment);
4262- }
4263-
4264- return NewPhdrs;
4265+ auto createPhdr = [](const SegmentInfo &SI) {
4266+ ELF64LEPhdrTy Phdr;
4267+ Phdr.p_type = ELF::PT_LOAD;
4268+ Phdr.p_offset = SI.FileOffset ;
4269+ Phdr.p_vaddr = SI.Address ;
4270+ Phdr.p_paddr = SI.Address ;
4271+ Phdr.p_filesz = SI.FileSize ;
4272+ Phdr.p_memsz = SI.Size ;
4273+ Phdr.p_flags = ELF::PF_R;
4274+ if (SI.IsExecutable )
4275+ Phdr.p_flags |= ELF::PF_X;
4276+ if (SI.IsWritable )
4277+ Phdr.p_flags |= ELF::PF_W;
4278+ Phdr.p_align = SI.Alignment ;
4279+
4280+ return Phdr;
42654281 };
42664282
42674283 auto writeNewSegmentPhdrs = [&]() {
4268- if (NewTextSegmentSize) {
4269- SmallVector<ELF64LE::Phdr, 3 > NewPhdrs = createNewPhdrs ();
4270- OS.write (reinterpret_cast <const char *>(NewPhdrs.data ()),
4271- sizeof (ELF64LE::Phdr) * NewPhdrs.size ());
4272- }
4273-
4274- if (NewWritableSegmentSize) {
4275- ELF64LEPhdrTy NewPhdr;
4276- NewPhdr.p_type = ELF::PT_LOAD;
4277- NewPhdr.p_offset = getFileOffsetForAddress (NewWritableSegmentAddress);
4278- NewPhdr.p_vaddr = NewWritableSegmentAddress;
4279- NewPhdr.p_paddr = NewWritableSegmentAddress;
4280- NewPhdr.p_filesz = NewWritableSegmentSize;
4281- NewPhdr.p_memsz = NewWritableSegmentSize;
4282- NewPhdr.p_align = BC->RegularPageSize ;
4283- NewPhdr.p_flags = ELF::PF_R | ELF::PF_W;
4284- OS.write (reinterpret_cast <const char *>(&NewPhdr), sizeof (NewPhdr));
4284+ for (const SegmentInfo &SI : BC->NewSegments ) {
4285+ ELF64LEPhdrTy Phdr = createPhdr (SI);
4286+ OS.write (reinterpret_cast <const char *>(&Phdr), sizeof (Phdr));
42854287 }
42864288 };
42874289
@@ -4317,11 +4319,9 @@ void RewriteInstance::patchELFPHDRTable() {
43174319 case ELF::PT_GNU_STACK:
43184320 if (opts::UseGnuStack) {
43194321 // Overwrite the header with the new segment header.
4320- assert (!opts::Instrument);
4321- SmallVector<ELF64LE::Phdr, 3 > NewPhdrs = createNewPhdrs ();
4322- assert (NewPhdrs.size () == 1 &&
4323- " expect exactly one program header was created" );
4324- NewPhdr = NewPhdrs[0 ];
4322+ assert (BC->NewSegments .size () == 1 &&
4323+ " Expected exactly one new segment" );
4324+ NewPhdr = createPhdr (BC->NewSegments .front ());
43254325 ModdedGnuStack = true ;
43264326 }
43274327 break ;
@@ -5946,8 +5946,10 @@ void RewriteInstance::rewriteFile() {
59465946 addBATSection ();
59475947
59485948 // Patch program header table.
5949- if (!BC->IsLinuxKernel )
5949+ if (!BC->IsLinuxKernel ) {
5950+ updateSegmentInfo ();
59505951 patchELFPHDRTable ();
5952+ }
59515953
59525954 // Finalize memory image of section string table.
59535955 finalizeSectionStringTable ();
0 commit comments