diff options
author | Fangrui Song <i@maskray.me> | 2023-05-12 23:58:39 -0700 |
---|---|---|
committer | Fangrui Song <i@maskray.me> | 2023-05-12 23:58:39 -0700 |
commit | 2473b1af085ad54e89666cedf684fdf10a84f058 (patch) | |
tree | b72c69e06070fe1f5cc0eff282c40ac3313dabfa /lld | |
parent | 96ddbd6dd85f9bc27fc3bc101411c7928a0c2756 (diff) | |
download | llvm-2473b1af085ad54e89666cedf684fdf10a84f058.tar.gz |
[ELF] Simplify getSectionRank and rewrite comments
Replace some RF_ flags with integer literals.
Rewrite the isWrite/isExec block to make the code block order reflect
the section order.
Rewrite some imprecise comments.
This is NFC, if we don't count invalid cases such as non-writable TLS
and non-writable RELRO.
Diffstat (limited to 'lld')
-rw-r--r-- | lld/ELF/Writer.cpp | 118 |
1 files changed, 44 insertions, 74 deletions
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index ffbe79872034..9266764ee0f6 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -829,10 +829,7 @@ enum RankFlags { RF_NOT_ADDR_SET = 1 << 27, RF_NOT_ALLOC = 1 << 26, RF_PARTITION = 1 << 18, // Partition number (8 bits) - RF_NOT_PART_EHDR = 1 << 17, - RF_NOT_PART_PHDR = 1 << 16, - RF_NOT_INTERP = 1 << 15, - RF_NOT_NOTE = 1 << 14, + RF_NOT_SPECIAL = 1 << 17, RF_WRITE = 1 << 13, RF_EXEC_WRITE = 1 << 12, RF_EXEC = 1 << 11, @@ -840,12 +837,6 @@ enum RankFlags { RF_NOT_RELRO = 1 << 9, RF_NOT_TLS = 1 << 8, RF_BSS = 1 << 7, - RF_PPC_TOC = 1 << 4, - RF_PPC_GOT = 1 << 3, - RF_PPC_BRANCH_LT = 1 << 2, - RF_MIPS_GPREL = 1 << 1, - RF_MIPS_NOT_GOT = 1 << 0, - RF_RISCV_SDATA = 1 << 0, }; static unsigned getSectionRank(const OutputSection &osec) { @@ -864,71 +855,53 @@ static unsigned getSectionRank(const OutputSection &osec) { if (osec.type == SHT_LLVM_PART_EHDR) return rank; - rank |= RF_NOT_PART_EHDR; - if (osec.type == SHT_LLVM_PART_PHDR) - return rank; - rank |= RF_NOT_PART_PHDR; + return rank | 1; // Put .interp first because some loaders want to see that section // on the first page of the executable file when loaded into memory. if (osec.name == ".interp") - return rank; - rank |= RF_NOT_INTERP; + return rank | 2; - // Put .note sections (which make up one PT_NOTE) at the beginning so that - // they are likely to be included in a core file even if core file size is - // limited. In particular, we want a .note.gnu.build-id and a .note.tag to be - // included in a core to match core files with executables. + // Put .note sections at the beginning so that they are likely to be included + // in a truncate core file. In particular, .note.gnu.build-id, if available, + // can identify the object file. if (osec.type == SHT_NOTE) - return rank; - rank |= RF_NOT_NOTE; + return rank | 3; + + rank |= RF_NOT_SPECIAL; // Sort sections based on their access permission in the following - // order: R, RX, RWX, RW. This order is based on the following - // considerations: - // * Read-only sections come first such that they go in the - // PT_LOAD covering the program headers at the start of the file. - // * Read-only, executable sections come next. - // * Writable, executable sections follow such that .plt on - // architectures where it needs to be writable will be placed - // between .text and .data. - // * Writable sections come last, such that .bss lands at the very - // end of the last PT_LOAD. + // order: R, RX, RXW, RW(RELRO), RW(non-RELRO). + // + // Read-only sections come first such that they go in the PT_LOAD covering the + // program headers at the start of the file. + // + // The layout for writable sections is PT_LOAD(PT_GNU_RELRO(.data.rel.ro + // .bss.rel.ro) | .data .bss), where | marks where page alignment happens. + // An alternative ordering is PT_LOAD(.data | PT_GNU_RELRO( .data.rel.ro + // .bss.rel.ro) | .bss), but it may waste more bytes due to 2 alignment + // places. bool isExec = osec.flags & SHF_EXECINSTR; bool isWrite = osec.flags & SHF_WRITE; - if (isExec) { - if (isWrite) - rank |= RF_EXEC_WRITE; - else - rank |= RF_EXEC; - } else if (isWrite) { + if (!isWrite && !isExec) { + // Make PROGBITS sections (e.g .rodata .eh_frame) closer to .text to + // alleviate relocation overflow pressure. Large special sections such as + // .dynstr and .dynsym can be away from .text. + if (osec.type == SHT_PROGBITS) + rank |= RF_RODATA; + } else if (isExec) { + rank |= isWrite ? RF_EXEC_WRITE : RF_EXEC; + } else { rank |= RF_WRITE; - } else if (osec.type == SHT_PROGBITS) { - // Make non-executable and non-writable PROGBITS sections (e.g .rodata - // .eh_frame) closer to .text. They likely contain PC or GOT relative - // relocations and there could be relocation overflow if other huge sections - // (.dynstr .dynsym) were placed in between. - rank |= RF_RODATA; - } - - // Place RelRo sections first. After considering SHT_NOBITS below, the - // ordering is PT_LOAD(PT_GNU_RELRO(.data.rel.ro .bss.rel.ro) | .data .bss), - // where | marks where page alignment happens. An alternative ordering is - // PT_LOAD(.data | PT_GNU_RELRO( .data.rel.ro .bss.rel.ro) | .bss), but it may - // waste more bytes due to 2 alignment places. - if (!isRelroSection(&osec)) - rank |= RF_NOT_RELRO; - - // If we got here we know that both A and B are in the same PT_LOAD. - - // The TLS initialization block needs to be a single contiguous block in a R/W - // PT_LOAD, so stick TLS sections directly before the other RelRo R/W - // sections. Since p_filesz can be less than p_memsz, place NOBITS sections - // after PROGBITS. - if (!(osec.flags & SHF_TLS)) - rank |= RF_NOT_TLS; + // The TLS initialization block needs to be a single contiguous block. Place + // TLS sections directly before the other RELRO sections. + if (!(osec.flags & SHF_TLS)) + rank |= RF_NOT_TLS; + if (!isRelroSection(&osec)) + rank |= RF_NOT_RELRO; + } // Within TLS sections, or within other RelRo sections, or within non-RelRo // sections, place non-NOBITS sections first. @@ -943,24 +916,21 @@ static unsigned getSectionRank(const OutputSection &osec) { // their coverage by a single signed 16-bit offset from the TOC base // pointer. StringRef name = osec.name; - if (name == ".toc") - rank |= RF_PPC_TOC; - - if (name == ".got") - rank |= RF_PPC_GOT; - if (name == ".branch_lt") - rank |= RF_PPC_BRANCH_LT; + rank |= 1; + else if (name == ".got") + rank |= 2; + else if (name == ".toc") + rank |= 4; } if (config->emachine == EM_MIPS) { + if (osec.name != ".got") + rank |= 1; // All sections with SHF_MIPS_GPREL flag should be grouped together // because data in these sections is addressable with a gp relative address. if (osec.flags & SHF_MIPS_GPREL) - rank |= RF_MIPS_GPREL; - - if (osec.name != ".got") - rank |= RF_MIPS_NOT_GOT; + rank |= 2; } if (config->emachine == EM_RISCV) { @@ -968,7 +938,7 @@ static unsigned getSectionRank(const OutputSection &osec) { // and match GNU ld. StringRef name = osec.name; if (name == ".sdata" || (osec.type == SHT_NOBITS && name != ".sbss")) - rank |= RF_RISCV_SDATA; + rank |= 1; } return rank; |