MC: Overhaul handling of .lcomm

- Darwin lied about not supporting .lcomm and turned it into zerofill in the
  asm parser. Push the zerofill-conversion down into macho-specific code.
- This makes the tri-state LCOMMType enum superfluous, there are no targets
  without .lcomm.
- Do proper error reporting when trying to use .lcomm with alignment on a target
  that doesn't support it.
- .comm and .lcomm alignment was parsed in bytes on COFF, should be power of 2.
- Fixes PR13755 (.lcomm crashes on ELF).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@163395 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Benjamin Kramer 2012-09-07 17:25:13 +00:00
parent 8e70b5506e
commit 39646d96e7
14 changed files with 67 additions and 38 deletions

View File

@ -32,10 +32,6 @@ namespace llvm {
enum ExceptionsType { None, DwarfCFI, SjLj, ARM, Win64 };
}
namespace LCOMM {
enum LCOMMType { None, NoAlignment, ByteAlignment };
}
/// MCAsmInfo - This class is intended to be used as a base class for asm
/// properties and features specific to the target.
class MCAsmInfo {
@ -247,14 +243,14 @@ namespace llvm {
/// .long a - b
bool HasAggressiveSymbolFolding; // Defaults to true.
/// LCOMMDirectiveType - Describes if the target supports the .lcomm
/// directive and whether it has an alignment parameter.
LCOMM::LCOMMType LCOMMDirectiveType; // Defaults to LCOMM::None.
/// COMMDirectiveAlignmentIsInBytes - True is COMMDirective's optional
/// COMMDirectiveAlignmentIsInBytes - True is .comm's and .lcomms optional
/// alignment is to be specified in bytes instead of log2(n).
bool COMMDirectiveAlignmentIsInBytes; // Defaults to true;
/// LCOMMDirectiveSupportsAlignment - True if .lcomm supports an optional
/// alignment argument on this target.
bool LCOMMDirectiveSupportsAlignment; // Defaults to false.
/// HasDotTypeDotSizeDirective - True if the target has .type and .size
/// directives, this is true for most ELF targets.
bool HasDotTypeDotSizeDirective; // Defaults to true.
@ -496,13 +492,13 @@ namespace llvm {
bool hasAggressiveSymbolFolding() const {
return HasAggressiveSymbolFolding;
}
LCOMM::LCOMMType getLCOMMDirectiveType() const {
return LCOMMDirectiveType;
}
bool hasDotTypeDotSizeDirective() const {return HasDotTypeDotSizeDirective;}
bool getCOMMDirectiveAlignmentIsInBytes() const {
return COMMDirectiveAlignmentIsInBytes;
}
bool getLCOMMDirectiveSupportsAlignment() const {
return LCOMMDirectiveSupportsAlignment;
}
bool hasDotTypeDotSizeDirective() const {return HasDotTypeDotSizeDirective;}
bool hasSingleParameterDotFile() const { return HasSingleParameterDotFile; }
bool hasNoDeadStrip() const { return HasNoDeadStrip; }
bool hasSymbolResolver() const { return HasSymbolResolver; }

View File

@ -312,8 +312,7 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
return;
}
if (MAI->getLCOMMDirectiveType() != LCOMM::None &&
(MAI->getLCOMMDirectiveType() != LCOMM::NoAlignment || Align == 1)) {
if (Align == 1 || MAI->getLCOMMDirectiveSupportsAlignment()) {
// .lcomm _foo, 42
OutStreamer.EmitLocalCommonSymbol(GVSym, Size, Align);
return;

View File

@ -68,8 +68,8 @@ MCAsmInfo::MCAsmInfo() {
GlobalDirective = "\t.globl\t";
HasSetDirective = true;
HasAggressiveSymbolFolding = true;
LCOMMDirectiveType = LCOMM::None;
COMMDirectiveAlignmentIsInBytes = true;
LCOMMDirectiveSupportsAlignment = false;
HasDotTypeDotSizeDirective = true;
HasSingleParameterDotFile = true;
HasNoDeadStrip = false;

View File

@ -20,7 +20,7 @@ void MCAsmInfoCOFF::anchor() { }
MCAsmInfoCOFF::MCAsmInfoCOFF() {
GlobalPrefix = "_";
COMMDirectiveAlignmentIsInBytes = false;
LCOMMDirectiveType = LCOMM::ByteAlignment;
LCOMMDirectiveSupportsAlignment = true;
HasDotTypeDotSizeDirective = false;
HasSingleParameterDotFile = false;
PrivateGlobalPrefix = "L"; // Prefix for private global symbols

View File

@ -32,6 +32,7 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() {
AlignmentIsInBytes = false;
COMMDirectiveAlignmentIsInBytes = false;
LCOMMDirectiveSupportsAlignment = true;
InlineAsmStart = " InlineAsm Start";
InlineAsmEnd = " InlineAsm End";

View File

@ -517,13 +517,16 @@ void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
/// @param Size - The size of the common symbol.
void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlign) {
assert(MAI.getLCOMMDirectiveType() != LCOMM::None &&
"Doesn't have .lcomm, can't emit it!");
OS << "\t.lcomm\t" << *Symbol << ',' << Size;
if (ByteAlign > 1) {
assert(MAI.getLCOMMDirectiveType() == LCOMM::ByteAlignment &&
"Alignment not supported on .lcomm!");
OS << ',' << ByteAlign;
assert(MAI.getLCOMMDirectiveSupportsAlignment() &&
"alignment not supported on .lcomm!");
if (MAI.getCOMMDirectiveAlignmentIsInBytes()) {
OS << ',' << ByteAlign;
} else {
assert(isPowerOf2_32(ByteAlign) && "alignment must be a power of 2");
OS << ',' << Log2_32(ByteAlign);
}
}
EmitEOL();
}

View File

@ -70,9 +70,7 @@ public:
llvm_unreachable("macho doesn't support this directive");
}
virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment) {
llvm_unreachable("macho doesn't support this directive");
}
unsigned ByteAlignment);
virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
uint64_t Size = 0, unsigned ByteAlignment = 0);
virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
@ -325,6 +323,15 @@ void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
SD.setCommon(Size, ByteAlignment);
}
void MCMachOStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment) {
// '.lcomm' is equivalent to '.zerofill'.
return EmitZerofill(getContext().getMachOSection("__DATA", "__bss",
MCSectionMachO::S_ZEROFILL,
0, SectionKind::getBSS()),
Symbol, Size, ByteAlignment);
}
void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
uint64_t Size, unsigned ByteAlignment) {
MCSectionData &SectData = getAssembler().getOrCreateSectionData(*Section);

View File

@ -2280,8 +2280,11 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) {
if (ParseAbsoluteExpression(Pow2Alignment))
return true;
if (IsLocal && !Lexer.getMAI().getLCOMMDirectiveSupportsAlignment())
return Error(Pow2AlignmentLoc, "alignment not supported on this target");
// If this target takes alignments in bytes (not log) validate and convert.
if (Lexer.getMAI().getAlignmentIsInBytes()) {
if (Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) {
if (!isPowerOf2_64(Pow2Alignment))
return Error(Pow2AlignmentLoc, "alignment must be a power of 2");
Pow2Alignment = Log2_64(Pow2Alignment);
@ -2309,13 +2312,9 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) {
if (!Sym->isUndefined())
return Error(IDLoc, "invalid symbol redefinition");
// '.lcomm' is equivalent to '.zerofill'.
// Create the Symbol as a common or local common with Size and Pow2Alignment
if (IsLocal) {
getStreamer().EmitZerofill(Ctx.getMachOSection(
"__DATA", "__bss", MCSectionMachO::S_ZEROFILL,
0, SectionKind::getBSS()),
Sym, Size, 1 << Pow2Alignment);
getStreamer().EmitLocalCommonSymbol(Sym, Size, 1 << Pow2Alignment);
return false;
}

View File

@ -50,7 +50,6 @@ ARMELFMCAsmInfo::ARMELFMCAsmInfo() {
Code32Directive = ".code\t32";
WeakRefDirective = "\t.weak\t";
LCOMMDirectiveType = LCOMM::NoAlignment;
HasLEB128 = true;
SupportsDebugInformation = true;

View File

@ -24,7 +24,7 @@ HexagonMCAsmInfo::HexagonMCAsmInfo(const Target &T, StringRef TT) {
HasLEB128 = true;
PrivateGlobalPrefix = ".L";
LCOMMDirectiveType = LCOMM::ByteAlignment;
LCOMMDirectiveSupportsAlignment = true;
InlineAsmStart = "# InlineAsm Start";
InlineAsmEnd = "# InlineAsm End";
ZeroDirective = "\t.space\t";

View File

@ -64,7 +64,6 @@ PPCLinuxMCAsmInfo::PPCLinuxMCAsmInfo(bool is64Bit) {
ZeroDirective = "\t.space\t";
Data64bitsDirective = is64Bit ? "\t.quad\t" : 0;
LCOMMDirectiveType = LCOMM::NoAlignment;
AssemblerDialect = 0; // Old-Style mnemonics.
}

View File

@ -1,9 +1,14 @@
# RUN: llvm-mc -triple i386-apple-darwin10 %s | FileCheck %s
# RUN: llvm-mc -triple i386-pc-mingw32 %s | FileCheck %s
# RUN: not llvm-mc -triple i386-linux-gnu %s 2>&1 | FileCheck %s -check-prefix=ERROR
# CHECK: TEST0:
# CHECK: .zerofill __DATA,__bss,a,7,4
# CHECK: .zerofill __DATA,__bss,b,8
# CHECK: .zerofill __DATA,__bss,c,0
# CHECK: .lcomm a,7,4
# CHECK: .lcomm b,8
# CHECK: .lcomm c,0
# ELF doesn't like alignment on .lcomm.
# ERROR: alignment not supported on this target
TEST0:
.lcomm a, 8-1, 4
.lcomm b,8

View File

@ -41,7 +41,7 @@ foo:
// CHECK: .comm "a 6",1
.comm "a 6", 1
// CHECK: .zerofill __DATA,__bss,"a 7",1,0
// CHECK: .lcomm "a 7",1
.lcomm "a 7", 1
// FIXME: We don't bother to support .lsym.

21
test/MC/ELF/lcomm.s Normal file
View File

@ -0,0 +1,21 @@
// RUN: llvm-mc -triple i386-pc-linux-gnu %s -filetype=obj -o - | elf-dump | FileCheck %s
.lcomm A, 5
.lcomm B, 32 << 20
// CHECK: (('st_name', 0x00000001) # 'A'
// CHECK: ('st_value', 0x00000000)
// CHECK: ('st_size', 0x00000005)
// CHECK: ('st_bind', 0x0)
// CHECK: ('st_type', 0x1)
// CHECK: ('st_other', 0x00)
// CHECK: ('st_shndx', 0x0003)
// CHECK: ),
// CHECK: (('st_name', 0x00000003) # 'B'
// CHECK: ('st_value', 0x00000005)
// CHECK: ('st_size', 0x02000000)
// CHECK: ('st_bind', 0x0)
// CHECK: ('st_type', 0x1)
// CHECK: ('st_other', 0x00)
// CHECK: ('st_shndx', 0x0003)
// CHECK: ),