1 //===- llvm/MC/MCWinCOFFStreamer.cpp --------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains an implementation of a Windows COFF object file streamer. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/SmallString.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/Triple.h" 17 #include "llvm/ADT/Twine.h" 18 #include "llvm/BinaryFormat/COFF.h" 19 #include "llvm/MC/MCAsmBackend.h" 20 #include "llvm/MC/MCAssembler.h" 21 #include "llvm/MC/MCCodeEmitter.h" 22 #include "llvm/MC/MCContext.h" 23 #include "llvm/MC/MCExpr.h" 24 #include "llvm/MC/MCFixup.h" 25 #include "llvm/MC/MCFragment.h" 26 #include "llvm/MC/MCObjectFileInfo.h" 27 #include "llvm/MC/MCObjectStreamer.h" 28 #include "llvm/MC/MCObjectWriter.h" 29 #include "llvm/MC/MCSection.h" 30 #include "llvm/MC/MCSymbolCOFF.h" 31 #include "llvm/MC/MCWinCOFFStreamer.h" 32 #include "llvm/Support/Casting.h" 33 #include "llvm/Support/ErrorHandling.h" 34 #include "llvm/Support/MathExtras.h" 35 #include "llvm/Support/SMLoc.h" 36 #include "llvm/Support/raw_ostream.h" 37 #include <algorithm> 38 #include <cassert> 39 #include <cstdint> 40 41 using namespace llvm; 42 43 #define DEBUG_TYPE "WinCOFFStreamer" 44 45 MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context, 46 std::unique_ptr<MCAsmBackend> MAB, 47 std::unique_ptr<MCCodeEmitter> CE, 48 std::unique_ptr<MCObjectWriter> OW) 49 : MCObjectStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)), 50 CurSymbol(nullptr) {} 51 52 void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst, 53 const MCSubtargetInfo &STI) { 54 MCDataFragment *DF = getOrCreateDataFragment(); 55 56 SmallVector<MCFixup, 4> Fixups; 57 SmallString<256> Code; 58 raw_svector_ostream VecOS(Code); 59 getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); 60 61 // Add the fixups and data. 62 for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { 63 Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); 64 DF->getFixups().push_back(Fixups[i]); 65 } 66 DF->setHasInstructions(STI); 67 DF->getContents().append(Code.begin(), Code.end()); 68 } 69 70 void MCWinCOFFStreamer::InitSections(bool NoExecStack) { 71 // FIXME: this is identical to the ELF one. 72 // This emulates the same behavior of GNU as. This makes it easier 73 // to compare the output as the major sections are in the same order. 74 SwitchSection(getContext().getObjectFileInfo()->getTextSection()); 75 EmitCodeAlignment(4); 76 77 SwitchSection(getContext().getObjectFileInfo()->getDataSection()); 78 EmitCodeAlignment(4); 79 80 SwitchSection(getContext().getObjectFileInfo()->getBSSSection()); 81 EmitCodeAlignment(4); 82 83 SwitchSection(getContext().getObjectFileInfo()->getTextSection()); 84 } 85 86 void MCWinCOFFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc) { 87 auto *Symbol = cast<MCSymbolCOFF>(S); 88 MCObjectStreamer::EmitLabel(Symbol, Loc); 89 } 90 91 void MCWinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { 92 llvm_unreachable("not implemented"); 93 } 94 95 void MCWinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) { 96 llvm_unreachable("not implemented"); 97 } 98 99 bool MCWinCOFFStreamer::EmitSymbolAttribute(MCSymbol *S, 100 MCSymbolAttr Attribute) { 101 auto *Symbol = cast<MCSymbolCOFF>(S); 102 getAssembler().registerSymbol(*Symbol); 103 104 switch (Attribute) { 105 default: return false; 106 case MCSA_WeakReference: 107 case MCSA_Weak: 108 Symbol->setIsWeakExternal(); 109 Symbol->setExternal(true); 110 break; 111 case MCSA_Global: 112 Symbol->setExternal(true); 113 break; 114 case MCSA_AltEntry: 115 llvm_unreachable("COFF doesn't support the .alt_entry attribute"); 116 } 117 118 return true; 119 } 120 121 void MCWinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { 122 llvm_unreachable("not implemented"); 123 } 124 125 void MCWinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *S) { 126 auto *Symbol = cast<MCSymbolCOFF>(S); 127 if (CurSymbol) 128 Error("starting a new symbol definition without completing the " 129 "previous one"); 130 CurSymbol = Symbol; 131 } 132 133 void MCWinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { 134 if (!CurSymbol) { 135 Error("storage class specified outside of symbol definition"); 136 return; 137 } 138 139 if (StorageClass & ~COFF::SSC_Invalid) { 140 Error("storage class value '" + Twine(StorageClass) + 141 "' out of range"); 142 return; 143 } 144 145 getAssembler().registerSymbol(*CurSymbol); 146 cast<MCSymbolCOFF>(CurSymbol)->setClass((uint16_t)StorageClass); 147 } 148 149 void MCWinCOFFStreamer::EmitCOFFSymbolType(int Type) { 150 if (!CurSymbol) { 151 Error("symbol type specified outside of a symbol definition"); 152 return; 153 } 154 155 if (Type & ~0xffff) { 156 Error("type value '" + Twine(Type) + "' out of range"); 157 return; 158 } 159 160 getAssembler().registerSymbol(*CurSymbol); 161 cast<MCSymbolCOFF>(CurSymbol)->setType((uint16_t)Type); 162 } 163 164 void MCWinCOFFStreamer::EndCOFFSymbolDef() { 165 if (!CurSymbol) 166 Error("ending symbol definition without starting one"); 167 CurSymbol = nullptr; 168 } 169 170 void MCWinCOFFStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { 171 // SafeSEH is a feature specific to 32-bit x86. It does not exist (and is 172 // unnecessary) on all platforms which use table-based exception dispatch. 173 if (getContext().getObjectFileInfo()->getTargetTriple().getArch() != 174 Triple::x86) 175 return; 176 177 const MCSymbolCOFF *CSymbol = cast<MCSymbolCOFF>(Symbol); 178 if (CSymbol->isSafeSEH()) 179 return; 180 181 MCSection *SXData = getContext().getObjectFileInfo()->getSXDataSection(); 182 getAssembler().registerSection(*SXData); 183 if (SXData->getAlignment() < 4) 184 SXData->setAlignment(4); 185 186 new MCSymbolIdFragment(Symbol, SXData); 187 188 getAssembler().registerSymbol(*Symbol); 189 CSymbol->setIsSafeSEH(); 190 191 // The Microsoft linker requires that the symbol type of a handler be 192 // function. Go ahead and oblige it here. 193 CSymbol->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION 194 << COFF::SCT_COMPLEX_TYPE_SHIFT); 195 } 196 197 void MCWinCOFFStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) { 198 MCSection *Sec = getCurrentSectionOnly(); 199 getAssembler().registerSection(*Sec); 200 if (Sec->getAlignment() < 4) 201 Sec->setAlignment(4); 202 203 new MCSymbolIdFragment(Symbol, getCurrentSectionOnly()); 204 205 getAssembler().registerSymbol(*Symbol); 206 } 207 208 void MCWinCOFFStreamer::EmitCOFFSectionIndex(const MCSymbol *Symbol) { 209 visitUsedSymbol(*Symbol); 210 MCDataFragment *DF = getOrCreateDataFragment(); 211 const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext()); 212 MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, FK_SecRel_2); 213 DF->getFixups().push_back(Fixup); 214 DF->getContents().resize(DF->getContents().size() + 2, 0); 215 } 216 217 void MCWinCOFFStreamer::EmitCOFFSecRel32(const MCSymbol *Symbol, 218 uint64_t Offset) { 219 visitUsedSymbol(*Symbol); 220 MCDataFragment *DF = getOrCreateDataFragment(); 221 // Create Symbol A for the relocation relative reference. 222 const MCExpr *MCE = MCSymbolRefExpr::create(Symbol, getContext()); 223 // Add the constant offset, if given. 224 if (Offset) 225 MCE = MCBinaryExpr::createAdd( 226 MCE, MCConstantExpr::create(Offset, getContext()), getContext()); 227 // Build the secrel32 relocation. 228 MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_SecRel_4); 229 // Record the relocation. 230 DF->getFixups().push_back(Fixup); 231 // Emit 4 bytes (zeros) to the object file. 232 DF->getContents().resize(DF->getContents().size() + 4, 0); 233 } 234 235 void MCWinCOFFStreamer::EmitCOFFImgRel32(const MCSymbol *Symbol, 236 int64_t Offset) { 237 visitUsedSymbol(*Symbol); 238 MCDataFragment *DF = getOrCreateDataFragment(); 239 // Create Symbol A for the relocation relative reference. 240 const MCExpr *MCE = MCSymbolRefExpr::create( 241 Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32, getContext()); 242 // Add the constant offset, if given. 243 if (Offset) 244 MCE = MCBinaryExpr::createAdd( 245 MCE, MCConstantExpr::create(Offset, getContext()), getContext()); 246 // Build the imgrel relocation. 247 MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_Data_4); 248 // Record the relocation. 249 DF->getFixups().push_back(Fixup); 250 // Emit 4 bytes (zeros) to the object file. 251 DF->getContents().resize(DF->getContents().size() + 4, 0); 252 } 253 254 void MCWinCOFFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, 255 unsigned ByteAlignment) { 256 auto *Symbol = cast<MCSymbolCOFF>(S); 257 258 const Triple &T = getContext().getObjectFileInfo()->getTargetTriple(); 259 if (T.isKnownWindowsMSVCEnvironment()) { 260 if (ByteAlignment > 32) 261 report_fatal_error("alignment is limited to 32-bytes"); 262 263 // Round size up to alignment so that we will honor the alignment request. 264 Size = std::max(Size, static_cast<uint64_t>(ByteAlignment)); 265 } 266 267 getAssembler().registerSymbol(*Symbol); 268 Symbol->setExternal(true); 269 Symbol->setCommon(Size, ByteAlignment); 270 271 if (!T.isKnownWindowsMSVCEnvironment() && ByteAlignment > 1) { 272 SmallString<128> Directive; 273 raw_svector_ostream OS(Directive); 274 const MCObjectFileInfo *MFI = getContext().getObjectFileInfo(); 275 276 OS << " -aligncomm:\"" << Symbol->getName() << "\"," 277 << Log2_32_Ceil(ByteAlignment); 278 279 PushSection(); 280 SwitchSection(MFI->getDrectveSection()); 281 EmitBytes(Directive); 282 PopSection(); 283 } 284 } 285 286 void MCWinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size, 287 unsigned ByteAlignment) { 288 auto *Symbol = cast<MCSymbolCOFF>(S); 289 290 MCSection *Section = getContext().getObjectFileInfo()->getBSSSection(); 291 PushSection(); 292 SwitchSection(Section); 293 EmitValueToAlignment(ByteAlignment, 0, 1, 0); 294 EmitLabel(Symbol); 295 Symbol->setExternal(false); 296 EmitZeros(Size); 297 PopSection(); 298 } 299 300 void MCWinCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, 301 uint64_t Size, unsigned ByteAlignment, 302 SMLoc Loc) { 303 llvm_unreachable("not implemented"); 304 } 305 306 void MCWinCOFFStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, 307 uint64_t Size, unsigned ByteAlignment) { 308 llvm_unreachable("not implemented"); 309 } 310 311 // TODO: Implement this if you want to emit .comment section in COFF obj files. 312 void MCWinCOFFStreamer::EmitIdent(StringRef IdentString) { 313 llvm_unreachable("not implemented"); 314 } 315 316 void MCWinCOFFStreamer::EmitWinEHHandlerData(SMLoc Loc) { 317 llvm_unreachable("not implemented"); 318 } 319 320 void MCWinCOFFStreamer::FinishImpl() { 321 MCObjectStreamer::FinishImpl(); 322 } 323 324 void MCWinCOFFStreamer::Error(const Twine &Msg) const { 325 getContext().reportError(SMLoc(), Msg); 326 } 327