33
33
#include " llvm/Object/Decompressor.h"
34
34
#include " llvm/Object/ELFObjectFile.h"
35
35
#include " llvm/Support/Endian.h"
36
+ #include " llvm/Support/LEB128.h"
36
37
#include " llvm/Support/MD5.h"
37
38
#include " llvm/Support/RandomNumberGenerator.h"
38
39
#include " llvm/Support/SHA1.h"
@@ -817,7 +818,7 @@ unsigned MipsGotSection::getLocalEntriesNum() const {
817
818
818
819
void MipsGotSection::finalizeContents () { updateAllocSize (); }
819
820
820
- void MipsGotSection::updateAllocSize () {
821
+ bool MipsGotSection::updateAllocSize () {
821
822
PageEntriesNum = 0 ;
822
823
for (std::pair<const OutputSection *, size_t > &P : PageIndexMap) {
823
824
// For each output section referenced by GOT page relocations calculate
@@ -831,6 +832,7 @@ void MipsGotSection::updateAllocSize() {
831
832
}
832
833
Size = (getLocalEntriesNum () + GlobalEntries.size () + TlsEntries.size ()) *
833
834
Config->Wordsize ;
835
+ return false ;
834
836
}
835
837
836
838
bool MipsGotSection::empty () const {
@@ -1063,10 +1065,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
1063
1065
1064
1066
this ->Link = InX::DynStrTab->getParent ()->SectionIndex ;
1065
1067
if (In<ELFT>::RelaDyn->getParent () && !In<ELFT>::RelaDyn->empty ()) {
1066
- bool IsRela = Config->IsRela ;
1067
- add ({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
1068
- add ({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent (),
1068
+ add ({In<ELFT>::RelaDyn->DynamicTag , In<ELFT>::RelaDyn});
1069
+ add ({In<ELFT>::RelaDyn->SizeDynamicTag , In<ELFT>::RelaDyn->getParent (),
1069
1070
Entry::SecSize});
1071
+
1072
+ bool IsRela = Config->IsRela ;
1070
1073
add ({IsRela ? DT_RELAENT : DT_RELENT,
1071
1074
uint64_t (IsRela ? sizeof (Elf_Rela) : sizeof (Elf_Rel))});
1072
1075
@@ -1202,21 +1205,57 @@ uint32_t DynamicReloc::getSymIndex() const {
1202
1205
return 0 ;
1203
1206
}
1204
1207
1205
- template <class ELFT >
1206
- RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
1207
- : SyntheticSection(SHF_ALLOC, Config->IsRela ? SHT_RELA : SHT_REL,
1208
- Config->Wordsize, Name),
1209
- Sort (Sort) {
1210
- this ->Entsize = Config->IsRela ? sizeof (Elf_Rela) : sizeof (Elf_Rel);
1211
- }
1208
+ RelocationBaseSection::RelocationBaseSection (StringRef Name, uint32_t Type,
1209
+ int32_t DynamicTag,
1210
+ int32_t SizeDynamicTag)
1211
+ : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name),
1212
+ DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {}
1212
1213
1213
- template <class ELFT >
1214
- void RelocationSection<ELFT>::addReloc(const DynamicReloc &Reloc) {
1214
+ void RelocationBaseSection::addReloc (const DynamicReloc &Reloc) {
1215
1215
if (Reloc.Type == Target->RelativeRel )
1216
1216
++NumRelativeRelocs;
1217
1217
Relocs.push_back (Reloc);
1218
1218
}
1219
1219
1220
+ void RelocationBaseSection::finalizeContents () {
1221
+ // If all relocations are R_*_RELATIVE they don't refer to any
1222
+ // dynamic symbol and we don't need a dynamic symbol table. If that
1223
+ // is the case, just use 0 as the link.
1224
+ this ->Link = InX::DynSymTab ? InX::DynSymTab->getParent ()->SectionIndex : 0 ;
1225
+
1226
+ // Set required output section properties.
1227
+ getParent ()->Link = this ->Link ;
1228
+ }
1229
+
1230
+ template <class ELFT >
1231
+ static void encodeDynamicReloc (typename ELFT::Rela *P,
1232
+ const DynamicReloc &Rel) {
1233
+ if (Config->IsRela )
1234
+ P->r_addend = Rel.getAddend ();
1235
+ P->r_offset = Rel.getOffset ();
1236
+ if (Config->EMachine == EM_MIPS && Rel.getInputSec () == InX::MipsGot)
1237
+ // The MIPS GOT section contains dynamic relocations that correspond to TLS
1238
+ // entries. These entries are placed after the global and local sections of
1239
+ // the GOT. At the point when we create these relocations, the size of the
1240
+ // global and local sections is unknown, so the offset that we store in the
1241
+ // TLS entry's DynamicReloc is relative to the start of the TLS section of
1242
+ // the GOT, rather than being relative to the start of the GOT. This line of
1243
+ // code adds the size of the global and local sections to the virtual
1244
+ // address computed by getOffset() in order to adjust it into the TLS
1245
+ // section.
1246
+ P->r_offset += InX::MipsGot->getTlsOffset ();
1247
+ P->setSymbolAndType (Rel.getSymIndex (), Rel.Type , Config->IsMips64EL );
1248
+ }
1249
+
1250
+ template <class ELFT >
1251
+ RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort)
1252
+ : RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL,
1253
+ Config->IsRela ? DT_RELA : DT_REL,
1254
+ Config->IsRela ? DT_RELASZ : DT_RELSZ),
1255
+ Sort (Sort) {
1256
+ this ->Entsize = Config->IsRela ? sizeof (Elf_Rela) : sizeof (Elf_Rel);
1257
+ }
1258
+
1220
1259
template <class ELFT , class RelTy >
1221
1260
static bool compRelocations (const RelTy &A, const RelTy &B) {
1222
1261
bool AIsRel = A.getType (Config->IsMips64EL ) == Target->RelativeRel ;
@@ -1230,18 +1269,8 @@ static bool compRelocations(const RelTy &A, const RelTy &B) {
1230
1269
template <class ELFT > void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
1231
1270
uint8_t *BufBegin = Buf;
1232
1271
for (const DynamicReloc &Rel : Relocs) {
1233
- auto *P = reinterpret_cast <Elf_Rela *>(Buf);
1272
+ encodeDynamicReloc<ELFT>( reinterpret_cast <Elf_Rela *>(Buf), Rel );
1234
1273
Buf += Config->IsRela ? sizeof (Elf_Rela) : sizeof (Elf_Rel);
1235
-
1236
- if (Config->IsRela )
1237
- P->r_addend = Rel.getAddend ();
1238
- P->r_offset = Rel.getOffset ();
1239
- if (Config->EMachine == EM_MIPS && Rel.getInputSec () == InX::MipsGot)
1240
- // Dynamic relocation against MIPS GOT section make deal TLS entries
1241
- // allocated in the end of the GOT. We need to adjust the offset to take
1242
- // in account 'local' and 'global' GOT entries.
1243
- P->r_offset += InX::MipsGot->getTlsOffset ();
1244
- P->setSymbolAndType (Rel.getSymIndex (), Rel.Type , Config->IsMips64EL );
1245
1274
}
1246
1275
1247
1276
if (Sort) {
@@ -1259,14 +1288,193 @@ template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
1259
1288
return this ->Entsize * Relocs.size ();
1260
1289
}
1261
1290
1262
- template <class ELFT > void RelocationSection<ELFT>::finalizeContents() {
1263
- // If all relocations are *RELATIVE they don't refer to any
1264
- // dynamic symbol and we don't need a dynamic symbol table. If that
1265
- // is the case, just use 0 as the link.
1266
- this ->Link = InX::DynSymTab ? InX::DynSymTab->getParent ()->SectionIndex : 0 ;
1291
+ template <class ELFT >
1292
+ AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection(
1293
+ StringRef Name)
1294
+ : RelocationBaseSection(
1295
+ Name, Config->IsRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL,
1296
+ Config->IsRela ? DT_ANDROID_RELA : DT_ANDROID_REL,
1297
+ Config->IsRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) {
1298
+ this ->Entsize = 1 ;
1299
+ }
1267
1300
1268
- // Set required output section properties.
1269
- getParent ()->Link = this ->Link ;
1301
+ template <class ELFT >
1302
+ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
1303
+ // This function computes the contents of an Android-format packed relocation
1304
+ // section.
1305
+ //
1306
+ // This format compresses relocations by using relocation groups to factor out
1307
+ // fields that are common between relocations and storing deltas from previous
1308
+ // relocations in SLEB128 format (which has a short representation for small
1309
+ // numbers). A good example of a relocation type with common fields is
1310
+ // R_*_RELATIVE, which is normally used to represent function pointers in
1311
+ // vtables. In the REL format, each relative relocation has the same r_info
1312
+ // field, and is only different from other relative relocations in terms of
1313
+ // the r_offset field. By sorting relocations by offset, grouping them by
1314
+ // r_info and representing each relocation with only the delta from the
1315
+ // previous offset, each 8-byte relocation can be compressed to as little as 1
1316
+ // byte (or less with run-length encoding). This relocation packer was able to
1317
+ // reduce the size of the relocation section in an Android Chromium DSO from
1318
+ // 2,911,184 bytes to 174,693 bytes, or 6% of the original size.
1319
+ //
1320
+ // A relocation section consists of a header containing the literal bytes
1321
+ // 'APS2' followed by a sequence of SLEB128-encoded integers. The first two
1322
+ // elements are the total number of relocations in the section and an initial
1323
+ // r_offset value. The remaining elements define a sequence of relocation
1324
+ // groups. Each relocation group starts with a header consisting of the
1325
+ // following elements:
1326
+ //
1327
+ // - the number of relocations in the relocation group
1328
+ // - flags for the relocation group
1329
+ // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is set) the r_offset delta
1330
+ // for each relocation in the group.
1331
+ // - (if RELOCATION_GROUPED_BY_INFO_FLAG is set) the value of the r_info
1332
+ // field for each relocation in the group.
1333
+ // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG and
1334
+ // RELOCATION_GROUPED_BY_ADDEND_FLAG are set) the r_addend delta for
1335
+ // each relocation in the group.
1336
+ //
1337
+ // Following the relocation group header are descriptions of each of the
1338
+ // relocations in the group. They consist of the following elements:
1339
+ //
1340
+ // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is not set) the r_offset
1341
+ // delta for this relocation.
1342
+ // - (if RELOCATION_GROUPED_BY_INFO_FLAG is not set) the value of the r_info
1343
+ // field for this relocation.
1344
+ // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG is set and
1345
+ // RELOCATION_GROUPED_BY_ADDEND_FLAG is not set) the r_addend delta for
1346
+ // this relocation.
1347
+
1348
+ size_t OldSize = RelocData.size ();
1349
+
1350
+ RelocData = {' A' , ' P' , ' S' , ' 2' };
1351
+ raw_svector_ostream OS (RelocData);
1352
+
1353
+ // The format header includes the number of relocations and the initial
1354
+ // offset (we set this to zero because the first relocation group will
1355
+ // perform the initial adjustment).
1356
+ encodeSLEB128 (Relocs.size (), OS);
1357
+ encodeSLEB128 (0 , OS);
1358
+
1359
+ std::vector<Elf_Rela> Relatives, NonRelatives;
1360
+
1361
+ for (const DynamicReloc &Rel : Relocs) {
1362
+ Elf_Rela R;
1363
+ encodeDynamicReloc<ELFT>(&R, Rel);
1364
+
1365
+ if (R.getType (Config->IsMips64EL ) == Target->RelativeRel )
1366
+ Relatives.push_back (R);
1367
+ else
1368
+ NonRelatives.push_back (R);
1369
+ }
1370
+
1371
+ std::sort (Relatives.begin (), Relatives.end (),
1372
+ [](const Elf_Rel &A, const Elf_Rel &B) {
1373
+ return A.r_offset < B.r_offset ;
1374
+ });
1375
+
1376
+ // Try to find groups of relative relocations which are spaced one word
1377
+ // apart from one another. These generally correspond to vtable entries. The
1378
+ // format allows these groups to be encoded using a sort of run-length
1379
+ // encoding, but each group will cost 7 bytes in addition to the offset from
1380
+ // the previous group, so it is only profitable to do this for groups of
1381
+ // size 8 or larger.
1382
+ std::vector<Elf_Rela> UngroupedRelatives;
1383
+ std::vector<std::vector<Elf_Rela>> RelativeGroups;
1384
+ for (auto I = Relatives.begin (), E = Relatives.end (); I != E;) {
1385
+ std::vector<Elf_Rela> Group;
1386
+ do {
1387
+ Group.push_back (*I++);
1388
+ } while (I != E && (I - 1 )->r_offset + Config->Wordsize == I->r_offset );
1389
+
1390
+ if (Group.size () < 8 )
1391
+ UngroupedRelatives.insert (UngroupedRelatives.end (), Group.begin (),
1392
+ Group.end ());
1393
+ else
1394
+ RelativeGroups.emplace_back (std::move (Group));
1395
+ }
1396
+
1397
+ unsigned HasAddendIfRela =
1398
+ Config->IsRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0 ;
1399
+
1400
+ uint64_t Offset = 0 ;
1401
+ uint64_t Addend = 0 ;
1402
+
1403
+ // Emit the run-length encoding for the groups of adjacent relative
1404
+ // relocations. Each group is represented using two groups in the packed
1405
+ // format. The first is used to set the current offset to the start of the
1406
+ // group (and also encodes the first relocation), and the second encodes the
1407
+ // remaining relocations.
1408
+ for (std::vector<Elf_Rela> &G : RelativeGroups) {
1409
+ // The first relocation in the group.
1410
+ encodeSLEB128 (1 , OS);
1411
+ encodeSLEB128 (RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG |
1412
+ RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela,
1413
+ OS);
1414
+ encodeSLEB128 (G[0 ].r_offset - Offset, OS);
1415
+ encodeSLEB128 (Target->RelativeRel , OS);
1416
+ if (Config->IsRela ) {
1417
+ encodeSLEB128 (G[0 ].r_addend - Addend, OS);
1418
+ Addend = G[0 ].r_addend ;
1419
+ }
1420
+
1421
+ // The remaining relocations.
1422
+ encodeSLEB128 (G.size () - 1 , OS);
1423
+ encodeSLEB128 (RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG |
1424
+ RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela,
1425
+ OS);
1426
+ encodeSLEB128 (Config->Wordsize , OS);
1427
+ encodeSLEB128 (Target->RelativeRel , OS);
1428
+ if (Config->IsRela ) {
1429
+ for (auto I = G.begin () + 1 , E = G.end (); I != E; ++I) {
1430
+ encodeSLEB128 (I->r_addend - Addend, OS);
1431
+ Addend = I->r_addend ;
1432
+ }
1433
+ }
1434
+
1435
+ Offset = G.back ().r_offset ;
1436
+ }
1437
+
1438
+ // Now the ungrouped relatives.
1439
+ if (!UngroupedRelatives.empty ()) {
1440
+ encodeSLEB128 (UngroupedRelatives.size (), OS);
1441
+ encodeSLEB128 (RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela, OS);
1442
+ encodeSLEB128 (Target->RelativeRel , OS);
1443
+ for (Elf_Rela &R : UngroupedRelatives) {
1444
+ encodeSLEB128 (R.r_offset - Offset, OS);
1445
+ Offset = R.r_offset ;
1446
+ if (Config->IsRela ) {
1447
+ encodeSLEB128 (R.r_addend - Addend, OS);
1448
+ Addend = R.r_addend ;
1449
+ }
1450
+ }
1451
+ }
1452
+
1453
+ // Finally the non-relative relocations.
1454
+ std::sort (NonRelatives.begin (), NonRelatives.end (),
1455
+ [](const Elf_Rela &A, const Elf_Rela &B) {
1456
+ return A.r_offset < B.r_offset ;
1457
+ });
1458
+ if (!NonRelatives.empty ()) {
1459
+ encodeSLEB128 (NonRelatives.size (), OS);
1460
+ encodeSLEB128 (HasAddendIfRela, OS);
1461
+ for (Elf_Rela &R : NonRelatives) {
1462
+ encodeSLEB128 (R.r_offset - Offset, OS);
1463
+ Offset = R.r_offset ;
1464
+ encodeSLEB128 (R.r_info , OS);
1465
+ if (Config->IsRela ) {
1466
+ encodeSLEB128 (R.r_addend - Addend, OS);
1467
+ Addend = R.r_addend ;
1468
+ }
1469
+ }
1470
+ }
1471
+
1472
+ // Returns whether the section size changed. We need to keep recomputing both
1473
+ // section layout and the contents of this section until the size converges
1474
+ // because changing this section's size can affect section layout, which in
1475
+ // turn can affect the sizes of the LEB-encoded integers stored in this
1476
+ // section.
1477
+ return RelocData.size () != OldSize;
1270
1478
}
1271
1479
1272
1480
SymbolTableBaseSection::SymbolTableBaseSection (StringTableSection &StrTabSec)
@@ -2471,6 +2679,11 @@ template class elf::RelocationSection<ELF32BE>;
2471
2679
template class elf ::RelocationSection<ELF64LE>;
2472
2680
template class elf ::RelocationSection<ELF64BE>;
2473
2681
2682
+ template class elf ::AndroidPackedRelocationSection<ELF32LE>;
2683
+ template class elf ::AndroidPackedRelocationSection<ELF32BE>;
2684
+ template class elf ::AndroidPackedRelocationSection<ELF64LE>;
2685
+ template class elf ::AndroidPackedRelocationSection<ELF64BE>;
2686
+
2474
2687
template class elf ::SymbolTableSection<ELF32LE>;
2475
2688
template class elf ::SymbolTableSection<ELF32BE>;
2476
2689
template class elf ::SymbolTableSection<ELF64LE>;
0 commit comments