@@ -547,9 +547,14 @@ Error RewriteInstance::discoverStorage() {
547
547
NextAvailableOffset = std::max (NextAvailableOffset,
548
548
Phdr.p_offset + Phdr.p_filesz );
549
549
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 };
553
558
if (BC->TheTriple ->getArch () == llvm::Triple::x86_64 &&
554
559
Phdr.p_vaddr >= BinaryContext::KernelStartX86_64)
555
560
BC->IsLinuxKernel = true ;
@@ -4182,6 +4187,74 @@ void RewriteInstance::updateOutputValues(const BOLTLinker &Linker) {
4182
4187
Function->updateOutputValues (Linker);
4183
4188
}
4184
4189
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
+
4185
4258
void RewriteInstance::patchELFPHDRTable () {
4186
4259
auto ELF64LEFile = cast<ELF64LEObjectFile>(InputFile);
4187
4260
const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile ();
@@ -4208,107 +4281,36 @@ void RewriteInstance::patchELFPHDRTable() {
4208
4281
if (opts::Instrument)
4209
4282
Phnum += 2 ;
4210
4283
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 ()) {
4221
4285
BC->outs () << " BOLT-INFO: not adding new segments\n " ;
4222
4286
return ;
4223
4287
}
4224
4288
4225
4289
const uint64_t SavedPos = OS.tell ();
4226
4290
OS.seek (PHDRTableOffset);
4227
4291
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;
4292
4308
};
4293
4309
4294
4310
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));
4312
4314
}
4313
4315
};
4314
4316
@@ -4344,11 +4346,9 @@ void RewriteInstance::patchELFPHDRTable() {
4344
4346
case ELF::PT_GNU_STACK:
4345
4347
if (opts::UseGnuStack) {
4346
4348
// 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 ());
4352
4352
ModdedGnuStack = true ;
4353
4353
}
4354
4354
break ;
@@ -5973,8 +5973,10 @@ void RewriteInstance::rewriteFile() {
5973
5973
addBATSection ();
5974
5974
5975
5975
// Patch program header table.
5976
- if (!BC->IsLinuxKernel )
5976
+ if (!BC->IsLinuxKernel ) {
5977
+ updateSegmentInfo ();
5977
5978
patchELFPHDRTable ();
5979
+ }
5978
5980
5979
5981
// Finalize memory image of section string table.
5980
5982
finalizeSectionStringTable ();
0 commit comments