@@ -628,6 +628,11 @@ Error RewriteInstance::discoverStorage() {
628628 unsigned Phnum = Obj.getHeader ().e_phnum ;
629629 Phnum += 3 ;
630630
631+ // Reserve two more pheaders to avoid having writeable and executable
632+ // segment in instrumented binary.
633+ if (opts::Instrument)
634+ Phnum += 2 ;
635+
631636 NextAvailableAddress += Phnum * sizeof (ELF64LEPhdrTy);
632637 NextAvailableOffset += Phnum * sizeof (ELF64LEPhdrTy);
633638 }
@@ -2083,6 +2088,13 @@ void RewriteInstance::adjustCommandLineOptions() {
20832088 opts::HotText = false ;
20842089 }
20852090
2091+ if (opts::Instrument && opts::UseGnuStack) {
2092+ BC->errs () << " BOLT-ERROR: cannot avoid having writeable and executable "
2093+ " segment in instrumented binary if program headers will be "
2094+ " updated in place\n " ;
2095+ exit (1 );
2096+ }
2097+
20862098 if (opts::HotText && opts::HotTextMoveSections.getNumOccurrences () == 0 ) {
20872099 opts::HotTextMoveSections.addValue (" .stub" );
20882100 opts::HotTextMoveSections.addValue (" .mover" );
@@ -3612,11 +3624,13 @@ void RewriteInstance::emitAndLink() {
36123624 static_cast <MCObjectStreamer &>(*Streamer).getAssembler ());
36133625 }
36143626
3615- if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary ())
3627+ if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary ()) {
3628+ StartLinkingRuntimeLib = true ;
36163629 RtLibrary->link (*BC, ToolPath, *Linker, [this ](auto MapSection) {
36173630 // Map newly registered sections.
36183631 this ->mapAllocatableSections (MapSection);
36193632 });
3633+ }
36203634
36213635 // Once the code is emitted, we can rename function sections to actual
36223636 // output sections and de-register sections used for emission.
@@ -4011,12 +4025,17 @@ void RewriteInstance::mapAllocatableSections(
40114025 Section.setOutputFileOffset (Section.getInputFileOffset ());
40124026 MapSection (Section, Section.getAddress ());
40134027 } else {
4014- NextAvailableAddress =
4015- alignTo (NextAvailableAddress, Section.getAlignment ());
4028+ uint64_t Alignment = Section.getAlignment ();
4029+ if (opts::Instrument && StartLinkingRuntimeLib) {
4030+ Alignment = BC->RegularPageSize ;
4031+ StartLinkingRuntimeLib = false ;
4032+ }
4033+ NextAvailableAddress = alignTo (NextAvailableAddress, Alignment);
4034+
40164035 LLVM_DEBUG ({
4017- dbgs () << " BOLT: mapping section " << Section.getName () << " (0x "
4018- << Twine::utohexstr (Section.getAllocAddress ()) << " ) to 0x "
4019- << Twine::utohexstr (NextAvailableAddress) << " :0x"
4036+ dbgs () << " BOLT-DEBUG : mapping section " << Section.getName ()
4037+ << " (0x " << Twine::utohexstr (Section.getAllocAddress ())
4038+ << " ) to 0x " << Twine::utohexstr (NextAvailableAddress) << " :0x"
40204039 << Twine::utohexstr (NextAvailableAddress +
40214040 Section.getOutputSize ())
40224041 << ' \n ' ;
@@ -4079,6 +4098,9 @@ void RewriteInstance::patchELFPHDRTable() {
40794098 }
40804099 }
40814100
4101+ if (opts::Instrument)
4102+ Phnum += 2 ;
4103+
40824104 // NOTE Currently .eh_frame_hdr appends to the last segment, recalculate
40834105 // last segments size based on the NextAvailableAddress variable.
40844106 if (!NewWritableSegmentSize) {
@@ -4093,7 +4115,8 @@ void RewriteInstance::patchELFPHDRTable() {
40934115 const uint64_t SavedPos = OS.tell ();
40944116 OS.seek (PHDRTableOffset);
40954117
4096- auto createNewTextPhdr = [&]() {
4118+ auto createNewPhdrs = [&]() {
4119+ SmallVector<ELF64LEPhdrTy, 3 > NewPhdrs;
40974120 ELF64LEPhdrTy NewPhdr;
40984121 NewPhdr.p_type = ELF::PT_LOAD;
40994122 if (PHDRTableAddress) {
@@ -4108,20 +4131,67 @@ void RewriteInstance::patchELFPHDRTable() {
41084131 NewPhdr.p_filesz = NewTextSegmentSize;
41094132 NewPhdr.p_memsz = NewTextSegmentSize;
41104133 NewPhdr.p_flags = ELF::PF_X | ELF::PF_R;
4111- if (opts::Instrument) {
4112- // FIXME: Currently instrumentation is experimental and the runtime data
4113- // is emitted with code, thus everything needs to be writable.
4114- NewPhdr.p_flags |= ELF::PF_W;
4115- }
41164134 NewPhdr.p_align = BC->PageAlign ;
41174135
4118- return NewPhdr;
4136+ if (!opts::Instrument) {
4137+ NewPhdrs.push_back (NewPhdr);
4138+ } else {
4139+ ErrorOr<BinarySection &> Sec =
4140+ BC->getUniqueSectionByName (" .bolt.instr.counters" );
4141+ assert (Sec && " expected one and only one `.bolt.instr.counters` section" );
4142+ const uint64_t Addr = Sec->getOutputAddress ();
4143+ const uint64_t Offset = Sec->getOutputFileOffset ();
4144+ const uint64_t Size = Sec->getOutputSize ();
4145+ assert (Addr > NewPhdr.p_vaddr &&
4146+ Addr + Size < NewPhdr.p_vaddr + NewPhdr.p_memsz &&
4147+ " `.bolt.instr.counters` section is expected to be included in the "
4148+ " new text sgement" );
4149+
4150+ // Set correct size for the previous header since we are breaking the
4151+ // new text segment into three segments.
4152+ uint64_t Delta = Addr - NewPhdr.p_vaddr ;
4153+ NewPhdr.p_filesz = Delta;
4154+ NewPhdr.p_memsz = Delta;
4155+ NewPhdrs.push_back (NewPhdr);
4156+
4157+ // Create a program header for a RW segment that includes the
4158+ // `.bolt.instr.counters` section only.
4159+ ELF64LEPhdrTy NewPhdrRWSegment;
4160+ NewPhdrRWSegment.p_type = ELF::PT_LOAD;
4161+ NewPhdrRWSegment.p_offset = Offset;
4162+ NewPhdrRWSegment.p_vaddr = Addr;
4163+ NewPhdrRWSegment.p_paddr = Addr;
4164+ NewPhdrRWSegment.p_filesz = Size;
4165+ NewPhdrRWSegment.p_memsz = Size;
4166+ NewPhdrRWSegment.p_flags = ELF::PF_R | ELF::PF_W;
4167+ NewPhdrRWSegment.p_align = BC->RegularPageSize ;
4168+ NewPhdrs.push_back (NewPhdrRWSegment);
4169+
4170+ // Create a program header for a RX segment that includes all the RX
4171+ // sections from runtime library.
4172+ ELF64LEPhdrTy NewPhdrRXSegment;
4173+ NewPhdrRXSegment.p_type = ELF::PT_LOAD;
4174+ const uint64_t AddrRX = alignTo (Addr + Size, BC->RegularPageSize );
4175+ const uint64_t OffsetRX = alignTo (Offset + Size, BC->RegularPageSize );
4176+ const uint64_t SizeRX = NewTextSegmentSize - (AddrRX - NewPhdr.p_paddr );
4177+ NewPhdrRXSegment.p_offset = OffsetRX;
4178+ NewPhdrRXSegment.p_vaddr = AddrRX;
4179+ NewPhdrRXSegment.p_paddr = AddrRX;
4180+ NewPhdrRXSegment.p_filesz = SizeRX;
4181+ NewPhdrRXSegment.p_memsz = SizeRX;
4182+ NewPhdrRXSegment.p_flags = ELF::PF_X | ELF::PF_R;
4183+ NewPhdrRXSegment.p_align = BC->RegularPageSize ;
4184+ NewPhdrs.push_back (NewPhdrRXSegment);
4185+ }
4186+
4187+ return NewPhdrs;
41194188 };
41204189
41214190 auto writeNewSegmentPhdrs = [&]() {
41224191 if (PHDRTableAddress || NewTextSegmentSize) {
4123- ELF64LE::Phdr NewPhdr = createNewTextPhdr ();
4124- OS.write (reinterpret_cast <const char *>(&NewPhdr), sizeof (NewPhdr));
4192+ SmallVector<ELF64LE::Phdr, 3 > NewPhdrs = createNewPhdrs ();
4193+ OS.write (reinterpret_cast <const char *>(NewPhdrs.data ()),
4194+ sizeof (ELF64LE::Phdr) * NewPhdrs.size ());
41254195 }
41264196
41274197 if (NewWritableSegmentSize) {
@@ -4169,8 +4239,12 @@ void RewriteInstance::patchELFPHDRTable() {
41694239 }
41704240 case ELF::PT_GNU_STACK:
41714241 if (opts::UseGnuStack) {
4172- // Overwrite the header with the new text segment header.
4173- NewPhdr = createNewTextPhdr ();
4242+ // Overwrite the header with the new segment header.
4243+ assert (!opts::Instrument);
4244+ SmallVector<ELF64LE::Phdr, 3 > NewPhdrs = createNewPhdrs ();
4245+ assert (NewPhdrs.size () == 1 &&
4246+ " expect exactly one program header was created" );
4247+ NewPhdr = NewPhdrs[0 ];
41744248 ModdedGnuStack = true ;
41754249 }
41764250 break ;
0 commit comments