Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -117,6 +117,9 @@ enum SignReturnAddressKeyValue { AKey, BKey }; + // Allowed values are {"all", "labels", "none", ""} + std::string BasicBlockSections; + enum class FramePointerKind { None, // Omit all frame pointers. NonLeaf, // Keep non-leaf frame pointers. Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -47,6 +47,9 @@ ///< aliases to base ctors when possible. CODEGENOPT(DataSections , 1, 0) ///< Set when -fdata-sections is enabled. CODEGENOPT(UniqueSectionNames, 1, 1) ///< Set for -funique-section-names. +CODEGENOPT(UniqueBBSectionNames, 1, 1) ///< Set for -funique-bb-section-names, + ///< Produce unique section names with + ///< basic block sections. ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory. @@ -145,6 +148,7 @@ CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN. CODEGENOPT(FlushDenorm , 1, 0) ///< Allow FP denorm numbers to be flushed to zero CODEGENOPT(CorrectlyRoundedDivSqrt, 1, 0) ///< -cl-fp32-correctly-rounded-divide-sqrt +CODEGENOPT(UniqueInternalFuncNames, 1, 0) ///< Internal Linkage functions get unique names. /// When false, this attempts to generate code as if the result of an /// overflowing conversion matches the overflowing behavior of a target's native @@ -333,6 +337,11 @@ /// Whether copy relocations support is available when building as PIE. CODEGENOPT(PIECopyRelocations, 1, 0) +/// Relocate with symbols instead of sections. Relocating with sections allows +/// the assembler to omit some local symbols but it is valid to relocate with +/// symbols. Propeller uses this as it simplifies linker relaxations. +CODEGENOPT(RelocateWithSymbols, 1, 0) + /// Whether we should use the undefined behaviour optimization for control flow /// paths that reach the end of a function without executing a required return. CODEGENOPT(StrictReturn, 1, 1) Index: clang/include/clang/Driver/CC1Options.td =================================================================== --- clang/include/clang/Driver/CC1Options.td +++ clang/include/clang/Driver/CC1Options.td @@ -207,6 +207,8 @@ HelpText<"Make assembler warnings fatal">; def mrelax_relocations : Flag<["--"], "mrelax-relocations">, HelpText<"Use relaxable elf relocations">; +def mrelocate_with_symbols : Flag<["-"], "mrelocate-with-symbols">, + HelpText<"Always use Symbols for relocations instead of sections">; def msave_temp_labels : Flag<["-"], "msave-temp-labels">, HelpText<"Save temporary labels in the symbol table. " "Note this may change .s semantics and shouldn't generally be used " Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1302,6 +1302,12 @@ def fthinlto_index_EQ : Joined<["-"], "fthinlto-index=">, Flags<[CoreOption, CC1Option]>, Group, HelpText<"Perform ThinLTO importing using provided function summary index">; +def fpropeller_optimize_EQ : Joined<["-"], "fpropeller-optimize=">, Flags<[CoreOption, CC1Option]>, Group, + HelpText<"Enable Propeller optimization using the given profiles">; +def fpropeller_label : Flag<["-"], "fpropeller-label">, Group, + HelpText<"Label the binary's basic blocks for generating Propeller profiles">; +def fno_propeller : Flag<["-"], "fno-propeller">, Group, + HelpText<"Disable Propeller (default)">; def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">, Group, Flags<[DriverOption, CoreOption]>; def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group, @@ -1863,6 +1869,8 @@ HelpText<"Place each function in its own section (ELF Only)">; def fno_function_sections : Flag<["-"], "fno-function-sections">, Group, Flags<[CC1Option]>; +def fbasicblock_sections_EQ : Joined<["-"], "fbasicblock-sections=">, Group, Flags<[CC1Option, CC1AsOption]>, + HelpText<"Place each function's basic blocks in unique sections (ELF Only) : all | labels | none | ">; def fdata_sections : Flag <["-"], "fdata-sections">, Group, Flags<[CC1Option]>, HelpText<"Place each data in its own section (ELF Only)">; def fno_data_sections : Flag <["-"], "fno-data-sections">, Group, @@ -1878,6 +1886,16 @@ def fno_unique_section_names : Flag <["-"], "fno-unique-section-names">, Group, Flags<[CC1Option]>; +def funique_bb_section_names : Flag <["-"], "funique-bb-section-names">, + Group, Flags<[CC1Option]>, + HelpText<"Use unique names for basic block sections (ELF Only)">; +def fno_unique_bb_section_names : Flag <["-"], "fno-unique-bb-section-names">, + Group, Flags<[CC1Option]>; +def funique_internal_funcnames : Flag <["-"], "funique-internal-funcnames">, + Group, Flags<[CC1Option]>, + HelpText<"Uniqueify Internal Linkage Function Names">; +def fno_unique_internal_funcnames : Flag <["-"], "fno-unique-internal-funcnames">, + Group, Flags<[CC1Option]>; def fstrict_return : Flag<["-"], "fstrict-return">, Group, Flags<[CC1Option]>, HelpText<"Always treat control flow paths that fall off the end of a " Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -418,6 +418,29 @@ } } +static void getBasicBlockSectionsList(llvm::TargetOptions &Options, + std::string FunctionsListFile) { + assert((Options.BasicBlockSections = llvm::BasicBlockSection::List) && + "Invalid BasicBlock Section Type"); + if (FunctionsListFile.empty()) + return; + auto MBOrErr = llvm::MemoryBuffer::getFile(FunctionsListFile); + if (auto EC = MBOrErr.getError()) { + errs() << "Cannot open " + FunctionsListFile + ": " + EC.message(); + return; + } + std::unique_ptr &MB = *MBOrErr; + MemoryBufferRef MBRef = MB->getMemBufferRef(); + SmallVector Arr; + MBRef.getBuffer().split(Arr, '\n'); + for (StringRef S : Arr) { + // Function names follow a '!' character. + // Empty '!' implies no more functions. + if (S.consume_front("!") && !S.empty()) + Options.BasicBlockSectionsList[S.str()] = true; + } +} + static void initTargetOptions(llvm::TargetOptions &Options, const CodeGenOptions &CodeGenOpts, const clang::TargetOptions &TargetOpts, @@ -476,9 +499,22 @@ Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath; Options.StackAlignmentOverride = CodeGenOpts.StackAlignment; + + Options.BasicBlockSections = + llvm::StringSwitch( + CodeGenOpts.BasicBlockSections) + .Case("all", llvm::BasicBlockSection::All) + .Case("labels", llvm::BasicBlockSection::Labels) + .Case("none", llvm::BasicBlockSection::None) + .Default(llvm::BasicBlockSection::List); + + if (Options.BasicBlockSections == llvm::BasicBlockSection::List) + getBasicBlockSectionsList(Options, CodeGenOpts.BasicBlockSections); + Options.FunctionSections = CodeGenOpts.FunctionSections; Options.DataSections = CodeGenOpts.DataSections; Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames; + Options.UniqueBBSectionNames = CodeGenOpts.UniqueBBSectionNames; Options.EmulatedTLS = CodeGenOpts.EmulatedTLS; Options.ExplicitEmulatedTLS = CodeGenOpts.ExplicitEmulatedTLS; Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning(); @@ -494,6 +530,7 @@ Options.MCOptions.MCIncrementalLinkerCompatible = CodeGenOpts.IncrementalLinkerCompatible; Options.MCOptions.MCPIECopyRelocations = CodeGenOpts.PIECopyRelocations; + Options.MCOptions.MCRelocateWithSymbols = CodeGenOpts.RelocateWithSymbols; Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings; Options.MCOptions.MCNoWarn = CodeGenOpts.NoWarn; Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose; Index: clang/lib/CodeGen/CGDeclCXX.cpp =================================================================== --- clang/lib/CodeGen/CGDeclCXX.cpp +++ clang/lib/CodeGen/CGDeclCXX.cpp @@ -342,8 +342,15 @@ Name, &getModule()); if (!getLangOpts().AppleKext && !TLS) { // Set the section if needed. - if (const char *Section = getTarget().getStaticInitSectionSpecifier()) - Fn->setSection(Section); + if (const char *Section = getTarget().getStaticInitSectionSpecifier()) { + if (getCodeGenOpts().FunctionSections) { + Twine NewName = Section + Name; + Fn->setSection(NewName.str()); + } + else { + Fn->setSection(Section); + } + } } SetInternalFunctionAttributes(GlobalDecl(), Fn, FI); Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -59,6 +59,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" #include "llvm/Support/TimeProfiler.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" using namespace clang; using namespace CodeGen; @@ -1028,7 +1029,6 @@ llvm_unreachable("None multiversion type isn't valid here"); } } - return Out.str(); } @@ -1094,6 +1094,18 @@ const auto *ND = cast(GD.getDecl()); std::string MangledName = getMangledNameImpl(*this, GD, ND); + // With BasicBlockSections, it is important to have a unique name for + // internal linkage functions, to differentiate the symbols across + // modules. + if (getCodeGenOpts().UniqueInternalFuncNames && + dyn_cast(GD.getDecl()) && + this->getFunctionLinkage(GD) == llvm::GlobalValue::InternalLinkage) { + std::string UniqueSuffix = getUniqueModuleId(&getModule(), true); + if (!UniqueSuffix.empty()) { + MangledName = MangledName + '.' + UniqueSuffix; + } + } + // Adjust kernel stub mangling as we may need to be able to differentiate // them from the kernel itself (e.g., for HIP). if (auto *FD = dyn_cast(GD.getDecl())) Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2302,6 +2302,14 @@ CmdArgs.push_back(MipsTargetFeature); } + // Basic Block Sections needs relocations via symbols for linker to do + // relaxation easily. + auto BasicBlockSections = + Args.getLastArgValue(options::OPT_fbasicblock_sections_EQ, "none"); + + if (BasicBlockSections != "none" && BasicBlockSections != "labels") + CmdArgs.push_back("-mrelocate-with-symbols"); + // forward -fembed-bitcode to assmebler if (C.getDriver().embedBitcodeEnabled() || C.getDriver().embedBitcodeMarkerOnly()) @@ -3778,8 +3786,13 @@ options::OPT_fno_function_sections, options::OPT_fdata_sections, options::OPT_fno_data_sections, + options::OPT_fbasicblock_sections_EQ, + options::OPT_funique_internal_funcnames, + options::OPT_fno_unique_internal_funcnames, options::OPT_funique_section_names, options::OPT_fno_unique_section_names, + options::OPT_funique_bb_section_names, + options::OPT_fno_unique_bb_section_names, options::OPT_mrestrict_it, options::OPT_mno_restrict_it, options::OPT_mstackrealign, @@ -4294,6 +4307,35 @@ CmdArgs.push_back("-ffunction-sections"); } + // Handle Propeller optimization flags here. + if (Arg *A = Args.getLastArg(options::OPT_fpropeller_optimize_EQ, + options::OPT_fpropeller_label, + options::OPT_fno_propeller)) { + // Propeller optimizations work much better with unique + // internal func names. + // We push "-funique-internal-funcnames" only if no + // -f(no-)unique-internal-funcnames is specified. + bool NeedExplicitUniqueInternalFuncNames = + (nullptr == + Args.getLastArg(options::OPT_funique_internal_funcnames, + options::OPT_fno_unique_internal_funcnames)); + if (A->getOption().matches(options::OPT_fpropeller_optimize_EQ)) { + CmdArgs.push_back( + Args.MakeArgString(Twine("-fbasicblock-sections=") + A->getValue())); + if (NeedExplicitUniqueInternalFuncNames) + CmdArgs.push_back("-funique-internal-funcnames"); + } else if (A->getOption().matches(options::OPT_fpropeller_label)) { + CmdArgs.push_back("-fbasicblock-sections=labels"); + if (NeedExplicitUniqueInternalFuncNames) + CmdArgs.push_back("-funique-internal-funcnames"); + } + } + + if (Arg *A = Args.getLastArg(options::OPT_fbasicblock_sections_EQ)) { + CmdArgs.push_back( + Args.MakeArgString(Twine("-fbasicblock-sections=") + A->getValue())); + } + if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, UseSeparateSections)) { CmdArgs.push_back("-fdata-sections"); @@ -4303,6 +4345,14 @@ options::OPT_fno_unique_section_names, true)) CmdArgs.push_back("-fno-unique-section-names"); + if (Args.hasFlag(options::OPT_funique_internal_funcnames, + options::OPT_fno_unique_internal_funcnames, false)) + CmdArgs.push_back("-funique-internal-funcnames"); + + if (Args.hasFlag(options::OPT_funique_bb_section_names, + options::OPT_fno_unique_bb_section_names, false)) + CmdArgs.push_back("-funique-bb-section-names"); + Args.AddLastArg(CmdArgs, options::OPT_finstrument_functions, options::OPT_finstrument_functions_after_inlining, options::OPT_finstrument_function_entry_bare); Index: clang/lib/Driver/ToolChains/Gnu.cpp =================================================================== --- clang/lib/Driver/ToolChains/Gnu.cpp +++ clang/lib/Driver/ToolChains/Gnu.cpp @@ -623,6 +623,31 @@ } } + if (Arg *A = Args.getLastArg(options::OPT_fpropeller_optimize_EQ, + options::OPT_fpropeller_label, + options::OPT_fno_propeller)) { + // With Propeller, trigger the linker flags only with lld. + if (A->getOption().matches(options::OPT_fpropeller_optimize_EQ)) { + if (!Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_lower("lld")) + D.Diag(clang::diag::err_drv_unsupported_opt) + << "Linker does not support -fpropeller-optimize="; + CmdArgs.push_back( + Args.MakeArgString(Twine("--propeller=") + A->getValue())); + if (D.isUsingLTO()) + CmdArgs.push_back(Args.MakeArgString( + Twine("--lto-basicblock-sections=") + A->getValue())); + CmdArgs.push_back("--optimize-bb-jumps"); + CmdArgs.push_back("--no-call-graph-profile-sort"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("nokeep-text-section-prefix"); + CmdArgs.push_back("--no-warn-symbol-ordering"); + } else if (A->getOption().matches(options::OPT_fpropeller_label)) { + if (D.isUsingLTO()) + CmdArgs.push_back(Args.MakeArgString( + Twine("--lto-basicblock-sections=labels"))); + } + } + // Add OpenMP offloading linker script args if required. AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -924,6 +924,7 @@ Args.hasArg(OPT_mincremental_linker_compatible); Opts.PIECopyRelocations = Args.hasArg(OPT_mpie_copy_relocations); + Opts.RelocateWithSymbols = Args.hasArg(OPT_mrelocate_with_symbols); Opts.NoPLT = Args.hasArg(OPT_fno_plt); Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels); Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm); @@ -945,14 +946,33 @@ Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ); Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array); + Opts.BasicBlockSections = Args.getLastArgValue(OPT_fbasicblock_sections_EQ, + "none"); + if (Opts.BasicBlockSections != "all" && + Opts.BasicBlockSections != "labels" && + Opts.BasicBlockSections != "none" && + !llvm::sys::fs::exists(Opts.BasicBlockSections)) { + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fbasicblock_sections_EQ)->getAsString(Args) + << Opts.BasicBlockSections; + } + + // Basic Block Sections implies Function Sections. Opts.FunctionSections = Args.hasFlag(OPT_ffunction_sections, - OPT_fno_function_sections, false); + OPT_fno_function_sections, false) || + (Opts.BasicBlockSections != "none" && + Opts.BasicBlockSections != "labels"); + Opts.DataSections = Args.hasFlag(OPT_fdata_sections, OPT_fno_data_sections, false); Opts.StackSizeSection = Args.hasFlag(OPT_fstack_size_section, OPT_fno_stack_size_section, false); Opts.UniqueSectionNames = Args.hasFlag(OPT_funique_section_names, OPT_fno_unique_section_names, true); + Opts.UniqueBBSectionNames = Args.hasFlag(OPT_funique_bb_section_names, + OPT_fno_unique_bb_section_names, false); + Opts.UniqueInternalFuncNames = Args.hasFlag(OPT_funique_internal_funcnames, + OPT_fno_unique_internal_funcnames, false); Opts.MergeFunctions = Args.hasArg(OPT_fmerge_functions); Index: clang/test/CodeGen/basicblock-sections.c =================================================================== --- /dev/null +++ clang/test/CodeGen/basicblock-sections.c @@ -0,0 +1,47 @@ +// REQUIRES: x86-registered-target + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=all -fbasicblock-sections=none -o - < %s | FileCheck %s --check-prefix=PLAIN + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=labels -o - < %s | FileCheck %s --check-prefix=BB_LABELS +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=all -o - < %s | FileCheck %s --check-prefix=BB_WORLD --check-prefix=BB_ALL +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=%S/basicblock-sections.funcnames -o - < %s | FileCheck %s --check-prefix=BB_WORLD --check-prefix=BB_LIST +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=all -funique-bb-section-names -o - < %s | FileCheck %s --check-prefix=UNIQUE + +int world(int a) { + if (a > 10) + return 10; + else if (a > 5) + return 5; + else + return 0; +} + +int another(int a) { + if (a > 10) + return 20; + return 0; +} + +// PLAIN-NOT: section +// PLAIN: world +// +// BB_LABELS-NOT: section +// BB_LABELS: world +// BB_LABELS-LABEL: a.BB.world +// BB_LABELS-LABEL: aa.BB.world +// BB_LABEL-LABEL: a.BB.another +// +// BB_WORLD: .section .text.world,"ax",@progbits +// BB_WORLD: world +// BB_WORLD: .section .text.world,"ax",@progbits,unique +// BB_WORLD: a.BB.world +// BB_WORLD: .section .text.another,"ax",@progbits +// BB_ALL: .section .text.another,"ax",@progbits,unique +// BB_ALL: a.BB.another +// BB_LIST-NOT: .section .text.another,"ax",@progbits,unique +// BB_LIST: another +// BB_LIST-NOT: a.BB.another +// +// UNIQUE: .section .text.world.a.BB.world +// UNIQUE: .section .text.another.a.BB.another Index: clang/test/CodeGen/basicblock-sections.funcnames =================================================================== --- /dev/null +++ clang/test/CodeGen/basicblock-sections.funcnames @@ -0,0 +1 @@ +!world Index: clang/test/CodeGen/unique_internal_funcnames.c =================================================================== --- /dev/null +++ clang/test/CodeGen/unique_internal_funcnames.c @@ -0,0 +1,18 @@ +// REQUIRES: x86-registered-target + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -funique-internal-funcnames -fno-unique-internal-funcnames -o - < %s | FileCheck %s --check-prefix=PLAIN +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -funique-internal-funcnames -o - < %s | FileCheck %s --check-prefix=UNIQUE + + +static int foo() { + return 0; +} + +int (*bar()) () { + return foo; +} + +// PLAIN: foo: +// UNIQUE-NOT: foo: +// UNIQUE: foo.$ Index: clang/test/Driver/propeller-flags.c =================================================================== --- /dev/null +++ clang/test/Driver/propeller-flags.c @@ -0,0 +1,13 @@ +// Check that -fpropeller flag invokes the correct options. +// RUN: %clang -### %s -target x86_64-unknown-linux -fpropeller-label -flto=thin 2>&1 | FileCheck %s -check-prefix=CHECK_PROPELLER_LABEL +// RUN: %clang -### %s -target x86_64-unknown-linux -fpropeller-optimize=perf.propeller -flto=thin 2>&1 | FileCheck %s -check-prefix=CHECK_PROPELLER_OPT + +// CHECK_PROPELLER_LABEL: "-fbasicblock-sections=labels" +// CHECK_PROPELLER_LABEL: "-funique-internal-funcnames" +// CHECK_PROPELLER_LABEL: "--lto-basicblock-sections=labels" +// +// CHECK_PROPELLER_OPT: "-fbasicblock-sections=perf.propeller" +// CHECK_PROPELLER_OPT: "-funique-internal-funcnames" +// CHECK_PROPELLER_OPT: "--propeller=perf.propeller" +// CHECK_PROPELLER_OPT: "--lto-basicblock-sections=perf.propeller" +// CHECK_PROPELLER_OPT: "--optimize-bb-jumps" Index: clang/tools/driver/cc1as_main.cpp =================================================================== --- clang/tools/driver/cc1as_main.cpp +++ clang/tools/driver/cc1as_main.cpp @@ -90,6 +90,7 @@ unsigned SaveTemporaryLabels : 1; unsigned GenDwarfForAssembly : 1; unsigned RelaxELFRelocations : 1; + unsigned RelocateWithSymbols : 1; unsigned DwarfVersion; std::string DwarfDebugFlags; std::string DwarfDebugProducer; @@ -236,6 +237,7 @@ } Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); + Opts.RelocateWithSymbols = Args.hasArg(OPT_mrelocate_with_symbols); Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.DwarfDebugProducer = Args.getLastArgValue(OPT_dwarf_debug_producer); @@ -361,6 +363,7 @@ MAI->setCompressDebugSections(Opts.CompressDebugSections); MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations); + MAI->setRelocateWithSymbols(Opts.RelocateWithSymbols); bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; if (Opts.OutputPath.empty())