Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -108,7 +108,7 @@ template void finalize(); template void writeTo(uint8_t *Buf); template void maybeCompress(); - uint32_t getFiller(); + llvm::Optional getFiller(); void sort(std::function Order); void sortInitFini(); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -395,9 +395,9 @@ for (InputSection *IS : ISD->Sections) if (IS->Live) Sections.push_back(IS); - uint32_t Filler = getFiller(); + llvm::Optional Filler = getFiller(); if (Filler) - fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler); + fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, *Filler); parallelForEachN(0, Sections.size(), [=](size_t I) { InputSection *IS = Sections[I]; @@ -411,7 +411,7 @@ End = Buf + Size; else End = Buf + Sections[I + 1]->OutSecOff; - fill(Start, End - Start, Filler); + fill(Start, End - Start, *Filler); } }); @@ -581,12 +581,17 @@ sort([](InputSectionBase *S) { return getPriority(S->Name); }); } -uint32_t OutputSection::getFiller() { +llvm::Optional OutputSection::getFiller() { if (Filler) return *Filler; - if (Flags & SHF_EXECINSTR) + if (Flags & SHF_EXECINSTR) { + // .init and .fini are run from start to end, so we need to pad it with nops + // instead of trap instructions + if (Name == ".init" || Name == ".fini") + return Target->NopInstr; return Target->TrapInstr; - return 0; + } + return None; } template void OutputSection::writeHeaderTo(ELF32LE::Shdr *Shdr); Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -100,6 +100,8 @@ // A 4-byte field corresponding to one or more trap instructions, used to pad // executable OutputSections. uint32_t TrapInstr = 0; + // NOP instruction used to pad .init/.fini sections + uint32_t NopInstr = 0; virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const; Index: test/ELF/Inputs/freebsd-mips-crtn.s =================================================================== --- /dev/null +++ test/ELF/Inputs/freebsd-mips-crtn.s @@ -0,0 +1,10 @@ +# Check that aligning the .fini section doesn't insert trap instructions + +.section .fini,"ax",%progbits +.p2align 4 +.set noreorder +sd $gp, 0($sp) +sd $ra, 8($sp) +jr $ra +daddu $sp, $sp, 32 +.set reorder Index: test/ELF/fini-padding.s =================================================================== --- /dev/null +++ test/ELF/fini-padding.s @@ -0,0 +1,86 @@ +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %S/Inputs/freebsd-mips-crtn.s -o %t-crtn.o +# RUN: ld.lld -Bstatic %t.o %t-crtn.o -o %t.exe +# RUN: llvm-readobj -s %t.exe | FileCheck %s -check-prefix SECTIONS +# RUN: llvm-objdump -d -p -h %t.exe | FileCheck %s + +# LLD was inserting trap instructions into FreeBSD binaries .init/.fini sections +# The crtn.s file wrongly aligned .init to 2**4 instead of 4 so lld was filling +# in padding with trap instructions + +# Even though the FreeBSD code was wrong we should still not insert trap +# instructions into .init/.fini. It contains concatenated snippets of code that +# runs in order. We should insert nops here the same way BFD does it + +.text +.global __start +__start: + jr $ra + nop + +.global dtor +dtor: + jr $ra + nop + +.section .fini,"ax",%progbits +.set noreorder +dla $t9, dtor +li $a0, 42 +jalr $t9 +nop +li $a0, 0x1234 + +.section .init,"ax",%progbits +.p2align 4 +.set noreorder +li $a0, 42 + +.section .init,"ax",%progbits +.p2align 4 +.set noreorder +li $a0, 43 + + +# SECTIONS: Section { +# SECTIONS: Name: .fini (36) +# SECTIONS-NEXT: Type: SHT_PROGBITS (0x1) +# SECTIONS-NEXT: Flags [ (0x6) +# SECTIONS-NEXT: SHF_ALLOC (0x2) +# SECTIONS-NEXT: SHF_EXECINSTR (0x4) +# SECTIONS-NEXT: ] +# SECTIONS-NEXT: Address: 0x20020 +# SECTIONS-NEXT: Offset: 0x10020 +# SECTIONS-NEXT: Size: 64 +# SECTIONS-NEXT: Link: 0 +# SECTIONS-NEXT: Info: 0 +# SECTIONS-NEXT: AddressAlignment: 16 +# SECTIONS-NEXT: EntrySize: 0 +# SECTIONS-NEXT: } + + +# We don't want any trap instructions inserted between the .fini and .init sections + +# CHECK-LABEL: Disassembly of section .fini: +# CHECK-NEXT: .fini: +# CHECK-NEXT: 20020: 3c 19 00 00 lui $25, 0 +# CHECK: 2003c: 03 20 f8 09 jalr $25 +# CHECK-NEXT: 20040: 00 00 00 00 nop +# CHECK-NEXT: 20044: 24 04 12 34 addiu $4, $zero, 4660 +# The following two instructions were previously filled with traps: +# CHECK-NEXT: 20048: 00 00 00 00 nop +# CHECK-NEXT: 2004c: 00 00 00 00 nop +# now the code from crtn.o: +# CHECK-NEXT: 20050: ff bc 00 00 sd $gp, 0($sp) +# CHECK-NEXT: 20054: ff bf 00 08 sd $ra, 8($sp) +# CHECK-NEXT: 20058: 03 e0 00 08 jr $ra +# CHECK-NEXT: 2005c: 67 bd 00 20 daddiu $sp, $sp, 32 + + +# CHECK-LABEL: Disassembly of section .init: +# CHECK-NEXT: .init: +# CHECK-NEXT: 24 04 00 2a addiu $4, $zero, 42 +# CHECK-NEXT: 00 00 00 00 nop +# CHECK-NEXT: 00 00 00 00 nop +# CHECK-NEXT: 00 00 00 00 nop +# CHECK-NEXT: 24 04 00 2b addiu $4, $zero, 43