@@ -628,6 +628,11 @@ Error RewriteInstance::discoverStorage() {
628
628
unsigned Phnum = Obj.getHeader ().e_phnum ;
629
629
Phnum += 3 ;
630
630
631
+ // Reserve two more pheaders to avoid having writeable and executable
632
+ // segment in instrumented binary.
633
+ if (opts::Instrument)
634
+ Phnum += 2 ;
635
+
631
636
NextAvailableAddress += Phnum * sizeof (ELF64LEPhdrTy);
632
637
NextAvailableOffset += Phnum * sizeof (ELF64LEPhdrTy);
633
638
}
@@ -2083,6 +2088,13 @@ void RewriteInstance::adjustCommandLineOptions() {
2083
2088
opts::HotText = false ;
2084
2089
}
2085
2090
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
+
2086
2098
if (opts::HotText && opts::HotTextMoveSections.getNumOccurrences () == 0 ) {
2087
2099
opts::HotTextMoveSections.addValue (" .stub" );
2088
2100
opts::HotTextMoveSections.addValue (" .mover" );
@@ -3612,11 +3624,13 @@ void RewriteInstance::emitAndLink() {
3612
3624
static_cast <MCObjectStreamer &>(*Streamer).getAssembler ());
3613
3625
}
3614
3626
3615
- if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary ())
3627
+ if (RuntimeLibrary *RtLibrary = BC->getRuntimeLibrary ()) {
3628
+ StartLinkingRuntimeLib = true ;
3616
3629
RtLibrary->link (*BC, ToolPath, *Linker, [this ](auto MapSection) {
3617
3630
// Map newly registered sections.
3618
3631
this ->mapAllocatableSections (MapSection);
3619
3632
});
3633
+ }
3620
3634
3621
3635
// Once the code is emitted, we can rename function sections to actual
3622
3636
// output sections and de-register sections used for emission.
@@ -4011,12 +4025,17 @@ void RewriteInstance::mapAllocatableSections(
4011
4025
Section.setOutputFileOffset (Section.getInputFileOffset ());
4012
4026
MapSection (Section, Section.getAddress ());
4013
4027
} 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
+
4016
4035
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"
4020
4039
<< Twine::utohexstr (NextAvailableAddress +
4021
4040
Section.getOutputSize ())
4022
4041
<< ' \n ' ;
@@ -4079,6 +4098,9 @@ void RewriteInstance::patchELFPHDRTable() {
4079
4098
}
4080
4099
}
4081
4100
4101
+ if (opts::Instrument)
4102
+ Phnum += 2 ;
4103
+
4082
4104
// NOTE Currently .eh_frame_hdr appends to the last segment, recalculate
4083
4105
// last segments size based on the NextAvailableAddress variable.
4084
4106
if (!NewWritableSegmentSize) {
@@ -4093,7 +4115,8 @@ void RewriteInstance::patchELFPHDRTable() {
4093
4115
const uint64_t SavedPos = OS.tell ();
4094
4116
OS.seek (PHDRTableOffset);
4095
4117
4096
- auto createNewTextPhdr = [&]() {
4118
+ auto createNewPhdrs = [&]() {
4119
+ SmallVector<ELF64LEPhdrTy, 3 > NewPhdrs;
4097
4120
ELF64LEPhdrTy NewPhdr;
4098
4121
NewPhdr.p_type = ELF::PT_LOAD;
4099
4122
if (PHDRTableAddress) {
@@ -4108,20 +4131,67 @@ void RewriteInstance::patchELFPHDRTable() {
4108
4131
NewPhdr.p_filesz = NewTextSegmentSize;
4109
4132
NewPhdr.p_memsz = NewTextSegmentSize;
4110
4133
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
- }
4116
4134
NewPhdr.p_align = BC->PageAlign ;
4117
4135
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;
4119
4188
};
4120
4189
4121
4190
auto writeNewSegmentPhdrs = [&]() {
4122
4191
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 ());
4125
4195
}
4126
4196
4127
4197
if (NewWritableSegmentSize) {
@@ -4169,8 +4239,12 @@ void RewriteInstance::patchELFPHDRTable() {
4169
4239
}
4170
4240
case ELF::PT_GNU_STACK:
4171
4241
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 ];
4174
4248
ModdedGnuStack = true ;
4175
4249
}
4176
4250
break ;
0 commit comments