//===- DarwinAsmParser.cpp - Darwin (Mach-O) Assembly Parser --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCAsmParserExtension.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/SectionKind.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Triple.h" #include #include #include #include #include using namespace llvm; namespace { /// Implementation of directive handling which is shared across all /// Darwin targets. class DarwinAsmParser : public MCAsmParserExtension { template void addDirectiveHandler(StringRef Directive) { MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( this, HandleDirective); getParser().addDirectiveHandler(Directive, Handler); } bool parseSectionSwitch(StringRef Segment, StringRef Section, unsigned TAA = 0, unsigned ImplicitAlign = 0, unsigned StubSize = 0); SMLoc LastVersionDirective; public: DarwinAsmParser() = default; void Initialize(MCAsmParser &Parser) override { // Call the base implementation. this->MCAsmParserExtension::Initialize(Parser); addDirectiveHandler<&DarwinAsmParser::parseDirectiveAltEntry>(".alt_entry"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveDesc>(".desc"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveIndirectSymbol>( ".indirect_symbol"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveLsym>(".lsym"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveSubsectionsViaSymbols>( ".subsections_via_symbols"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveDumpOrLoad>(".dump"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveDumpOrLoad>(".load"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveSection>(".section"); addDirectiveHandler<&DarwinAsmParser::parseDirectivePushSection>( ".pushsection"); addDirectiveHandler<&DarwinAsmParser::parseDirectivePopSection>( ".popsection"); addDirectiveHandler<&DarwinAsmParser::parseDirectivePrevious>(".previous"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveSecureLogUnique>( ".secure_log_unique"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveSecureLogReset>( ".secure_log_reset"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveTBSS>(".tbss"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveZerofill>(".zerofill"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveDataRegion>( ".data_region"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveDataRegionEnd>( ".end_data_region"); // Special section directives. addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveBss>(".bss"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConst>(".const"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConstData>( ".const_data"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConstructor>( ".constructor"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveCString>( ".cstring"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveData>(".data"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveDestructor>( ".destructor"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveDyld>(".dyld"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveFVMLibInit0>( ".fvmlib_init0"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveFVMLibInit1>( ".fvmlib_init1"); addDirectiveHandler< &DarwinAsmParser::parseSectionDirectiveLazySymbolPointers>( ".lazy_symbol_pointer"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveLinkerOption>( ".linker_option"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral16>( ".literal16"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral4>( ".literal4"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral8>( ".literal8"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveModInitFunc>( ".mod_init_func"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveModTermFunc>( ".mod_term_func"); addDirectiveHandler< &DarwinAsmParser::parseSectionDirectiveNonLazySymbolPointers>( ".non_lazy_symbol_pointer"); addDirectiveHandler< &DarwinAsmParser::parseSectionDirectiveThreadLocalVariablePointers>( ".thread_local_variable_pointer"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCatClsMeth>( ".objc_cat_cls_meth"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCatInstMeth>( ".objc_cat_inst_meth"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCategory>( ".objc_category"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClass>( ".objc_class"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClassNames>( ".objc_class_names"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClassVars>( ".objc_class_vars"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClsMeth>( ".objc_cls_meth"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClsRefs>( ".objc_cls_refs"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCInstMeth>( ".objc_inst_meth"); addDirectiveHandler< &DarwinAsmParser::parseSectionDirectiveObjCInstanceVars>( ".objc_instance_vars"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCMessageRefs>( ".objc_message_refs"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCMetaClass>( ".objc_meta_class"); addDirectiveHandler< &DarwinAsmParser::parseSectionDirectiveObjCMethVarNames>( ".objc_meth_var_names"); addDirectiveHandler< &DarwinAsmParser::parseSectionDirectiveObjCMethVarTypes>( ".objc_meth_var_types"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCModuleInfo>( ".objc_module_info"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCProtocol>( ".objc_protocol"); addDirectiveHandler< &DarwinAsmParser::parseSectionDirectiveObjCSelectorStrs>( ".objc_selector_strs"); addDirectiveHandler< &DarwinAsmParser::parseSectionDirectiveObjCStringObject>( ".objc_string_object"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCSymbols>( ".objc_symbols"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectivePICSymbolStub>( ".picsymbol_stub"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveStaticConst>( ".static_const"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveStaticData>( ".static_data"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveSymbolStub>( ".symbol_stub"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveTData>(".tdata"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveText>(".text"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveThreadInitFunc>( ".thread_init_func"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveTLV>(".tlv"); addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveIdent>(".ident"); addDirectiveHandler<&DarwinAsmParser::parseWatchOSVersionMin>( ".watchos_version_min"); addDirectiveHandler<&DarwinAsmParser::parseTvOSVersionMin>( ".tvos_version_min"); addDirectiveHandler<&DarwinAsmParser::parseIOSVersionMin>( ".ios_version_min"); addDirectiveHandler<&DarwinAsmParser::parseMacOSXVersionMin>( ".macosx_version_min"); addDirectiveHandler<&DarwinAsmParser::parseBuildVersion>(".build_version"); addDirectiveHandler<&DarwinAsmParser::parseDirectiveCGProfile>( ".cg_profile"); LastVersionDirective = SMLoc(); } bool parseDirectiveAltEntry(StringRef, SMLoc); bool parseDirectiveDesc(StringRef, SMLoc); bool parseDirectiveIndirectSymbol(StringRef, SMLoc); bool parseDirectiveDumpOrLoad(StringRef, SMLoc); bool parseDirectiveLsym(StringRef, SMLoc); bool parseDirectiveLinkerOption(StringRef, SMLoc); bool parseDirectiveSection(StringRef, SMLoc); bool parseDirectivePushSection(StringRef, SMLoc); bool parseDirectivePopSection(StringRef, SMLoc); bool parseDirectivePrevious(StringRef, SMLoc); bool parseDirectiveSecureLogReset(StringRef, SMLoc); bool parseDirectiveSecureLogUnique(StringRef, SMLoc); bool parseDirectiveSubsectionsViaSymbols(StringRef, SMLoc); bool parseDirectiveTBSS(StringRef, SMLoc); bool parseDirectiveZerofill(StringRef, SMLoc); bool parseDirectiveDataRegion(StringRef, SMLoc); bool parseDirectiveDataRegionEnd(StringRef, SMLoc); // Named Section Directive bool parseSectionDirectiveBss(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__bss"); } bool parseSectionDirectiveConst(StringRef, SMLoc) { return parseSectionSwitch("__TEXT", "__const"); } bool parseSectionDirectiveStaticConst(StringRef, SMLoc) { return parseSectionSwitch("__TEXT", "__static_const"); } bool parseSectionDirectiveCString(StringRef, SMLoc) { return parseSectionSwitch("__TEXT","__cstring", MachO::S_CSTRING_LITERALS); } bool parseSectionDirectiveLiteral4(StringRef, SMLoc) { return parseSectionSwitch("__TEXT", "__literal4", MachO::S_4BYTE_LITERALS, 4); } bool parseSectionDirectiveLiteral8(StringRef, SMLoc) { return parseSectionSwitch("__TEXT", "__literal8", MachO::S_8BYTE_LITERALS, 8); } bool parseSectionDirectiveLiteral16(StringRef, SMLoc) { return parseSectionSwitch("__TEXT","__literal16", MachO::S_16BYTE_LITERALS, 16); } bool parseSectionDirectiveConstructor(StringRef, SMLoc) { return parseSectionSwitch("__TEXT","__constructor"); } bool parseSectionDirectiveDestructor(StringRef, SMLoc) { return parseSectionSwitch("__TEXT","__destructor"); } bool parseSectionDirectiveFVMLibInit0(StringRef, SMLoc) { return parseSectionSwitch("__TEXT","__fvmlib_init0"); } bool parseSectionDirectiveFVMLibInit1(StringRef, SMLoc) { return parseSectionSwitch("__TEXT","__fvmlib_init1"); } bool parseSectionDirectiveSymbolStub(StringRef, SMLoc) { return parseSectionSwitch("__TEXT","__symbol_stub", MachO::S_SYMBOL_STUBS | MachO::S_ATTR_PURE_INSTRUCTIONS, // FIXME: Different on PPC and ARM. 0, 16); } bool parseSectionDirectivePICSymbolStub(StringRef, SMLoc) { return parseSectionSwitch("__TEXT","__picsymbol_stub", MachO::S_SYMBOL_STUBS | MachO::S_ATTR_PURE_INSTRUCTIONS, 0, 26); } bool parseSectionDirectiveData(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__data"); } bool parseSectionDirectiveStaticData(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__static_data"); } bool parseSectionDirectiveNonLazySymbolPointers(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__nl_symbol_ptr", MachO::S_NON_LAZY_SYMBOL_POINTERS, 4); } bool parseSectionDirectiveLazySymbolPointers(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__la_symbol_ptr", MachO::S_LAZY_SYMBOL_POINTERS, 4); } bool parseSectionDirectiveThreadLocalVariablePointers(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__thread_ptr", MachO::S_THREAD_LOCAL_VARIABLE_POINTERS, 4); } bool parseSectionDirectiveDyld(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__dyld"); } bool parseSectionDirectiveModInitFunc(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__mod_init_func", MachO::S_MOD_INIT_FUNC_POINTERS, 4); } bool parseSectionDirectiveModTermFunc(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__mod_term_func", MachO::S_MOD_TERM_FUNC_POINTERS, 4); } bool parseSectionDirectiveConstData(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__const"); } bool parseSectionDirectiveObjCClass(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__class", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCMetaClass(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__meta_class", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCCatClsMeth(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__cat_cls_meth", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCCatInstMeth(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__cat_inst_meth", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCProtocol(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__protocol", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCStringObject(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__string_object", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCClsMeth(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__cls_meth", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCInstMeth(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__inst_meth", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCClsRefs(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__cls_refs", MachO::S_ATTR_NO_DEAD_STRIP | MachO::S_LITERAL_POINTERS, 4); } bool parseSectionDirectiveObjCMessageRefs(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__message_refs", MachO::S_ATTR_NO_DEAD_STRIP | MachO::S_LITERAL_POINTERS, 4); } bool parseSectionDirectiveObjCSymbols(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__symbols", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCCategory(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__category", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCClassVars(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__class_vars", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCInstanceVars(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__instance_vars", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCModuleInfo(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__module_info", MachO::S_ATTR_NO_DEAD_STRIP); } bool parseSectionDirectiveObjCClassNames(StringRef, SMLoc) { return parseSectionSwitch("__TEXT", "__cstring", MachO::S_CSTRING_LITERALS); } bool parseSectionDirectiveObjCMethVarTypes(StringRef, SMLoc) { return parseSectionSwitch("__TEXT", "__cstring", MachO::S_CSTRING_LITERALS); } bool parseSectionDirectiveObjCMethVarNames(StringRef, SMLoc) { return parseSectionSwitch("__TEXT", "__cstring", MachO::S_CSTRING_LITERALS); } bool parseSectionDirectiveObjCSelectorStrs(StringRef, SMLoc) { return parseSectionSwitch("__OBJC", "__selector_strs", MachO::S_CSTRING_LITERALS); } bool parseSectionDirectiveTData(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__thread_data", MachO::S_THREAD_LOCAL_REGULAR); } bool parseSectionDirectiveText(StringRef, SMLoc) { return parseSectionSwitch("__TEXT", "__text", MachO::S_ATTR_PURE_INSTRUCTIONS); } bool parseSectionDirectiveTLV(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__thread_vars", MachO::S_THREAD_LOCAL_VARIABLES); } bool parseSectionDirectiveIdent(StringRef, SMLoc) { // Darwin silently ignores the .ident directive. getParser().eatToEndOfStatement(); return false; } bool parseSectionDirectiveThreadInitFunc(StringRef, SMLoc) { return parseSectionSwitch("__DATA", "__thread_init", MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS); } bool parseWatchOSVersionMin(StringRef Directive, SMLoc Loc) { return parseVersionMin(Directive, Loc, MCVM_WatchOSVersionMin); } bool parseTvOSVersionMin(StringRef Directive, SMLoc Loc) { return parseVersionMin(Directive, Loc, MCVM_TvOSVersionMin); } bool parseIOSVersionMin(StringRef Directive, SMLoc Loc) { return parseVersionMin(Directive, Loc, MCVM_IOSVersionMin); } bool parseMacOSXVersionMin(StringRef Directive, SMLoc Loc) { return parseVersionMin(Directive, Loc, MCVM_OSXVersionMin); } bool parseBuildVersion(StringRef Directive, SMLoc Loc); bool parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type); bool parseMajorMinorVersionComponent(unsigned *Major, unsigned *Minor, const char *VersionName); bool parseOptionalTrailingVersionComponent(unsigned *Component, const char *ComponentName); bool parseVersion(unsigned *Major, unsigned *Minor, unsigned *Update); bool parseSDKVersion(VersionTuple &SDKVersion); void checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc, Triple::OSType ExpectedOS); bool parseDirectiveCGProfile(StringRef Directive, SMLoc Loc); }; } // end anonymous namespace bool DarwinAsmParser::parseSectionSwitch(StringRef Segment, StringRef Section, unsigned TAA, unsigned Alignment, unsigned StubSize) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in section switching directive"); Lex(); // FIXME: Arch specific. bool isText = TAA & MachO::S_ATTR_PURE_INSTRUCTIONS; getStreamer().switchSection(getContext().getMachOSection( Segment, Section, TAA, StubSize, isText ? SectionKind::getText() : SectionKind::getData())); // Set the implicit alignment, if any. // // FIXME: This isn't really what 'as' does; I think it just uses the implicit // alignment on the section (e.g., if one manually inserts bytes into the // section, then just issuing the section switch directive will not realign // the section. However, this is arguably more reasonable behavior, and there // is no good reason for someone to intentionally emit incorrectly sized // values into the implicitly aligned sections. if (Alignment) getStreamer().emitValueToAlignment(Align(Alignment)); return false; } /// parseDirectiveAltEntry /// ::= .alt_entry identifier bool DarwinAsmParser::parseDirectiveAltEntry(StringRef, SMLoc) { StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); // Look up symbol. MCSymbol *Sym = getContext().getOrCreateSymbol(Name); if (Sym->isDefined()) return TokError(".alt_entry must preceed symbol definition"); if (!getStreamer().emitSymbolAttribute(Sym, MCSA_AltEntry)) return TokError("unable to emit symbol attribute"); Lex(); return false; } /// parseDirectiveDesc /// ::= .desc identifier , expression bool DarwinAsmParser::parseDirectiveDesc(StringRef, SMLoc) { StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); // Handle the identifier as the key symbol. MCSymbol *Sym = getContext().getOrCreateSymbol(Name); if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.desc' directive"); Lex(); int64_t DescValue; if (getParser().parseAbsoluteExpression(DescValue)) return true; if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.desc' directive"); Lex(); // Set the n_desc field of this Symbol to this DescValue getStreamer().emitSymbolDesc(Sym, DescValue); return false; } /// parseDirectiveIndirectSymbol /// ::= .indirect_symbol identifier bool DarwinAsmParser::parseDirectiveIndirectSymbol(StringRef, SMLoc Loc) { const MCSectionMachO *Current = static_cast( getStreamer().getCurrentSectionOnly()); MachO::SectionType SectionType = Current->getType(); if (SectionType != MachO::S_NON_LAZY_SYMBOL_POINTERS && SectionType != MachO::S_LAZY_SYMBOL_POINTERS && SectionType != MachO::S_THREAD_LOCAL_VARIABLE_POINTERS && SectionType != MachO::S_SYMBOL_STUBS) return Error(Loc, "indirect symbol not in a symbol pointer or stub " "section"); StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in .indirect_symbol directive"); MCSymbol *Sym = getContext().getOrCreateSymbol(Name); // Assembler local symbols don't make any sense here. Complain loudly. if (Sym->isTemporary()) return TokError("non-local symbol required in directive"); if (!getStreamer().emitSymbolAttribute(Sym, MCSA_IndirectSymbol)) return TokError("unable to emit indirect symbol attribute for: " + Name); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.indirect_symbol' directive"); Lex(); return false; } /// parseDirectiveDumpOrLoad /// ::= ( .dump | .load ) "filename" bool DarwinAsmParser::parseDirectiveDumpOrLoad(StringRef Directive, SMLoc IDLoc) { bool IsDump = Directive == ".dump"; if (getLexer().isNot(AsmToken::String)) return TokError("expected string in '.dump' or '.load' directive"); Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.dump' or '.load' directive"); Lex(); // FIXME: If/when .dump and .load are implemented they will be done in the // the assembly parser and not have any need for an MCStreamer API. if (IsDump) return Warning(IDLoc, "ignoring directive .dump for now"); else return Warning(IDLoc, "ignoring directive .load for now"); } /// ParseDirectiveLinkerOption /// ::= .linker_option "string" ( , "string" )* bool DarwinAsmParser::parseDirectiveLinkerOption(StringRef IDVal, SMLoc) { SmallVector Args; while (true) { if (getLexer().isNot(AsmToken::String)) return TokError("expected string in '" + Twine(IDVal) + "' directive"); std::string Data; if (getParser().parseEscapedString(Data)) return true; Args.push_back(Data); if (getLexer().is(AsmToken::EndOfStatement)) break; if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); Lex(); } getStreamer().emitLinkerOptions(Args); return false; } /// parseDirectiveLsym /// ::= .lsym identifier , expression bool DarwinAsmParser::parseDirectiveLsym(StringRef, SMLoc) { StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); // Handle the identifier as the key symbol. MCSymbol *Sym = getContext().getOrCreateSymbol(Name); if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.lsym' directive"); Lex(); const MCExpr *Value; if (getParser().parseExpression(Value)) return true; if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.lsym' directive"); Lex(); // We don't currently support this directive. // // FIXME: Diagnostic location! (void) Sym; return TokError("directive '.lsym' is unsupported"); } /// parseDirectiveSection: /// ::= .section identifier (',' identifier)* bool DarwinAsmParser::parseDirectiveSection(StringRef, SMLoc) { SMLoc Loc = getLexer().getLoc(); StringRef SectionName; if (getParser().parseIdentifier(SectionName)) return Error(Loc, "expected identifier after '.section' directive"); // Verify there is a following comma. if (!getLexer().is(AsmToken::Comma)) return TokError("unexpected token in '.section' directive"); std::string SectionSpec = std::string(SectionName); SectionSpec += ","; // Add all the tokens until the end of the line, ParseSectionSpecifier will // handle this. StringRef EOL = getLexer().LexUntilEndOfStatement(); SectionSpec.append(EOL.begin(), EOL.end()); Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.section' directive"); Lex(); StringRef Segment, Section; unsigned StubSize; unsigned TAA; bool TAAParsed; if (class Error E = MCSectionMachO::ParseSectionSpecifier( SectionSpec, Segment, Section, TAA, TAAParsed, StubSize)) return Error(Loc, toString(std::move(E))); // Issue a warning if the target is not powerpc and Section is a *coal* section. Triple TT = getParser().getContext().getTargetTriple(); Triple::ArchType ArchTy = TT.getArch(); if (ArchTy != Triple::ppc && ArchTy != Triple::ppc64) { StringRef NonCoalSection = StringSwitch(Section) .Case("__textcoal_nt", "__text") .Case("__const_coal", "__const") .Case("__datacoal_nt", "__data") .Default(Section); if (!Section.equals(NonCoalSection)) { StringRef SectionVal(Loc.getPointer()); size_t B = SectionVal.find(',') + 1, E = SectionVal.find(',', B); SMLoc BLoc = SMLoc::getFromPointer(SectionVal.data() + B); SMLoc ELoc = SMLoc::getFromPointer(SectionVal.data() + E); getParser().Warning(Loc, "section \"" + Section + "\" is deprecated", SMRange(BLoc, ELoc)); getParser().Note(Loc, "change section name to \"" + NonCoalSection + "\"", SMRange(BLoc, ELoc)); } } // FIXME: Arch specific. bool isText = Segment == "__TEXT"; // FIXME: Hack. getStreamer().switchSection(getContext().getMachOSection( Segment, Section, TAA, StubSize, isText ? SectionKind::getText() : SectionKind::getData())); return false; } /// ParseDirectivePushSection: /// ::= .pushsection identifier (',' identifier)* bool DarwinAsmParser::parseDirectivePushSection(StringRef S, SMLoc Loc) { getStreamer().pushSection(); if (parseDirectiveSection(S, Loc)) { getStreamer().popSection(); return true; } return false; } /// ParseDirectivePopSection: /// ::= .popsection bool DarwinAsmParser::parseDirectivePopSection(StringRef, SMLoc) { if (!getStreamer().popSection()) return TokError(".popsection without corresponding .pushsection"); return false; } /// ParseDirectivePrevious: /// ::= .previous bool DarwinAsmParser::parseDirectivePrevious(StringRef DirName, SMLoc) { MCSectionSubPair PreviousSection = getStreamer().getPreviousSection(); if (!PreviousSection.first) return TokError(".previous without corresponding .section"); getStreamer().switchSection(PreviousSection.first, PreviousSection.second); return false; } /// ParseDirectiveSecureLogUnique /// ::= .secure_log_unique ... message ... bool DarwinAsmParser::parseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) { StringRef LogMessage = getParser().parseStringToEndOfStatement(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.secure_log_unique' directive"); if (getContext().getSecureLogUsed()) return Error(IDLoc, ".secure_log_unique specified multiple times"); // Get the secure log path. StringRef SecureLogFile = getContext().getSecureLogFile(); if (SecureLogFile.empty()) return Error(IDLoc, ".secure_log_unique used but AS_SECURE_LOG_FILE " "environment variable unset."); // Open the secure log file if we haven't already. raw_fd_ostream *OS = getContext().getSecureLog(); if (!OS) { std::error_code EC; auto NewOS = std::make_unique( SecureLogFile, EC, sys::fs::OF_Append | sys::fs::OF_TextWithCRLF); if (EC) return Error(IDLoc, Twine("can't open secure log file: ") + SecureLogFile + " (" + EC.message() + ")"); OS = NewOS.get(); getContext().setSecureLog(std::move(NewOS)); } // Write the message. unsigned CurBuf = getSourceManager().FindBufferContainingLoc(IDLoc); *OS << getSourceManager().getBufferInfo(CurBuf).Buffer->getBufferIdentifier() << ":" << getSourceManager().FindLineNumber(IDLoc, CurBuf) << ":" << LogMessage + "\n"; getContext().setSecureLogUsed(true); return false; } /// ParseDirectiveSecureLogReset /// ::= .secure_log_reset bool DarwinAsmParser::parseDirectiveSecureLogReset(StringRef, SMLoc IDLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.secure_log_reset' directive"); Lex(); getContext().setSecureLogUsed(false); return false; } /// parseDirectiveSubsectionsViaSymbols /// ::= .subsections_via_symbols bool DarwinAsmParser::parseDirectiveSubsectionsViaSymbols(StringRef, SMLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.subsections_via_symbols' directive"); Lex(); getStreamer().emitAssemblerFlag(MCAF_SubsectionsViaSymbols); return false; } /// ParseDirectiveTBSS /// ::= .tbss identifier, size, align bool DarwinAsmParser::parseDirectiveTBSS(StringRef, SMLoc) { SMLoc IDLoc = getLexer().getLoc(); StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); // Handle the identifier as the key symbol. MCSymbol *Sym = getContext().getOrCreateSymbol(Name); if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lex(); int64_t Size; SMLoc SizeLoc = getLexer().getLoc(); if (getParser().parseAbsoluteExpression(Size)) return true; int64_t Pow2Alignment = 0; SMLoc Pow2AlignmentLoc; if (getLexer().is(AsmToken::Comma)) { Lex(); Pow2AlignmentLoc = getLexer().getLoc(); if (getParser().parseAbsoluteExpression(Pow2Alignment)) return true; } if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.tbss' directive"); Lex(); if (Size < 0) return Error(SizeLoc, "invalid '.tbss' directive size, can't be less than" "zero"); // FIXME: Diagnose overflow. if (Pow2Alignment < 0) return Error(Pow2AlignmentLoc, "invalid '.tbss' alignment, can't be less" "than zero"); if (!Sym->isUndefined()) return Error(IDLoc, "invalid symbol redefinition"); getStreamer().emitTBSSSymbol( getContext().getMachOSection("__DATA", "__thread_bss", MachO::S_THREAD_LOCAL_ZEROFILL, 0, SectionKind::getThreadBSS()), Sym, Size, Align(1ULL << Pow2Alignment)); return false; } /// ParseDirectiveZerofill /// ::= .zerofill segname , sectname [, identifier , size_expression [ /// , align_expression ]] bool DarwinAsmParser::parseDirectiveZerofill(StringRef, SMLoc) { StringRef Segment; if (getParser().parseIdentifier(Segment)) return TokError("expected segment name after '.zerofill' directive"); if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lex(); StringRef Section; SMLoc SectionLoc = getLexer().getLoc(); if (getParser().parseIdentifier(Section)) return TokError("expected section name after comma in '.zerofill' " "directive"); // If this is the end of the line all that was wanted was to create the // the section but with no symbol. if (getLexer().is(AsmToken::EndOfStatement)) { // Create the zerofill section but no symbol getStreamer().emitZerofill( getContext().getMachOSection(Segment, Section, MachO::S_ZEROFILL, 0, SectionKind::getBSS()), /*Symbol=*/nullptr, /*Size=*/0, Align(1), SectionLoc); return false; } if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lex(); SMLoc IDLoc = getLexer().getLoc(); StringRef IDStr; if (getParser().parseIdentifier(IDStr)) return TokError("expected identifier in directive"); // handle the identifier as the key symbol. MCSymbol *Sym = getContext().getOrCreateSymbol(IDStr); if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lex(); int64_t Size; SMLoc SizeLoc = getLexer().getLoc(); if (getParser().parseAbsoluteExpression(Size)) return true; int64_t Pow2Alignment = 0; SMLoc Pow2AlignmentLoc; if (getLexer().is(AsmToken::Comma)) { Lex(); Pow2AlignmentLoc = getLexer().getLoc(); if (getParser().parseAbsoluteExpression(Pow2Alignment)) return true; } if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.zerofill' directive"); Lex(); if (Size < 0) return Error(SizeLoc, "invalid '.zerofill' directive size, can't be less " "than zero"); // NOTE: The alignment in the directive is a power of 2 value, the assembler // may internally end up wanting an alignment in bytes. // FIXME: Diagnose overflow. if (Pow2Alignment < 0) return Error(Pow2AlignmentLoc, "invalid '.zerofill' directive alignment, " "can't be less than zero"); if (!Sym->isUndefined()) return Error(IDLoc, "invalid symbol redefinition"); // Create the zerofill Symbol with Size and Pow2Alignment // // FIXME: Arch specific. getStreamer().emitZerofill( getContext().getMachOSection(Segment, Section, MachO::S_ZEROFILL, 0, SectionKind::getBSS()), Sym, Size, Align(1ULL << Pow2Alignment), SectionLoc); return false; } /// ParseDirectiveDataRegion /// ::= .data_region [ ( jt8 | jt16 | jt32 ) ] bool DarwinAsmParser::parseDirectiveDataRegion(StringRef, SMLoc) { if (getLexer().is(AsmToken::EndOfStatement)) { Lex(); getStreamer().emitDataRegion(MCDR_DataRegion); return false; } StringRef RegionType; SMLoc Loc = getParser().getTok().getLoc(); if (getParser().parseIdentifier(RegionType)) return TokError("expected region type after '.data_region' directive"); int Kind = StringSwitch(RegionType) .Case("jt8", MCDR_DataRegionJT8) .Case("jt16", MCDR_DataRegionJT16) .Case("jt32", MCDR_DataRegionJT32) .Default(-1); if (Kind == -1) return Error(Loc, "unknown region type in '.data_region' directive"); Lex(); getStreamer().emitDataRegion((MCDataRegionType)Kind); return false; } /// ParseDirectiveDataRegionEnd /// ::= .end_data_region bool DarwinAsmParser::parseDirectiveDataRegionEnd(StringRef, SMLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.end_data_region' directive"); Lex(); getStreamer().emitDataRegion(MCDR_DataRegionEnd); return false; } static bool isSDKVersionToken(const AsmToken &Tok) { return Tok.is(AsmToken::Identifier) && Tok.getIdentifier() == "sdk_version"; } /// parseMajorMinorVersionComponent ::= major, minor bool DarwinAsmParser::parseMajorMinorVersionComponent(unsigned *Major, unsigned *Minor, const char *VersionName) { // Get the major version number. if (getLexer().isNot(AsmToken::Integer)) return TokError(Twine("invalid ") + VersionName + " major version number, integer expected"); int64_t MajorVal = getLexer().getTok().getIntVal(); if (MajorVal > 65535 || MajorVal <= 0) return TokError(Twine("invalid ") + VersionName + " major version number"); *Major = (unsigned)MajorVal; Lex(); if (getLexer().isNot(AsmToken::Comma)) return TokError(Twine(VersionName) + " minor version number required, comma expected"); Lex(); // Get the minor version number. if (getLexer().isNot(AsmToken::Integer)) return TokError(Twine("invalid ") + VersionName + " minor version number, integer expected"); int64_t MinorVal = getLexer().getTok().getIntVal(); if (MinorVal > 255 || MinorVal < 0) return TokError(Twine("invalid ") + VersionName + " minor version number"); *Minor = MinorVal; Lex(); return false; } /// parseOptionalTrailingVersionComponent ::= , version_number bool DarwinAsmParser::parseOptionalTrailingVersionComponent( unsigned *Component, const char *ComponentName) { assert(getLexer().is(AsmToken::Comma) && "comma expected"); Lex(); if (getLexer().isNot(AsmToken::Integer)) return TokError(Twine("invalid ") + ComponentName + " version number, integer expected"); int64_t Val = getLexer().getTok().getIntVal(); if (Val > 255 || Val < 0) return TokError(Twine("invalid ") + ComponentName + " version number"); *Component = Val; Lex(); return false; } /// parseVersion ::= parseMajorMinorVersionComponent /// parseOptionalTrailingVersionComponent bool DarwinAsmParser::parseVersion(unsigned *Major, unsigned *Minor, unsigned *Update) { if (parseMajorMinorVersionComponent(Major, Minor, "OS")) return true; // Get the update level, if specified *Update = 0; if (getLexer().is(AsmToken::EndOfStatement) || isSDKVersionToken(getLexer().getTok())) return false; if (getLexer().isNot(AsmToken::Comma)) return TokError("invalid OS update specifier, comma expected"); if (parseOptionalTrailingVersionComponent(Update, "OS update")) return true; return false; } bool DarwinAsmParser::parseSDKVersion(VersionTuple &SDKVersion) { assert(isSDKVersionToken(getLexer().getTok()) && "expected sdk_version"); Lex(); unsigned Major, Minor; if (parseMajorMinorVersionComponent(&Major, &Minor, "SDK")) return true; SDKVersion = VersionTuple(Major, Minor); // Get the subminor version, if specified. if (getLexer().is(AsmToken::Comma)) { unsigned Subminor; if (parseOptionalTrailingVersionComponent(&Subminor, "SDK subminor")) return true; SDKVersion = VersionTuple(Major, Minor, Subminor); } return false; } void DarwinAsmParser::checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc, Triple::OSType ExpectedOS) { const Triple &Target = getContext().getTargetTriple(); if (Target.getOS() != ExpectedOS) Warning(Loc, Twine(Directive) + (Arg.empty() ? Twine() : Twine(' ') + Arg) + " used while targeting " + Target.getOSName()); if (LastVersionDirective.isValid()) { Warning(Loc, "overriding previous version directive"); Note(LastVersionDirective, "previous definition is here"); } LastVersionDirective = Loc; } static Triple::OSType getOSTypeFromMCVM(MCVersionMinType Type) { switch (Type) { case MCVM_WatchOSVersionMin: return Triple::WatchOS; case MCVM_TvOSVersionMin: return Triple::TvOS; case MCVM_IOSVersionMin: return Triple::IOS; case MCVM_OSXVersionMin: return Triple::MacOSX; } llvm_unreachable("Invalid mc version min type"); } /// parseVersionMin /// ::= .ios_version_min parseVersion parseSDKVersion /// | .macosx_version_min parseVersion parseSDKVersion /// | .tvos_version_min parseVersion parseSDKVersion /// | .watchos_version_min parseVersion parseSDKVersion bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type) { unsigned Major; unsigned Minor; unsigned Update; if (parseVersion(&Major, &Minor, &Update)) return true; VersionTuple SDKVersion; if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) return true; if (parseEOL()) return addErrorSuffix(Twine(" in '") + Directive + "' directive"); Triple::OSType ExpectedOS = getOSTypeFromMCVM(Type); checkVersion(Directive, StringRef(), Loc, ExpectedOS); getStreamer().emitVersionMin(Type, Major, Minor, Update, SDKVersion); return false; } static Triple::OSType getOSTypeFromPlatform(MachO::PlatformType Type) { switch (Type) { case MachO::PLATFORM_UNKNOWN: /* silence warning */ break; case MachO::PLATFORM_MACOS: return Triple::MacOSX; case MachO::PLATFORM_IOS: return Triple::IOS; case MachO::PLATFORM_TVOS: return Triple::TvOS; case MachO::PLATFORM_WATCHOS: return Triple::WatchOS; case MachO::PLATFORM_BRIDGEOS: /* silence warning */ break; case MachO::PLATFORM_DRIVERKIT: return Triple::DriverKit; case MachO::PLATFORM_MACCATALYST: return Triple::IOS; case MachO::PLATFORM_IOSSIMULATOR: /* silence warning */ break; case MachO::PLATFORM_TVOSSIMULATOR: /* silence warning */ break; case MachO::PLATFORM_WATCHOSSIMULATOR: /* silence warning */ break; } llvm_unreachable("Invalid mach-o platform type"); } /// parseBuildVersion /// ::= .build_version (macos|ios|tvos|watchos), parseVersion parseSDKVersion bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) { StringRef PlatformName; SMLoc PlatformLoc = getTok().getLoc(); if (getParser().parseIdentifier(PlatformName)) return TokError("platform name expected"); unsigned Platform = StringSwitch(PlatformName) .Case("macos", MachO::PLATFORM_MACOS) .Case("ios", MachO::PLATFORM_IOS) .Case("tvos", MachO::PLATFORM_TVOS) .Case("watchos", MachO::PLATFORM_WATCHOS) .Case("macCatalyst", MachO::PLATFORM_MACCATALYST) .Case("driverkit", MachO::PLATFORM_DRIVERKIT) .Default(0); if (Platform == 0) return Error(PlatformLoc, "unknown platform name"); if (getLexer().isNot(AsmToken::Comma)) return TokError("version number required, comma expected"); Lex(); unsigned Major; unsigned Minor; unsigned Update; if (parseVersion(&Major, &Minor, &Update)) return true; VersionTuple SDKVersion; if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion)) return true; if (parseEOL()) return addErrorSuffix(" in '.build_version' directive"); Triple::OSType ExpectedOS = getOSTypeFromPlatform((MachO::PlatformType)Platform); checkVersion(Directive, PlatformName, Loc, ExpectedOS); getStreamer().emitBuildVersion(Platform, Major, Minor, Update, SDKVersion); return false; } /// parseDirectiveCGProfile /// ::= .cg_profile from, to, count bool DarwinAsmParser::parseDirectiveCGProfile(StringRef S, SMLoc Loc) { return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc); } namespace llvm { MCAsmParserExtension *createDarwinAsmParser() { return new DarwinAsmParser; } } // end llvm namespace