Skip to content

[lld] Support merging RISC-V Atomics ABI attributes #97347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

94 changes: 93 additions & 1 deletion lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1084,10 +1084,94 @@ static void mergeArch(RISCVISAUtils::OrderedExtensionMap &mergedExts,
}
}

static void mergeAtomic(DenseMap<unsigned, unsigned>::iterator it,
const InputSectionBase *oldSection,
const InputSectionBase *newSection,
RISCVAttrs::RISCVAtomicAbiTag oldTag,
RISCVAttrs::RISCVAtomicAbiTag newTag) {
using RISCVAttrs::RISCVAtomicAbiTag;
// Same tags stay the same, and UNKNOWN is compatible with anything
if (oldTag == newTag || newTag == RISCVAtomicAbiTag::UNKNOWN)
return;

auto reportAbiError = [&]() {
errorOrWarn("atomic abi mismatch for " + oldSection->name + "\n>>> " +
toString(oldSection) +
": atomic_abi=" + Twine(static_cast<unsigned>(oldTag)) +
"\n>>> " + toString(newSection) +
": atomic_abi=" + Twine(static_cast<unsigned>(newTag)));
};

auto reportUnknownAbiError = [](const InputSectionBase *section,
RISCVAtomicAbiTag tag) {
switch (tag) {
case RISCVAtomicAbiTag::UNKNOWN:
case RISCVAtomicAbiTag::A6C:
case RISCVAtomicAbiTag::A6S:
case RISCVAtomicAbiTag::A7:
return;
};
errorOrWarn("unknown atomic abi for " + section->name + "\n>>> " +
toString(section) +
": atomic_abi=" + Twine(static_cast<unsigned>(tag)));
};
switch (oldTag) {
case RISCVAtomicAbiTag::UNKNOWN:
it->getSecond() = static_cast<unsigned>(newTag);
return;
case RISCVAtomicAbiTag::A6C:
switch (newTag) {
case RISCVAtomicAbiTag::A6S:
it->getSecond() = static_cast<unsigned>(RISCVAtomicAbiTag::A6C);
return;
case RISCVAtomicAbiTag::A7:
reportAbiError();
return;
case RISCVAttrs::RISCVAtomicAbiTag::UNKNOWN:
case RISCVAttrs::RISCVAtomicAbiTag::A6C:
return;
};

case RISCVAtomicAbiTag::A6S:
switch (newTag) {
case RISCVAtomicAbiTag::A6C:
it->getSecond() = static_cast<unsigned>(RISCVAtomicAbiTag::A6C);
return;
case RISCVAtomicAbiTag::A7:
it->getSecond() = static_cast<unsigned>(RISCVAtomicAbiTag::A7);
return;
case RISCVAttrs::RISCVAtomicAbiTag::UNKNOWN:
case RISCVAttrs::RISCVAtomicAbiTag::A6S:
return;
};

case RISCVAtomicAbiTag::A7:
switch (newTag) {
case RISCVAtomicAbiTag::A6S:
it->getSecond() = static_cast<unsigned>(RISCVAtomicAbiTag::A7);
return;
case RISCVAtomicAbiTag::A6C:
reportAbiError();
return;
case RISCVAttrs::RISCVAtomicAbiTag::UNKNOWN:
case RISCVAttrs::RISCVAtomicAbiTag::A7:
return;
};
};

// If we get here, then we have an invalid tag, so report it.
// Putting these checks at the end allows us to only do these checks when we
// need to, since this is expected to be a rare occurrence.
reportUnknownAbiError(oldSection, oldTag);
reportUnknownAbiError(newSection, newTag);
}

static RISCVAttributesSection *
mergeAttributesSection(const SmallVector<InputSectionBase *, 0> &sections) {
using RISCVAttrs::RISCVAtomicAbiTag;
RISCVISAUtils::OrderedExtensionMap exts;
const InputSectionBase *firstStackAlign = nullptr;
const InputSectionBase *firstAtomicAbi = nullptr;
unsigned firstStackAlignValue = 0, xlen = 0;
bool hasArch = false;

Expand Down Expand Up @@ -1136,7 +1220,15 @@ mergeAttributesSection(const SmallVector<InputSectionBase *, 0> &sections) {
break;

case RISCVAttrs::AttrType::ATOMIC_ABI:
// TODO: Handle ATOMIC_ABI tag merging
if (auto i = parser.getAttributeValue(tag.attr)) {
auto r = merged.intAttr.try_emplace(tag.attr, *i);
if (r.second)
firstAtomicAbi = sec;
else
mergeAtomic(r.first, firstAtomicAbi, sec,
static_cast<RISCVAtomicAbiTag>(r.first->getSecond()),
static_cast<RISCVAtomicAbiTag>(*i));
}
continue;
}

Expand Down
212 changes: 212 additions & 0 deletions lld/test/ELF/riscv-attributes.s
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,46 @@
# RUN: not ld.lld a.o b.o c.o diff_stack_align.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=STACK_ALIGN --implicit-check-not=error:
# STACK_ALIGN: error: diff_stack_align.o:(.riscv.attributes) has stack_align=32 but a.o:(.riscv.attributes) has stack_align=16

## RISC-V tag merging for atomic_abi values A6C and A7 lead to an error.
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_A6C.s -o atomic_abi_A6C.o
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_A7.s -o atomic_abi_A7.o
# RUN: not ld.lld atomic_abi_A6C.o atomic_abi_A7.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ATOMIC_ABI_ERROR --implicit-check-not=error:
# ATOMIC_ABI_ERROR: error: atomic abi mismatch for .riscv.attributes
# ATOMIC_ABI_ERROR-NEXT: >>> atomic_abi_A6C.o:(.riscv.attributes): atomic_abi=1
# ATOMIC_ABI_ERROR-NEXT: >>> atomic_abi_A7.o:(.riscv.attributes): atomic_abi=3

## RISC-V tag merging for atomic_abi values A6C and invalid lead to an error.
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_invalid.s -o atomic_abi_invalid.o
# RUN: not ld.lld atomic_abi_A6C.o atomic_abi_invalid.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ATOMIC_ABI_INVALID --implicit-check-not=error:
# ATOMIC_ABI_INVALID: error: unknown atomic abi for .riscv.attributes
# ATOMIC_ABI_INVALID-NEXT: >>> atomic_abi_invalid.o:(.riscv.attributes): atomic_abi=42

# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_A6S.s -o atomic_abi_A6S.o
# RUN: ld.lld atomic_abi_A6S.o atomic_abi_A6C.o -o atomic_abi_A6C_A6S
# RUN: llvm-readobj -A atomic_abi_A6C_A6S | FileCheck %s --check-prefix=A6C_A6S

# RUN: ld.lld atomic_abi_A6S.o atomic_abi_A7.o -o atomic_abi_A6S_A7
# RUN: llvm-readobj -A atomic_abi_A6S_A7 | FileCheck %s --check-prefix=A6S_A7

# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_unknown.s -o atomic_abi_unknown.o
# RUN: ld.lld atomic_abi_unknown.o atomic_abi_A6C.o -o atomic_abi_A6C_unknown
# RUN: llvm-readobj -A atomic_abi_A6C_unknown | FileCheck %s --check-prefixes=UNKNOWN_A6C

# RUN: ld.lld atomic_abi_unknown.o diff_stack_align.o -o atomic_abi_none_unknown
# RUN: llvm-readobj -A atomic_abi_none_unknown | FileCheck %s --check-prefixes=UNKNOWN_NONE

# RUN: ld.lld diff_stack_align.o atomic_abi_A6C.o -o atomic_abi_A6C_none
# RUN: llvm-readobj -A atomic_abi_A6C_none | FileCheck %s --check-prefixes=NONE_A6C

# RUN: ld.lld atomic_abi_unknown.o atomic_abi_A6S.o -o atomic_abi_A6S_unknown
# RUN: llvm-readobj -A atomic_abi_A6S_unknown | FileCheck %s --check-prefix=UNKNOWN_A6S

# RUN: ld.lld atomic_abi_unknown.o atomic_abi_A7.o -o atomic_abi_A7_unknown
# RUN: llvm-readobj -A atomic_abi_A7_unknown | FileCheck %s --check-prefix=UNKNOWN_A7

# RUN: ld.lld diff_stack_align.o atomic_abi_A7.o -o atomic_abi_A7_none
# RUN: llvm-readobj -A atomic_abi_A7_none | FileCheck %s --check-prefix=NONE_A7

## The deprecated priv_spec is not handled as GNU ld does.
## Differing priv_spec attributes lead to an absent attribute.
# RUN: llvm-mc -filetype=obj -triple=riscv64 diff_priv_spec.s -o diff_priv_spec.o
Expand Down Expand Up @@ -286,6 +326,178 @@
.attribute priv_spec, 3
.attribute priv_spec_minor, 3

#--- atomic_abi_unknown.s
.attribute atomic_abi, 0

#--- atomic_abi_A6C.s
.attribute atomic_abi, 1

#--- atomic_abi_A6S.s
.attribute atomic_abi, 2

#--- atomic_abi_A7.s
.attribute atomic_abi, 3

#--- atomic_abi_invalid.s
.attribute atomic_abi, 42

# UNKNOWN_NONE: BuildAttributes {
# UNKNOWN_NONE-NEXT: FormatVersion: 0x41
# UNKNOWN_NONE-NEXT: Section 1 {
# UNKNOWN_NONE-NEXT: SectionLength: 17
# UNKNOWN_NONE-NEXT: Vendor: riscv
# UNKNOWN_NONE-NEXT: Tag: Tag_File (0x1)
# UNKNOWN_NONE-NEXT: Size: 7
# UNKNOWN_NONE-NEXT: FileAttributes {
# UNKNOWN_NONE-NEXT: Attribute {
# UNKNOWN_NONE-NEXT: Tag: 4
# UNKNOWN_NONE-NEXT: Value: 32
# UNKNOWN_NONE-NEXT: TagName: stack_align
# UNKNOWN_NONE-NEXT: Description: Stack alignment is 32-bytes
# UNKNOWN_NONE-NEXT: }
# UNKNOWN_NONE-NEXT: }
# UNKNOWN_NONE-NEXT: }
# UNKNOWN_NONE-NEXT: }

# NONE_A6C: BuildAttributes {
# NONE_A6C-NEXT: FormatVersion: 0x41
# NONE_A6C-NEXT: Section 1 {
# NONE_A6C-NEXT: SectionLength: 19
# NONE_A6C-NEXT: Vendor: riscv
# NONE_A6C-NEXT: Tag: Tag_File (0x1)
# NONE_A6C-NEXT: Size: 9
# NONE_A6C-NEXT: FileAttributes {
# NONE_A6C-NEXT: Attribute {
# NONE_A6C-NEXT: Tag: 14
# NONE_A6C-NEXT: Value: 1
# NONE_A6C-NEXT: TagName: atomic_abi
# NONE_A6C-NEXT: Description: Atomic ABI is 1
# NONE_A6C-NEXT: }
# NONE_A6C-NEXT: Attribute {
# NONE_A6C-NEXT: Tag: 4
# NONE_A6C-NEXT: Value: 32
# NONE_A6C-NEXT: TagName: stack_align
# NONE_A6C-NEXT: Description: Stack alignment is 32-bytes
# NONE_A6C-NEXT: }
# NONE_A6C-NEXT: }
# NONE_A6C-NEXT: }
# NONE_A6C-NEXT: }

# UNKNOWN_A6C: BuildAttributes {
# UNKNOWN_A6C-NEXT: FormatVersion: 0x41
# UNKNOWN_A6C-NEXT: Section 1 {
# UNKNOWN_A6C-NEXT: SectionLength: 17
# UNKNOWN_A6C-NEXT: Vendor: riscv
# UNKNOWN_A6C-NEXT: Tag: Tag_File (0x1)
# UNKNOWN_A6C-NEXT: Size: 7
# UNKNOWN_A6C-NEXT: FileAttributes {
# UNKNOWN_A6C-NEXT: Attribute {
# UNKNOWN_A6C-NEXT: Tag: 14
# UNKNOWN_A6C-NEXT: Value: 1
# UNKNOWN_A6C-NEXT: TagName: atomic_abi
# UNKNOWN_A6C-NEXT: Description: Atomic ABI is 1
# UNKNOWN_A6C-NEXT: }
# UNKNOWN_A6C-NEXT: }
# UNKNOWN_A6C-NEXT: }
# UNKNOWN_A6C-NEXT: }

# UNKNOWN_A6S: BuildAttributes {
# UNKNOWN_A6S-NEXT: FormatVersion: 0x41
# UNKNOWN_A6S-NEXT: Section 1 {
# UNKNOWN_A6S-NEXT: SectionLength:
# UNKNOWN_A6S-NEXT: Vendor: riscv
# UNKNOWN_A6S-NEXT: Tag: Tag_File (0x1)
# UNKNOWN_A6S-NEXT: Size: 7
# UNKNOWN_A6S-NEXT: FileAttributes {
# UNKNOWN_A6S-NEXT: Attribute {
# UNKNOWN_A6S-NEXT: Tag: 14
# UNKNOWN_A6S-NEXT: Value: 2
# UNKNOWN_A6S-NEXT: TagName: atomic_abi
# UNKNOWN_A6S-NEXT: Description: Atomic ABI is 2
# UNKNOWN_A6S-NEXT: }
# UNKNOWN_A6S-NEXT: }
# UNKNOWN_A6S-NEXT: }
# UNKNOWN_A6S-NEXT: }

# NONE_A7: BuildAttributes {
# NONE_A7-NEXT: FormatVersion: 0x41
# NONE_A7-NEXT: Section 1 {
# NONE_A7-NEXT: SectionLength: 19
# NONE_A7-NEXT: Vendor: riscv
# NONE_A7-NEXT: Tag: Tag_File (0x1)
# NONE_A7-NEXT: Size: 9
# NONE_A7-NEXT: FileAttributes {
# NONE_A7-NEXT: Attribute {
# NONE_A7-NEXT: Tag: 14
# NONE_A7-NEXT: Value: 3
# NONE_A7-NEXT: TagName: atomic_abi
# NONE_A7-NEXT: Description: Atomic ABI is 3
# NONE_A7-NEXT: }
# NONE_A7-NEXT: Attribute {
# NONE_A7-NEXT: Tag: 4
# NONE_A7-NEXT: Value: 32
# NONE_A7-NEXT: TagName: stack_align
# NONE_A7-NEXT: Description: Stack alignment is 32-bytes
# NONE_A7-NEXT: }
# NONE_A7-NEXT: }
# NONE_A7-NEXT: }
# NONE_A7-NEXT: }


# UNKNOWN_A7: BuildAttributes {
# UNKNOWN_A7-NEXT: FormatVersion: 0x41
# UNKNOWN_A7-NEXT: Section 1 {
# UNKNOWN_A7-NEXT: SectionLength: 17
# UNKNOWN_A7-NEXT: Vendor: riscv
# UNKNOWN_A7-NEXT: Tag: Tag_File (0x1)
# UNKNOWN_A7-NEXT: Size: 7
# UNKNOWN_A7-NEXT: FileAttributes {
# UNKNOWN_A7-NEXT: Attribute {
# UNKNOWN_A7-NEXT: Tag: 14
# UNKNOWN_A7-NEXT: Value: 3
# UNKNOWN_A7-NEXT: TagName: atomic_abi
# UNKNOWN_A7-NEXT: Description: Atomic ABI is 3
# UNKNOWN_A7-NEXT: }
# UNKNOWN_A7-NEXT: }
# UNKNOWN_A7-NEXT: }
# UNKNOWN_A7-NEXT: }

# A6C_A6S: BuildAttributes {
# A6C_A6S-NEXT: FormatVersion: 0x41
# A6C_A6S-NEXT: Section 1 {
# A6C_A6S-NEXT: SectionLength: 17
# A6C_A6S-NEXT: Vendor: riscv
# A6C_A6S-NEXT: Tag: Tag_File (0x1)
# A6C_A6S-NEXT: Size: 7
# A6C_A6S-NEXT: FileAttributes {
# A6C_A6S-NEXT: Attribute {
# A6C_A6S-NEXT: Tag: 14
# A6C_A6S-NEXT: Value: 1
# A6C_A6S-NEXT: TagName: atomic_abi
# A6C_A6S-NEXT: Description: Atomic ABI is 1
# A6C_A6S-NEXT: }
# A6C_A6S-NEXT: }
# A6C_A6S-NEXT: }
# A6C_A6S-NEXT: }

# A6S_A7: BuildAttributes {
# A6S_A7-NEXT: FormatVersion: 0x41
# A6S_A7-NEXT: Section 1 {
# A6S_A7-NEXT: SectionLength: 17
# A6S_A7-NEXT: Vendor: riscv
# A6S_A7-NEXT: Tag: Tag_File (0x1)
# A6S_A7-NEXT: Size: 7
# A6S_A7-NEXT: FileAttributes {
# A6S_A7-NEXT: Attribute {
# A6S_A7-NEXT: Tag: 14
# A6S_A7-NEXT: Value: 3
# A6S_A7-NEXT: TagName: atomic_abi
# A6S_A7-NEXT: Description: Atomic ABI is 3
# A6S_A7-NEXT: }
# A6S_A7-NEXT: }
# A6S_A7-NEXT: }
# A6S_A7-NEXT: }

#--- unknown13.s
.attribute 13, "0"
#--- unknown13a.s
Expand Down
Loading