From 774df86e74ec6b4379c5431b5b19c8b084d86e73 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 26 Jul 2025 23:00:59 -0700 Subject: [PATCH 1/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?= =?UTF-8?q?itial=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.5-bogner --- llvm/include/llvm/MC/MCSection.h | 13 ++--- llvm/lib/MC/MCObjectStreamer.cpp | 4 +- llvm/lib/MC/MCSection.cpp | 2 +- .../MCTargetDesc/LoongArchAsmBackend.cpp | 3 +- .../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 19 +++++-- .../MC/RISCV/Relocations/align-after-relax.s | 50 +++++++++++++++++++ llvm/test/MC/RISCV/align-option-relax.s | 23 +++++++-- llvm/test/MC/RISCV/align.s | 35 +++++-------- llvm/test/MC/RISCV/cfi-advance.s | 28 ++++++----- llvm/test/MC/RISCV/nop-slide.s | 19 +++---- 10 files changed, 129 insertions(+), 67 deletions(-) create mode 100644 llvm/test/MC/RISCV/Relocations/align-after-relax.s diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h index 7989310e5a8f2..f70ed4ade23f2 100644 --- a/llvm/include/llvm/MC/MCSection.h +++ b/llvm/include/llvm/MC/MCSection.h @@ -567,6 +567,10 @@ class LLVM_ABI MCSection { Align Alignment; /// The section index in the assemblers section list. unsigned Ordinal = 0; + // If not -1u, the first linker-relaxable fragment's order within the + // subsection. When present, the offset between two locations crossing this + // fragment may not be fully resolved. + unsigned FirstLinkerRelaxable = -1u; /// Whether this section has had instructions emitted into it. bool HasInstructions : 1; @@ -576,10 +580,6 @@ class LLVM_ABI MCSection { bool IsText : 1; bool IsBss : 1; - /// Whether the section contains linker-relaxable fragments. If true, the - /// offset between two locations may not be fully resolved. - bool LinkerRelaxable : 1; - MCFragment DummyFragment; // Mapping from subsection number to fragment list. At layout time, the @@ -634,8 +634,9 @@ class LLVM_ABI MCSection { bool isRegistered() const { return IsRegistered; } void setIsRegistered(bool Value) { IsRegistered = Value; } - bool isLinkerRelaxable() const { return LinkerRelaxable; } - void setLinkerRelaxable() { LinkerRelaxable = true; } + unsigned firstLinkerRelaxable() const { return FirstLinkerRelaxable; } + bool isLinkerRelaxable() const { return FirstLinkerRelaxable != -1u; } + void setFirstLinkerRelaxable(unsigned Order) { FirstLinkerRelaxable = Order; } MCFragment &getDummyFragment() { return DummyFragment; } diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index f0465521c1433..6c66031e7dfb3 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -361,7 +361,9 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst, // instruction cannot be resolved at assemble-time. if (!MarkedLinkerRelaxable) { MarkedLinkerRelaxable = true; - getCurrentSectionOnly()->setLinkerRelaxable(); + auto *Sec = getCurrentSectionOnly(); + if (!Sec->isLinkerRelaxable()) + Sec->setFirstLinkerRelaxable(F->getLayoutOrder()); newFragment(); } } diff --git a/llvm/lib/MC/MCSection.cpp b/llvm/lib/MC/MCSection.cpp index 4f282672afbbf..eafd59a2478e9 100644 --- a/llvm/lib/MC/MCSection.cpp +++ b/llvm/lib/MC/MCSection.cpp @@ -20,7 +20,7 @@ using namespace llvm; MCSection::MCSection(StringRef Name, bool IsText, bool IsBss, MCSymbol *Begin) : Begin(Begin), HasInstructions(false), IsRegistered(false), IsText(IsText), - IsBss(IsBss), LinkerRelaxable(false), Name(Name) { + IsBss(IsBss), Name(Name) { DummyFragment.setParent(this); } diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp index d9ea88cdeaf24..6110920b3760e 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchAsmBackend.cpp @@ -255,7 +255,8 @@ bool LoongArchAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) { MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_LARCH_ALIGN); F.setVarFixups({Fixup}); F.setLinkerRelaxable(); - F.getParent()->setLinkerRelaxable(); + if (!F.getParent()->isLinkerRelaxable()) + F.getParent()->setFirstLinkerRelaxable(F.getLayoutOrder()); return true; } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 82e3b5ceb4ef6..2d9ffc69ccc2f 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -306,11 +306,19 @@ void RISCVAsmBackend::relaxInstruction(MCInst &Inst, // If conditions are met, compute the padding size and create a fixup encoding // the padding size in the addend. bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) { - // Use default handling unless linker relaxation is enabled and the alignment - // is larger than the nop size. - const MCSubtargetInfo *STI = F.getSubtargetInfo(); - if (!STI->hasFeature(RISCV::FeatureRelax)) + // Alignments before the first linker-relaxable instruction have fixed sizes + // and do not require relocations. Alignments following a linker-relaxable + // instruction require a relocation, even if the STI specifies norelax. + // + // firstLinkerRelaxable represents the layout order within the subsection, + // which may be smaller than the section's order. Therefore, alignments in + // an earlier subsection may be unnecessarily treated as linker-relaxable. + auto *Sec = F.getParent(); + if (F.getLayoutOrder() <= Sec->firstLinkerRelaxable()) return false; + + // Use default handling unless the alignment is larger than the nop size. + const MCSubtargetInfo *STI = F.getSubtargetInfo(); unsigned MinNopLen = STI->hasFeature(RISCV::FeatureStdExtZca) ? 2 : 4; if (F.getAlignment() <= MinNopLen) return false; @@ -321,7 +329,8 @@ bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) { MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_RISCV_ALIGN); F.setVarFixups({Fixup}); F.setLinkerRelaxable(); - F.getParent()->setLinkerRelaxable(); + if (!Sec->isLinkerRelaxable()) + Sec->setFirstLinkerRelaxable(F.getLayoutOrder()); return true; } diff --git a/llvm/test/MC/RISCV/Relocations/align-after-relax.s b/llvm/test/MC/RISCV/Relocations/align-after-relax.s new file mode 100644 index 0000000000000..cb22e0245e286 --- /dev/null +++ b/llvm/test/MC/RISCV/Relocations/align-after-relax.s @@ -0,0 +1,50 @@ +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax %s --defsym LATE=1 -o %t1 +# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases %t1 | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax %s -o %t0 +# RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases %t0 | FileCheck %s --check-prefix=CHECK0 + +# CHECK: 6: c.nop +# CHECK-EMPTY: +# CHECK: 10: auipc ra, 0x0 +# CHECK-NEXT: R_RISCV_CALL_PLT foo +# CHECK-NEXT: R_RISCV_RELAX *ABS* +# CHECK: 20: c.nop +# CHECK-NEXT: R_RISCV_ALIGN *ABS*+0x6 + +## Alignment directives in a smaller-number subsection might be conservatively treated as linker-relaxable. +# CHECK0: 6: c.nop +# CHECK0-NEXT: R_RISCV_ALIGN *ABS*+0x6 +# CHECK0: 20: c.nop +# CHECK0-NEXT: R_RISCV_ALIGN *ABS*+0x6 + +.text 2 +.option push +.option norelax +## R_RISCV_ALIGN is required even if norelax, because there is a preceding linker-relaxable instruction. +.balign 8 +l2: + .word 0x12345678 +.option pop + +.text 1 + .space 4 +.ifdef LATE + .space 0 +.endif + call foo +.ifdef LATE + .space 8 +.else + .space 4 +.endif + +.text 0 +_start: + .space 6 +.option push +.option norelax +.balign 8 +l0: + .word 0x12345678 +.option pop diff --git a/llvm/test/MC/RISCV/align-option-relax.s b/llvm/test/MC/RISCV/align-option-relax.s index 890e1e72d7706..60cd55f5a8b4d 100644 --- a/llvm/test/MC/RISCV/align-option-relax.s +++ b/llvm/test/MC/RISCV/align-option-relax.s @@ -1,8 +1,21 @@ # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=-relax < %s \ # RUN: | llvm-readobj -r - | FileCheck %s -# Check that .option relax overrides -mno-relax and enables R_RISCV_ALIGN -# relocations. -# CHECK: R_RISCV_ALIGN - .option relax - .align 4 +## .option relax overrides -mno-relax and enables R_RISCV_ALIGN/R_RISCV_RELAX relocations. +# CHECK: .rela.text +# CHECK: R_RISCV_CALL_PLT +# CHECK-NEXT: R_RISCV_RELAX +# CHECK-NEXT: R_RISCV_ALIGN +.option relax +call foo +.align 4 + +## Alignments before the first linker-relaxable instruction do not need relocations. +# CHECK-NOT: .rela.text1 +.section .text1,"ax" +.align 4 +nop + +# CHECK: .rela.text2 +.section .text2,"ax" +call foo diff --git a/llvm/test/MC/RISCV/align.s b/llvm/test/MC/RISCV/align.s index da3b1aa9b637a..ab317f079dbcd 100644 --- a/llvm/test/MC/RISCV/align.s +++ b/llvm/test/MC/RISCV/align.s @@ -46,16 +46,17 @@ # type for .align N directive when linker relaxation enabled. # Linker could satisfy alignment by removing NOPs after linker relaxation. -# The first R_RISCV_ALIGN come from -# MCELFStreamer::InitSections() emitCodeAlignment(getTextSectionAligntment()). -# C-OR-ZCA-EXT-RELAX-RELOC: R_RISCV_ALIGN - 0x2 -# C-OR-ZCA-EXT-RELAX-INST: c.nop test: +## Start with a linker-relaxable instruction so that the following alignment can be relaxable. + call foo +# NORELAX-RELOC: R_RISCV_CALL_PLT +# C-OR-ZCA-EXT-NORELAX-RELOC: R_RISCV_CALL_PLT + .p2align 2 # If the +c extension is enabled, the text section will be 2-byte aligned, so # one c.nop instruction is sufficient. -# C-OR-ZCA-EXT-RELAX-RELOC-NOT: R_RISCV_ALIGN - 0x2 -# C-OR-ZCA-EXT-RELAX-INST-NOT: c.nop +# C-OR-ZCA-EXT-RELAX-RELOC: R_RISCV_ALIGN - 0x2 +# C-OR-ZCA-EXT-RELAX-INST: c.nop bne zero, a0, .LBB0_2 mv a0, zero .p2align 3 @@ -136,16 +137,8 @@ data2: add a0, a0, a1 ## Branches crossing the linker-relaxable R_RISCV_ALIGN need relocations. -# RELAX-RELOC: .rela.text3 { -# RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0 -# RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4 -# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0 -# RELAX-RELOC-NEXT: } -# C-OR-ZCA-EXT-RELAX-RELOC: .rela.text3 { -# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0 -# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4 -# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0 -# C-OR-ZCA-EXT-RELAX-RELOC-NEXT: } +# RELAX-RELOC-NOT: .rela.text3 { +# C-OR-ZCA-EXT-RELAX-RELOC-NOT: .rela.text3 { .section .text3, "ax" bnez t1, 1f bnez t2, 2f @@ -157,7 +150,6 @@ data2: ## .text3 with a call at the start # NORELAX-RELOC: .rela.text3a -# C-OR-ZCA-EXT-NORELAX-RELOC: .rela.text3a # RELAX-RELOC: .rela.text3a { # RELAX-RELOC-NEXT: 0x0 R_RISCV_CALL_PLT foo 0x0 # RELAX-RELOC-NEXT: 0x0 R_RISCV_RELAX - 0x0 @@ -165,6 +157,8 @@ data2: # RELAX-RELOC-NEXT: 0x10 R_RISCV_ALIGN - 0x4 # RELAX-RELOC-NEXT: 0x14 R_RISCV_BRANCH .Ltmp[[#]] 0x0 # RELAX-RELOC-NEXT: } +# C-OR-ZCA-EXT-NORELAX-RELOC: .rela.text3a +# C-OR-ZCA-EXT-RELAX-RELOC: .rela.text3a .section .text3a, "ax" call foo bnez t1, 1f @@ -177,11 +171,8 @@ bnez t1, 2b ## .text3 with a call at the end # RELAX-RELOC: .rela.text3b { -# RELAX-RELOC-NEXT: 0x4 R_RISCV_BRANCH .Ltmp[[#]] 0x0 -# RELAX-RELOC-NEXT: 0x8 R_RISCV_ALIGN - 0x4 -# RELAX-RELOC-NEXT: 0xC R_RISCV_BRANCH .Ltmp[[#]] 0x0 -# RELAX-RELOC-NEXT: 0x14 R_RISCV_CALL_PLT foo 0x0 -# RELAX-RELOC-NEXT: 0x14 R_RISCV_RELAX - 0x0 +# RELAX-RELOC-NEXT: 0x10 R_RISCV_CALL_PLT foo 0x0 +# RELAX-RELOC-NEXT: 0x10 R_RISCV_RELAX - 0x0 # RELAX-RELOC-NEXT: } .section .text3b, "ax" bnez t1, 1f diff --git a/llvm/test/MC/RISCV/cfi-advance.s b/llvm/test/MC/RISCV/cfi-advance.s index f3f8530c419f0..bad2ef07235e5 100644 --- a/llvm/test/MC/RISCV/cfi-advance.s +++ b/llvm/test/MC/RISCV/cfi-advance.s @@ -7,7 +7,7 @@ # NORELAX: Relocation section '.rela.text1' at offset {{.*}} contains 1 entries: # NORELAX-NEXT: Offset Info Type Sym. Value Symbol's Name + Addend -# NORELAX-NEXT: 00000000 00000313 R_RISCV_CALL_PLT 00000004 .L0 + 0 +# NORELAX-NEXT: 00000000 00000313 R_RISCV_CALL_PLT 00000008 .L0 + 0 # NORELAX-EMPTY: # RELAX: Relocation section '.rela.text1' at offset {{.*}} contains 2 entries: # RELAX: R_RISCV_CALL_PLT @@ -16,23 +16,25 @@ # NORELAX-NEXT: Relocation section '.rela.eh_frame' at offset {{.*}} contains 1 entries: # NORELAX: Offset Info Type Sym. Value Symbol's Name + Addend # NORELAX-NEXT: 0000001c 00000139 R_RISCV_32_PCREL 00000000 .L0 + 0 -# RELAX-NEXT: Relocation section '.rela.eh_frame' at offset {{.*}} contains 5 entries: +# RELAX-NEXT: Relocation section '.rela.eh_frame' at offset {{.*}} contains 7 entries: # RELAX: Offset Info Type Sym. Value Symbol's Name + Addend # RELAX-NEXT: 0000001c 00000139 R_RISCV_32_PCREL 00000000 .L0 + 0 -# RELAX-NEXT: 00000020 00000c23 R_RISCV_ADD32 0001017a .L0 + 0 +# RELAX-NEXT: 00000020 00000d23 R_RISCV_ADD32 0001017a .L0 + 0 # RELAX-NEXT: 00000020 00000127 R_RISCV_SUB32 00000000 .L0 + 0 -# RELAX-NEXT: 00000035 00000b35 R_RISCV_SET6 00010176 .L0 + 0 -# RELAX-NEXT: 00000035 00000934 R_RISCV_SUB6 0001016e .L0 + 0 +# RELAX-NEXT: 00000026 00000536 R_RISCV_SET8 00000068 .L0 + 0 +# RELAX-NEXT: 00000026 00000125 R_RISCV_SUB8 00000000 .L0 + 0 +# RELAX-NEXT: 00000035 00000c35 R_RISCV_SET6 00010176 .L0 + 0 +# RELAX-NEXT: 00000035 00000a34 R_RISCV_SUB6 0001016e .L0 + 0 # CHECK-EMPTY: -# NORELAX: Symbol table '.symtab' contains 13 entries: -# RELAX: Symbol table '.symtab' contains 16 entries: +# NORELAX: Symbol table '.symtab' contains 14 entries: +# RELAX: Symbol table '.symtab' contains 18 entries: # RELAX-NEXT: Num: Value Size Type Bind Vis Ndx Name # RELAX-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND # RELAX-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}} -# RELAX: 3: 00000004 0 NOTYPE LOCAL DEFAULT 2 .L0{{$}} -# RELAX: 9: 0001016e 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}} -# RELAX: 11: 00010176 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}} -# RELAX: 12: 0001017a 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}} +# RELAX: 3: 00000008 0 NOTYPE LOCAL DEFAULT 2 .L0{{$}} +# RELAX: 10: 0001016e 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}} +# RELAX: 12: 00010176 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}} +# RELAX: 13: 0001017a 0 NOTYPE LOCAL DEFAULT 2 .L0 {{$}} # CHECK-DWARFDUMP: DW_CFA_advance_loc1: 104 # CHECK-DWARFDUMP-NEXT: DW_CFA_def_cfa_offset: +8 @@ -48,11 +50,11 @@ .type test,@function test: .cfi_startproc - nop + call foo ## This looks similar to fake label names ".L0 ". Even if this is ".L0 ", ## the assembler will not conflate it with fake labels. .L0: - .zero 100, 0x90 + .zero 96, 0x90 .cfi_def_cfa_offset 8 nop .zero 255, 0x90 diff --git a/llvm/test/MC/RISCV/nop-slide.s b/llvm/test/MC/RISCV/nop-slide.s index 4dc888b3ba777..9ce2e59f31b08 100644 --- a/llvm/test/MC/RISCV/nop-slide.s +++ b/llvm/test/MC/RISCV/nop-slide.s @@ -1,5 +1,5 @@ -# RUN: llvm-mc -triple riscv64 -mattr +c,-relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s -check-prefix CHECK-RVC-NORELAX -# RUN: llvm-mc -triple riscv64 -mattr +c,+relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s -check-prefix CHECK-RVC-RELAX +# RUN: llvm-mc -triple riscv64 -mattr +c,-relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s -check-prefix CHECK-RVC +# RUN: llvm-mc -triple riscv64 -mattr +c,+relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s -check-prefix CHECK-RVC # RUN: llvm-mc -triple riscv64 -mattr -c,-relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s # RUN: llvm-mc -triple riscv64 -mattr -c,+relax -filetype obj -o - %s | llvm-objdump -d - | FileCheck %s @@ -9,17 +9,10 @@ .balign 4 auipc a0, 0 -# CHECK-RVC-NORELAX: 0000000000000000 <.text>: -# CHECK-RVC-NORELAX-NEXT: 0: 0000 unimp -# CHECK-RVC-NORELAX-NEXT: 2: 0001 nop -# CHECK-RVC-NORELAX-NEXT: 4: 00000517 auipc a0, 0x0 - -# CHECK-RVC-RELAX: 0000000000000000 <.text>: -# CHECK-RVC-RELAX-NEXT: 0: 0001 nop -# CHECK-RVC-RELAX-NEXT: 2: 0100 addi s0, sp, 0x80 -# CHECK-RVC-RELAX-NEXT: 4: 1700 addi s0, sp, 0x3a0 -# CHECK-RVC-RELAX-NEXT: 6: 0005 c.nop 0x1 -# CHECK-RVC-RELAX-NEXT: 8: 00 +# CHECK-RVC: 0000000000000000 <.text>: +# CHECK-RVC-NEXT: 0: 0000 unimp +# CHECK-RVC-NEXT: 2: 0001 nop +# CHECK-RVC-NEXT: 4: 00000517 auipc a0, 0x0 # CHECK: 0000000000000000 <.text>: # CHECK-NEXT: 0: 0000 From 5572e677c5dcfc3c4a2875ab45979a3582f018b7 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 26 Jul 2025 23:45:07 -0700 Subject: [PATCH 2/3] comments Created using spr 1.3.5-bogner --- llvm/lib/MC/MCObjectStreamer.cpp | 26 +++++++++---------- .../RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 10 +++---- .../MC/RISCV/Relocations/align-after-relax.s | 4 +-- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index 6c66031e7dfb3..d2e37ef766d43 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -340,33 +340,33 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst, MCFragment *F = getCurrentFragment(); // Append the instruction to the data fragment. - size_t FixupStartIndex = F->getFixups().size(); size_t CodeOffset = F->getContents().size(); SmallVector Fixups; getAssembler().getEmitter().encodeInstruction( Inst, F->getContentsForAppending(), Fixups, STI); F->doneAppending(); - if (!Fixups.empty()) - F->appendFixups(Fixups); F->setHasInstructions(STI); + if (Fixups.empty()) + return; bool MarkedLinkerRelaxable = false; - for (auto &Fixup : MutableArrayRef(F->getFixups()).slice(FixupStartIndex)) { + for (auto &Fixup : Fixups) { Fixup.setOffset(Fixup.getOffset() + CodeOffset); - if (!Fixup.isLinkerRelaxable()) + if (!Fixup.isLinkerRelaxable() || MarkedLinkerRelaxable) continue; - F->setLinkerRelaxable(); + MarkedLinkerRelaxable = true; + // Set the fragment's order within the subsection for use by + // MCAssembler::relaxAlign. + auto *Sec = F->getParent(); + if (!Sec->isLinkerRelaxable()) + Sec->setFirstLinkerRelaxable(F->getLayoutOrder()); // Do not add data after a linker-relaxable instruction. The difference // between a new label and a label at or before the linker-relaxable // instruction cannot be resolved at assemble-time. - if (!MarkedLinkerRelaxable) { - MarkedLinkerRelaxable = true; - auto *Sec = getCurrentSectionOnly(); - if (!Sec->isLinkerRelaxable()) - Sec->setFirstLinkerRelaxable(F->getLayoutOrder()); - newFragment(); - } + F->setLinkerRelaxable(); + newFragment(); } + F->appendFixups(Fixups); } void MCObjectStreamer::emitInstToFragment(const MCInst &Inst, diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 2d9ffc69ccc2f..c99a9e722473a 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -307,12 +307,12 @@ void RISCVAsmBackend::relaxInstruction(MCInst &Inst, // the padding size in the addend. bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) { // Alignments before the first linker-relaxable instruction have fixed sizes - // and do not require relocations. Alignments following a linker-relaxable + // and do not require relocations. Alignments after a linker-relaxable // instruction require a relocation, even if the STI specifies norelax. // - // firstLinkerRelaxable represents the layout order within the subsection, - // which may be smaller than the section's order. Therefore, alignments in - // an earlier subsection may be unnecessarily treated as linker-relaxable. + // firstLinkerRelaxable is the layout order within the subsection, which may + // be smaller than the section's order. Therefore, alignments in a + // lower-numbered subsection may be unnecessarily treated as linker-relaxable. auto *Sec = F.getParent(); if (F.getLayoutOrder() <= Sec->firstLinkerRelaxable()) return false; @@ -329,8 +329,6 @@ bool RISCVAsmBackend::relaxAlign(MCFragment &F, unsigned &Size) { MCFixup::create(0, Expr, FirstLiteralRelocationKind + ELF::R_RISCV_ALIGN); F.setVarFixups({Fixup}); F.setLinkerRelaxable(); - if (!Sec->isLinkerRelaxable()) - Sec->setFirstLinkerRelaxable(F.getLayoutOrder()); return true; } diff --git a/llvm/test/MC/RISCV/Relocations/align-after-relax.s b/llvm/test/MC/RISCV/Relocations/align-after-relax.s index cb22e0245e286..e21bf02b24e24 100644 --- a/llvm/test/MC/RISCV/Relocations/align-after-relax.s +++ b/llvm/test/MC/RISCV/Relocations/align-after-relax.s @@ -12,7 +12,7 @@ # CHECK: 20: c.nop # CHECK-NEXT: R_RISCV_ALIGN *ABS*+0x6 -## Alignment directives in a smaller-number subsection might be conservatively treated as linker-relaxable. +## Alignment directives in a lower-numbered subsection may be conservatively treated as linker-relaxable. # CHECK0: 6: c.nop # CHECK0-NEXT: R_RISCV_ALIGN *ABS*+0x6 # CHECK0: 20: c.nop @@ -21,7 +21,7 @@ .text 2 .option push .option norelax -## R_RISCV_ALIGN is required even if norelax, because there is a preceding linker-relaxable instruction. +## R_RISCV_ALIGN is required even if norelax, because it is after a linker-relaxable instruction. .balign 8 l2: .word 0x12345678 From a169b80e737542977e361ff31a1096776dc64711 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 7 Aug 2025 19:13:43 -0700 Subject: [PATCH 3/3] test Created using spr 1.3.5-bogner --- .../MC/RISCV/Relocations/align-after-relax.s | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/llvm/test/MC/RISCV/Relocations/align-after-relax.s b/llvm/test/MC/RISCV/Relocations/align-after-relax.s index e21bf02b24e24..95bef513dff97 100644 --- a/llvm/test/MC/RISCV/Relocations/align-after-relax.s +++ b/llvm/test/MC/RISCV/Relocations/align-after-relax.s @@ -4,18 +4,22 @@ # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax %s -o %t0 # RUN: llvm-objdump -dr --no-show-raw-insn -M no-aliases %t0 | FileCheck %s --check-prefix=CHECK0 -# CHECK: 6: c.nop +# CHECK: 4: 00 00 01 00 .word 0x00010000 # CHECK-EMPTY: +# CHECK: 8: 78 56 34 12 .word 0x12345678 +# CHECK-NEXT: c: 00 00 00 00 .word 0x00000000 # CHECK: 10: auipc ra, 0x0 # CHECK-NEXT: R_RISCV_CALL_PLT foo # CHECK-NEXT: R_RISCV_RELAX *ABS* -# CHECK: 20: c.nop +# CHECK: 18: c.nop # CHECK-NEXT: R_RISCV_ALIGN *ABS*+0x6 ## Alignment directives in a lower-numbered subsection may be conservatively treated as linker-relaxable. -# CHECK0: 6: c.nop -# CHECK0-NEXT: R_RISCV_ALIGN *ABS*+0x6 -# CHECK0: 20: c.nop +# CHECK0: 4: 00 00 01 00 .word 0x00010000 +# CHECK0-NEXT: 000000006: R_RISCV_ALIGN *ABS*+0x6 +# CHECK0-NEXT: 8: 13 00 00 00 .word 0x00000013 +# CHECK0: 14: auipc ra, 0x0 +# CHECK0: 1c: c.nop # CHECK0-NEXT: R_RISCV_ALIGN *ABS*+0x6 .text 2 @@ -28,16 +32,12 @@ l2: .option pop .text 1 - .space 4 + .org .+1 + .org .+3 .ifdef LATE - .space 0 + .org .+0 .endif call foo -.ifdef LATE - .space 8 -.else - .space 4 -.endif .text 0 _start: