@@ -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 ;
@@ -4182,6 +4187,74 @@ void RewriteInstance::updateOutputValues(const BOLTLinker &Linker) {
41824187 Function->updateOutputValues (Linker);
41834188}
41844189
4190+ void RewriteInstance::updateSegmentInfo () {
4191+ // NOTE Currently .eh_frame_hdr appends to the last segment, recalculate
4192+ // last segments size based on the NextAvailableAddress variable.
4193+ if (!NewWritableSegmentSize) {
4194+ if (NewTextSegmentAddress)
4195+ NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress;
4196+ } else {
4197+ NewWritableSegmentSize = NextAvailableAddress - NewWritableSegmentAddress;
4198+ }
4199+
4200+ if (NewTextSegmentSize) {
4201+ SegmentInfo TextSegment = {NewTextSegmentAddress,
4202+ NewTextSegmentSize,
4203+ NewTextSegmentOffset,
4204+ NewTextSegmentSize,
4205+ BC->PageAlign ,
4206+ true ,
4207+ false };
4208+ if (!opts::Instrument) {
4209+ BC->NewSegments .push_back (TextSegment);
4210+ } else {
4211+ ErrorOr<BinarySection &> Sec =
4212+ BC->getUniqueSectionByName (" .bolt.instr.counters" );
4213+ assert (Sec && " expected one and only one `.bolt.instr.counters` section" );
4214+ const uint64_t Addr = Sec->getOutputAddress ();
4215+ const uint64_t Offset = Sec->getOutputFileOffset ();
4216+ const uint64_t Size = Sec->getOutputSize ();
4217+ assert (Addr > TextSegment.Address &&
4218+ Addr + Size < TextSegment.Address + TextSegment.Size &&
4219+ " `.bolt.instr.counters` section is expected to be included in the "
4220+ " new text segment" );
4221+
4222+ // Set correct size for the previous header since we are breaking the
4223+ // new text segment into three segments.
4224+ uint64_t Delta = Addr - TextSegment.Address ;
4225+ TextSegment.Size = Delta;
4226+ TextSegment.FileSize = Delta;
4227+ BC->NewSegments .push_back (TextSegment);
4228+
4229+ // Create RW segment that includes the `.bolt.instr.counters` section.
4230+ SegmentInfo RWSegment = {Addr, Size, Offset, Size, BC->RegularPageSize ,
4231+ false , true };
4232+ BC->NewSegments .push_back (RWSegment);
4233+
4234+ // Create RX segment that includes all RX sections from runtime library.
4235+ const uint64_t AddrRX = alignTo (Addr + Size, BC->RegularPageSize );
4236+ const uint64_t OffsetRX = alignTo (Offset + Size, BC->RegularPageSize );
4237+ const uint64_t SizeRX =
4238+ NewTextSegmentSize - (AddrRX - TextSegment.Address );
4239+ SegmentInfo RXSegment = {
4240+ AddrRX, SizeRX, OffsetRX, SizeRX, BC->RegularPageSize , true , false };
4241+ BC->NewSegments .push_back (RXSegment);
4242+ }
4243+ }
4244+
4245+ if (NewWritableSegmentSize) {
4246+ SegmentInfo DataSegmentInfo = {
4247+ NewWritableSegmentAddress,
4248+ NewWritableSegmentSize,
4249+ getFileOffsetForAddress (NewWritableSegmentAddress),
4250+ NewWritableSegmentSize,
4251+ BC->RegularPageSize ,
4252+ false ,
4253+ true };
4254+ BC->NewSegments .push_back (DataSegmentInfo);
4255+ }
4256+ }
4257+
41854258void RewriteInstance::patchELFPHDRTable () {
41864259 auto ELF64LEFile = cast<ELF64LEObjectFile>(InputFile);
41874260 const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile ();
@@ -4208,107 +4281,36 @@ void RewriteInstance::patchELFPHDRTable() {
42084281 if (opts::Instrument)
42094282 Phnum += 2 ;
42104283
4211- // NOTE Currently .eh_frame_hdr appends to the last segment, recalculate
4212- // last segments size based on the NextAvailableAddress variable.
4213- if (!NewWritableSegmentSize) {
4214- if (NewTextSegmentAddress)
4215- NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress;
4216- } else {
4217- NewWritableSegmentSize = NextAvailableAddress - NewWritableSegmentAddress;
4218- }
4219-
4220- if (!NewTextSegmentSize && !NewWritableSegmentSize) {
4284+ if (BC->NewSegments .empty ()) {
42214285 BC->outs () << " BOLT-INFO: not adding new segments\n " ;
42224286 return ;
42234287 }
42244288
42254289 const uint64_t SavedPos = OS.tell ();
42264290 OS.seek (PHDRTableOffset);
42274291
4228- auto createNewPhdrs = [&]() {
4229- SmallVector<ELF64LEPhdrTy, 3 > NewPhdrs;
4230- ELF64LEPhdrTy NewPhdr;
4231- NewPhdr.p_type = ELF::PT_LOAD;
4232- NewPhdr.p_offset = NewTextSegmentOffset;
4233- NewPhdr.p_vaddr = NewTextSegmentAddress;
4234- NewPhdr.p_paddr = NewTextSegmentAddress;
4235- NewPhdr.p_filesz = NewTextSegmentSize;
4236- NewPhdr.p_memsz = NewTextSegmentSize;
4237- NewPhdr.p_flags = ELF::PF_X | ELF::PF_R;
4238- NewPhdr.p_align = BC->PageAlign ;
4239-
4240- if (!opts::Instrument) {
4241- NewPhdrs.push_back (NewPhdr);
4242- } else {
4243- ErrorOr<BinarySection &> Sec =
4244- BC->getUniqueSectionByName (" .bolt.instr.counters" );
4245- assert (Sec && " expected one and only one `.bolt.instr.counters` section" );
4246- const uint64_t Addr = Sec->getOutputAddress ();
4247- const uint64_t Offset = Sec->getOutputFileOffset ();
4248- const uint64_t Size = Sec->getOutputSize ();
4249- assert (Addr > NewPhdr.p_vaddr &&
4250- Addr + Size < NewPhdr.p_vaddr + NewPhdr.p_memsz &&
4251- " `.bolt.instr.counters` section is expected to be included in the "
4252- " new text sgement" );
4253-
4254- // Set correct size for the previous header since we are breaking the
4255- // new text segment into three segments.
4256- uint64_t Delta = Addr - NewPhdr.p_vaddr ;
4257- NewPhdr.p_filesz = Delta;
4258- NewPhdr.p_memsz = Delta;
4259- NewPhdrs.push_back (NewPhdr);
4260-
4261- // Create a program header for a RW segment that includes the
4262- // `.bolt.instr.counters` section only.
4263- ELF64LEPhdrTy NewPhdrRWSegment;
4264- NewPhdrRWSegment.p_type = ELF::PT_LOAD;
4265- NewPhdrRWSegment.p_offset = Offset;
4266- NewPhdrRWSegment.p_vaddr = Addr;
4267- NewPhdrRWSegment.p_paddr = Addr;
4268- NewPhdrRWSegment.p_filesz = Size;
4269- NewPhdrRWSegment.p_memsz = Size;
4270- NewPhdrRWSegment.p_flags = ELF::PF_R | ELF::PF_W;
4271- NewPhdrRWSegment.p_align = BC->RegularPageSize ;
4272- NewPhdrs.push_back (NewPhdrRWSegment);
4273-
4274- // Create a program header for a RX segment that includes all the RX
4275- // sections from runtime library.
4276- ELF64LEPhdrTy NewPhdrRXSegment;
4277- NewPhdrRXSegment.p_type = ELF::PT_LOAD;
4278- const uint64_t AddrRX = alignTo (Addr + Size, BC->RegularPageSize );
4279- const uint64_t OffsetRX = alignTo (Offset + Size, BC->RegularPageSize );
4280- const uint64_t SizeRX = NewTextSegmentSize - (AddrRX - NewPhdr.p_paddr );
4281- NewPhdrRXSegment.p_offset = OffsetRX;
4282- NewPhdrRXSegment.p_vaddr = AddrRX;
4283- NewPhdrRXSegment.p_paddr = AddrRX;
4284- NewPhdrRXSegment.p_filesz = SizeRX;
4285- NewPhdrRXSegment.p_memsz = SizeRX;
4286- NewPhdrRXSegment.p_flags = ELF::PF_X | ELF::PF_R;
4287- NewPhdrRXSegment.p_align = BC->RegularPageSize ;
4288- NewPhdrs.push_back (NewPhdrRXSegment);
4289- }
4290-
4291- return NewPhdrs;
4292+ auto createPhdr = [](const SegmentInfo &SI) {
4293+ ELF64LEPhdrTy Phdr;
4294+ Phdr.p_type = ELF::PT_LOAD;
4295+ Phdr.p_offset = SI.FileOffset ;
4296+ Phdr.p_vaddr = SI.Address ;
4297+ Phdr.p_paddr = SI.Address ;
4298+ Phdr.p_filesz = SI.FileSize ;
4299+ Phdr.p_memsz = SI.Size ;
4300+ Phdr.p_flags = ELF::PF_R;
4301+ if (SI.IsExecutable )
4302+ Phdr.p_flags |= ELF::PF_X;
4303+ if (SI.IsWritable )
4304+ Phdr.p_flags |= ELF::PF_W;
4305+ Phdr.p_align = SI.Alignment ;
4306+
4307+ return Phdr;
42924308 };
42934309
42944310 auto writeNewSegmentPhdrs = [&]() {
4295- if (NewTextSegmentSize) {
4296- SmallVector<ELF64LE::Phdr, 3 > NewPhdrs = createNewPhdrs ();
4297- OS.write (reinterpret_cast <const char *>(NewPhdrs.data ()),
4298- sizeof (ELF64LE::Phdr) * NewPhdrs.size ());
4299- }
4300-
4301- if (NewWritableSegmentSize) {
4302- ELF64LEPhdrTy NewPhdr;
4303- NewPhdr.p_type = ELF::PT_LOAD;
4304- NewPhdr.p_offset = getFileOffsetForAddress (NewWritableSegmentAddress);
4305- NewPhdr.p_vaddr = NewWritableSegmentAddress;
4306- NewPhdr.p_paddr = NewWritableSegmentAddress;
4307- NewPhdr.p_filesz = NewWritableSegmentSize;
4308- NewPhdr.p_memsz = NewWritableSegmentSize;
4309- NewPhdr.p_align = BC->RegularPageSize ;
4310- NewPhdr.p_flags = ELF::PF_R | ELF::PF_W;
4311- OS.write (reinterpret_cast <const char *>(&NewPhdr), sizeof (NewPhdr));
4311+ for (const SegmentInfo &SI : BC->NewSegments ) {
4312+ ELF64LEPhdrTy Phdr = createPhdr (SI);
4313+ OS.write (reinterpret_cast <const char *>(&Phdr), sizeof (Phdr));
43124314 }
43134315 };
43144316
@@ -4344,11 +4346,9 @@ void RewriteInstance::patchELFPHDRTable() {
43444346 case ELF::PT_GNU_STACK:
43454347 if (opts::UseGnuStack) {
43464348 // Overwrite the header with the new segment header.
4347- assert (!opts::Instrument);
4348- SmallVector<ELF64LE::Phdr, 3 > NewPhdrs = createNewPhdrs ();
4349- assert (NewPhdrs.size () == 1 &&
4350- " expect exactly one program header was created" );
4351- NewPhdr = NewPhdrs[0 ];
4349+ assert (BC->NewSegments .size () == 1 &&
4350+ " Expected exactly one new segment" );
4351+ NewPhdr = createPhdr (BC->NewSegments .front ());
43524352 ModdedGnuStack = true ;
43534353 }
43544354 break ;
@@ -5973,8 +5973,10 @@ void RewriteInstance::rewriteFile() {
59735973 addBATSection ();
59745974
59755975 // Patch program header table.
5976- if (!BC->IsLinuxKernel )
5976+ if (!BC->IsLinuxKernel ) {
5977+ updateSegmentInfo ();
59775978 patchELFPHDRTable ();
5979+ }
59785980
59795981 // Finalize memory image of section string table.
59805982 finalizeSectionStringTable ();
0 commit comments