3333#include " llvm/Object/Decompressor.h"
3434#include " llvm/Object/ELFObjectFile.h"
3535#include " llvm/Support/Endian.h"
36+ #include " llvm/Support/LEB128.h"
3637#include " llvm/Support/MD5.h"
3738#include " llvm/Support/RandomNumberGenerator.h"
3839#include " llvm/Support/SHA1.h"
@@ -817,7 +818,7 @@ unsigned MipsGotSection::getLocalEntriesNum() const {
817818
818819void MipsGotSection::finalizeContents () { updateAllocSize (); }
819820
820- void MipsGotSection::updateAllocSize () {
821+ bool MipsGotSection::updateAllocSize () {
821822 PageEntriesNum = 0 ;
822823 for (std::pair<const OutputSection *, size_t > &P : PageIndexMap) {
823824 // For each output section referenced by GOT page relocations calculate
@@ -831,6 +832,7 @@ void MipsGotSection::updateAllocSize() {
831832 }
832833 Size = (getLocalEntriesNum () + GlobalEntries.size () + TlsEntries.size ()) *
833834 Config->Wordsize ;
835+ return false ;
834836}
835837
836838bool MipsGotSection::empty () const {
@@ -1063,10 +1065,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
10631065
10641066 this ->Link = InX::DynStrTab->getParent ()->SectionIndex ;
10651067 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 (),
10691070 Entry::SecSize});
1071+
1072+ bool IsRela = Config->IsRela ;
10701073 add ({IsRela ? DT_RELAENT : DT_RELENT ,
10711074 uint64_t (IsRela ? sizeof (Elf_Rela) : sizeof (Elf_Rel))});
10721075
@@ -1202,21 +1205,57 @@ uint32_t DynamicReloc::getSymIndex() const {
12021205 return 0 ;
12031206}
12041207
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) {}
12121213
1213- template <class ELFT >
1214- void RelocationSection<ELFT >::addReloc(const DynamicReloc &Reloc) {
1214+ void RelocationBaseSection::addReloc (const DynamicReloc &Reloc) {
12151215 if (Reloc.Type == Target->RelativeRel )
12161216 ++NumRelativeRelocs;
12171217 Relocs.push_back (Reloc);
12181218}
12191219
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+
12201259template <class ELFT , class RelTy >
12211260static bool compRelocations (const RelTy &A, const RelTy &B) {
12221261 bool AIsRel = A.getType (Config->IsMips64EL ) == Target->RelativeRel ;
@@ -1230,18 +1269,8 @@ static bool compRelocations(const RelTy &A, const RelTy &B) {
12301269template <class ELFT > void RelocationSection<ELFT >::writeTo(uint8_t *Buf) {
12311270 uint8_t *BufBegin = Buf;
12321271 for (const DynamicReloc &Rel : Relocs) {
1233- auto *P = reinterpret_cast <Elf_Rela *>(Buf);
1272+ encodeDynamicReloc< ELFT >( reinterpret_cast <Elf_Rela *>(Buf), Rel );
12341273 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 );
12451274 }
12461275
12471276 if (Sort) {
@@ -1259,14 +1288,193 @@ template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
12591288 return this ->Entsize * Relocs.size ();
12601289}
12611290
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+ }
12671300
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;
12701478}
12711479
12721480SymbolTableBaseSection::SymbolTableBaseSection (StringTableSection &StrTabSec)
@@ -2471,6 +2679,11 @@ template class elf::RelocationSection<ELF32BE>;
24712679template class elf ::RelocationSection<ELF64LE >;
24722680template class elf ::RelocationSection<ELF64BE >;
24732681
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+
24742687template class elf ::SymbolTableSection<ELF32LE >;
24752688template class elf ::SymbolTableSection<ELF32BE >;
24762689template class elf ::SymbolTableSection<ELF64LE >;
0 commit comments