From 8f4d146c340c9423271ebd7bb3fd32b880000bc9 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Fri, 28 Aug 2009 07:08:35 +0000 Subject: [PATCH] llvm-mc: Support .comm emission. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80351 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCAssembler.h | 37 ++++++++++- lib/MC/MCAssembler.cpp | 46 ++++++++++---- lib/MC/MCMachOStreamer.cpp | 9 ++- test/MC/MachO/comm-1.s | 114 ++++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+), 15 deletions(-) create mode 100644 test/MC/MachO/comm-1.s diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 4b66159d4dc..182d2fe4d0a 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -452,6 +452,17 @@ public: /// IsPrivateExtern - True if this symbol is private extern. unsigned IsPrivateExtern : 1; + /// CommonSize - The size of the symbol, if it is 'common', or 0. + // + // FIXME: Pack this in with other fields? We could put it in offset, since a + // common symbol can never get a definition. + uint64_t CommonSize; + + /// CommonAlign - The alignment of the symbol, if it is 'common'. + // + // FIXME: Pack this in with other fields? + unsigned CommonAlign; + /// Flags - The Flags field is used by object file implementations to store /// additional per symbol information which is not easily classified. uint32_t Flags; @@ -485,7 +496,31 @@ public: bool isPrivateExtern() const { return IsPrivateExtern; } void setPrivateExtern(bool Value) { IsPrivateExtern = Value; } - + + /// isCommon - Is this a 'common' symbol. + bool isCommon() const { return CommonSize != 0; } + + /// setCommon - Mark this symbol as being 'common'. + /// + /// \param Size - The size of the symbol. + /// \param Align - The alignment of the symbol. + void setCommon(uint64_t Size, unsigned Align) { + CommonSize = Size; + CommonAlign = Align; + } + + /// getCommonSize - Return the size of a 'common' symbol. + uint64_t getCommonSize() const { + assert(isCommon() && "Not a 'common' symbol!"); + return CommonSize; + } + + /// getCommonAlignment - Return the alignment of a 'common' symbol. + unsigned getCommonAlignment() const { + assert(isCommon() && "Not a 'common' symbol!"); + return CommonAlign; + } + /// getFlags - Get the (implementation defined) symbol flags. uint32_t getFlags() const { return Flags; } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 8057fcb3593..0d9b540d15e 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -25,6 +25,11 @@ class MachObjectWriter; STATISTIC(EmittedFragments, "Number of emitted assembler fragments"); +// FIXME FIXME FIXME: There are number of places in this file where we convert +// what is a 64-bit assembler value used for computation into a value in the +// object file, which may truncate it. We should detect that truncation where +// invalid and report errors back. + static void WriteFileData(raw_ostream &OS, const MCSectionData &SD, MachObjectWriter &MOW); @@ -328,6 +333,8 @@ public: MCSymbolData &Data = *MSD.SymbolData; MCSymbol &Symbol = Data.getSymbol(); uint8_t Type = 0; + uint16_t Flags = Data.getFlags(); + uint32_t Address = 0; // Set the N_TYPE bits. See . // @@ -348,6 +355,30 @@ public: if (Data.isExternal() || Symbol.isUndefined()) Type |= STF_External; + // Compute the symbol address. + if (Symbol.isDefined()) { + if (Symbol.isAbsolute()) { + llvm_unreachable("FIXME: Not yet implemented!"); + } else { + Address = Data.getFragment()->getAddress() + Data.getOffset(); + } + } else if (Data.isCommon()) { + // Common symbols are encoded with the size in the address + // field, and their alignment in the flags. + Address = Data.getCommonSize(); + + // Common alignment is packed into the 'desc' bits. + if (unsigned Align = Data.getCommonAlignment()) { + unsigned Log2Size = Log2_32(Align); + assert((1U << Log2Size) == Align && "Invalid 'common' alignment!"); + if (Log2Size > 15) + llvm_report_error("invalid 'common' alignment '" + + Twine(Align) + "'"); + // FIXME: Keep this mask with the SymbolFlags enumeration. + Flags = (Flags & 0xF0FF) | (Log2Size << 8); + } + } + // struct nlist (12 bytes) Write32(MSD.StringIndex); @@ -356,17 +387,7 @@ public: // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' // value. - Write16(Data.getFlags() & 0xFFFF); - - // Write the symbol address. - uint32_t Address = 0; - if (Symbol.isDefined()) { - if (Symbol.isAbsolute()) { - llvm_unreachable("FIXME: Not yet implemented!"); - } else { - Address = Data.getFragment()->getAddress() + Data.getOffset(); - } - } + Write16(Flags); Write32(Address); } @@ -910,7 +931,8 @@ MCSymbolData::MCSymbolData() : Symbol(*(MCSymbol*)0) {} MCSymbolData::MCSymbolData(MCSymbol &_Symbol, MCFragment *_Fragment, uint64_t _Offset, MCAssembler *A) : Symbol(_Symbol), Fragment(_Fragment), Offset(_Offset), - IsExternal(false), IsPrivateExtern(false), Flags(0), Index(0) + IsExternal(false), IsPrivateExtern(false), + CommonSize(0), CommonAlign(0), Flags(0), Index(0) { if (A) A->getSymbolList().push_back(this); diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index b53a82e9586..e9722251c63 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -224,7 +224,7 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, break; case MCStreamer::Global: - getSymbolData(*Symbol).setExternal(true); + SD.setExternal(true); break; case MCStreamer::LazyReference: @@ -273,7 +273,12 @@ void MCMachOStreamer::EmitLocalSymbol(MCSymbol *Symbol, const MCValue &Value) { void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, unsigned Pow2Alignment) { - llvm_unreachable("FIXME: Not yet implemented!"); + // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself. + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + + MCSymbolData &SD = getSymbolData(*Symbol); + SD.setExternal(true); + SD.setCommon(Size, 1 << Pow2Alignment); } void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, diff --git a/test/MC/MachO/comm-1.s b/test/MC/MachO/comm-1.s new file mode 100644 index 00000000000..e979fb13920 --- /dev/null +++ b/test/MC/MachO/comm-1.s @@ -0,0 +1,114 @@ +// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s + + .comm sym_comm_B, 2 + .comm sym_comm_A, 4 + .comm sym_comm_C, 8, 2 + .comm sym_comm_D, 2, 3 + + .no_dead_strip sym_comm_C + +// CHECK: ('cputype', 7) +// CHECK: ('cpusubtype', 3) +// CHECK: ('filetype', 1) +// CHECK: ('num_load_commands', 1) +// CHECK: ('load_commands_size', 228) +// CHECK: ('flag', 0) +// CHECK: ('load_commands', [ +// CHECK: # Load Command 0 +// CHECK: (('command', 1) +// CHECK: ('size', 124) +// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('vm_addr', 0) +// CHECK: ('vm_size', 0) +// CHECK: ('file_offset', 256) +// CHECK: ('file_size', 0) +// CHECK: ('maxprot', 7) +// CHECK: ('initprot', 7) +// CHECK: ('num_sections', 1) +// CHECK: ('flags', 0) +// CHECK: ('sections', [ +// CHECK: # Section 0 +// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 256) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 1 +// CHECK: (('command', 2) +// CHECK: ('size', 24) +// CHECK: ('symoff', 256) +// CHECK: ('nsyms', 4) +// CHECK: ('stroff', 304) +// CHECK: ('strsize', 48) +// CHECK: ('_string_data', '\x00sym_comm_B\x00sym_comm_A\x00sym_comm_C\x00sym_comm_D\x00\x00\x00\x00') +// CHECK: ('_symbols', [ +// CHECK: # Symbol 0 +// CHECK: (('n_strx', 12) +// CHECK: ('n_type', 0x1) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 4) +// CHECK: ('_string', 'sym_comm_A') +// CHECK: ), +// CHECK: # Symbol 1 +// CHECK: (('n_strx', 1) +// CHECK: ('n_type', 0x1) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 2) +// CHECK: ('_string', 'sym_comm_B') +// CHECK: ), +// CHECK: # Symbol 2 +// CHECK: (('n_strx', 23) +// CHECK: ('n_type', 0x1) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 544) +// CHECK: ('n_value', 8) +// CHECK: ('_string', 'sym_comm_C') +// CHECK: ), +// CHECK: # Symbol 3 +// CHECK: (('n_strx', 34) +// CHECK: ('n_type', 0x1) +// CHECK: ('n_sect', 0) +// CHECK: ('n_desc', 768) +// CHECK: ('n_value', 2) +// CHECK: ('_string', 'sym_comm_D') +// CHECK: ), +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 2 +// CHECK: (('command', 11) +// CHECK: ('size', 80) +// CHECK: ('ilocalsym', 0) +// CHECK: ('nlocalsym', 0) +// CHECK: ('iextdefsym', 0) +// CHECK: ('nextdefsym', 0) +// CHECK: ('iundefsym', 0) +// CHECK: ('nundefsym', 4) +// CHECK: ('tocoff', 0) +// CHECK: ('ntoc', 0) +// CHECK: ('modtaboff', 0) +// CHECK: ('nmodtab', 0) +// CHECK: ('extrefsymoff', 0) +// CHECK: ('nextrefsyms', 0) +// CHECK: ('indirectsymoff', 0) +// CHECK: ('nindirectsyms', 0) +// CHECK: ('extreloff', 0) +// CHECK: ('nextrel', 0) +// CHECK: ('locreloff', 0) +// CHECK: ('nlocrel', 0) +// CHECK: ('_indirect_symbols', [ +// CHECK: ]) +// CHECK: ), +// CHECK: ])