LLVM学习笔记(57)

这篇具有很好参考价值的文章主要介绍了LLVM学习笔记(57)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

4.2. 代码入口(以下为7.0代码

LLVM有两个编译器。一个是静态编译器llc——它的输入是Clang从C、C++及ObjC源代码转换而来的LLVM IR,把IR编译为LLVM的字节码,或指定目标机器的汇编或机器码。另一个是动态编译器lli——它的输入是LLVM的字节码,并执行之。显然,指令选择与调度与llc的关系要紧密得多。文件llc.cpp就是llc的源代码所在。Llc的入口就是其中的main()函数。大致上这个main()函数是这样的:

276     int main(int argc, char **argv) {

277       InitLLVM X(argc, argv);

278    

279       // Enable debug stream buffering.

280       EnableDebugBuffering = true;

281    

282       LLVMContext Context;

283    

284      // Initialize targets first, so that --version shows registered targets.

285       InitializeAllTargets();

286       InitializeAllTargetMCs();

287       InitializeAllAsmPrinters();

288       InitializeAllAsmParsers();

289    

290       // Initialize codegen and IR passes used by llc so that the -print-after,

291       // -print-before, and -stop-after options work.

292       PassRegistry *Registry = PassRegistry::getPassRegistry();

293       initializeCore(*Registry);

294       initializeCodeGen(*Registry);

295       initializeLoopStrengthReducePass(*Registry);

296       initializeLowerIntrinsicsPass(*Registry);

297       initializeEntryExitInstrumenterPass(*Registry);

298       initializePostInlineEntryExitInstrumenterPass(*Registry);

299       initializeUnreachableBlockElimPass(*Registry);

300       initializeConstantHoistingLegacyPassPass(*Registry);

301       initializeScalarOpts(*Registry);

302       initializeVectorization(*Registry);

303       initializeScalarizeMaskedMemIntrinPass(*Registry);

304       initializeExpandReductionsPass(*Registry);

305    

306       // Initialize debugging passes.

307       initializeScavengerTestPass(*Registry);

308    

309       // Register the target printer for --version.

310       cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);

311    

312       cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n")

313    

314       Context.setDiscardValueNames(DiscardValueNames);

315    

316       // Set a diagnostic handler that doesn't exit on the first error

317       bool HasError = false;

318       Context.setDiagnosticHandler(

319             llvm::make_unique<LLCDiagnosticHandler>(&HasError));

320       Context.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, &HasError);

321    

322       if (PassRemarksWithHotness)

323          Context.setDiagnosticsHotnessRequested(true);

324    

325       if (PassRemarksHotnessThreshold)

326          Context.setDiagnosticsHotnessThreshold(PassRemarksHotnessThreshold);

327    

328       std::unique_ptr<ToolOutputFile> YamlFile;

329       if (RemarksFilename != "") {

330          std::error_code EC;

331         YamlFile =

332                llvm::make_unique<ToolOutputFile>(RemarksFilename, EC, sys::fs::F_None);

333          if (EC) {

334             WithColor::error(errs(), argv[0]) << EC.message() << '\n';

335             return 1;

336          }

337          Context.setDiagnosticsOutputFile(

338                 llvm::make_unique<yaml::Output>(YamlFile->os()));

339       }

340    

341       if (InputLanguage != "" && InputLanguage != "ir" &&

342                InputLanguage != "mir") {

343          WithColor::error(errs(), argv[0])

344                  << "input language must be '', 'IR' or 'MIR'\n";

345          return 1;

346       }

347    

348       // Compile the module TimeCompilations times to give better compile time

349       // metrics.

350       for (unsigned I = TimeCompilations; I; --I)

351         if (int RetVal = compileModule(argv, Context))

352           return RetVal;

353    

354       if (YamlFile)

355          YamlFile->keep();

356          return 0;

357     }

4.3. 目标机器的初始化方法 

285~288行初始化所有与目标机器相关的模块。以X86目标机器为例,InitializeAllTargets()会依次调用LLVMInitializeX86TargetInfo()以及LLVMInitializeX86Targe()(这个函数实际上会调用所有LLVM支持的目标机器的这些方法):

14       Target &llvm::getTheX86_32Target() {                                                                                  ß v7.0增加

15         static Target TheX86_32Target;

16         return TheX86_32Target;

17       }

18       Target &llvm::getTheX86_64Target() {

19         static Target TheX86_64Target;

20         return TheX86_64Target;

21       }

22      

23       extern "C" void LLVMInitializeX86TargetInfo() {

24         RegisterTarget<Triple::x86, /*HasJIT=*/true>

25           X(getTheX86_32Target(), "x86", "32-bit X86: Pentium-Pro and above");

26      

27         RegisterTarget<Triple::x86_64, /*HasJIT=*/true>

28           Y(getTheX86_64Target(), "x86-64", "64-bit X86: EM64T and AMD64");

29       }

V7.0TheX86_32Target/TheX86_64Target声明为函数的静态成员,通过函数获取,避免了无意的修改。

RegisterTarget在构造函数里调用方法TargetRegistry::RegisterTarget()注册代表32位与64位X86目标机器的Target实例。这使得在后面可以通过17或20行的Triple值来查找这些Target对象。

75       extern "C" void LLVMInitializeX86Target() {

76         // Register the target.

77         RegisterTargetMachine<X86TargetMachine> X(TheX86_32Target);

78         RegisterTargetMachine<X86TargetMachine> Y(TheX86_64Target);

79      

80         PassRegistry &PR = *PassRegistry::getPassRegistry();

81         initializeGlobalISel(PR);

82         initializeWinEHStatePassPass(PR);

83         initializeFixupBWInstPassPass(PR);

84         initializeEvexToVexInstPassPass(PR);

85         initializeFixupLEAPassPass(PR);

86         initializeShadowCallStackPass(PR);

87         initializeX86CallFrameOptimizationPass(PR);

88         initializeX86CmovConverterPassPass(PR);

89         initializeX86ExecutionDomainFixPass(PR);

90         initializeX86DomainReassignmentPass(PR);

91         initializeX86AvoidSFBPassPass(PR);

92         initializeX86FlagsCopyLoweringPassPass(PR);

93       }

RegisterTargetMachine在构造函数里调用方法TargetRegistry::RegisterTargetMachine()将自己的Allocator()方法设置为TheX86_32Target及TheX86_64Target生成目标机器实现(X86TargetMachine)的构造方法指针TargetMachineCtorFn,为后面创建目标机器对象做好准备。

1102   template <class TargetMachineImpl> struct RegisterTargetMachine {

1103     RegisterTargetMachine(Target &T) {

1104       TargetRegistry::RegisterTargetMachine(T, &Allocator);

1105     }

1106  

1107   private:

1108     static TargetMachine *

1109     Allocator(const Target &T, const Triple &TT, StringRef CPU, StringRef FS,

1110                                     const TargetOptions &Options, Reloc::Model RM,

1111                                     CodeModel::Model CM, CodeGenOpt::Level OL, bool JIT) {

1112       return new TargetMachineImpl(T, TT, CPU, FS, Options, RM, CM, OL, JIT);

1113     }

1114   };

上面1104行的TargetRegistry::RegisterTargetMachine()是同一文件里的一个静态函数:

756       static void RegisterTargetMachine(Target &T, Target::TargetMachineCtorTy Fn) {

757         T.TargetMachineCtorFn = Fn;

758       }

V7.0LVMInitializeX86Target()里额外初始化x86所需的优化/处理遍。第一个就是GlobalISel相关的遍,我们看一下它要什么:

19       void llvm::initializeGlobalISel(PassRegistry &Registry) {

20         initializeIRTranslatorPass(Registry);

21         initializeLegalizerPass(Registry);

22         initializeLocalizerPass(Registry);

23         initializeRegBankSelectPass(Registry);

24         initializeInstructionSelectPass(Registry);

25       }

不出意外,GlobalISel需要这些遍:IRTranslatorLegalizerLocalizer(将常量形式指令移动/复制到靠近使用处。主要是为了绕过快速寄存器分配器的缺陷)、RegBankSelect,以及我们已经有点熟悉的InstructionSelect

剩下的遍有这些(WinEHStatePassWindows相关,我们不看):

  • FixupBWInstPass:查找使用32位指令替换64位指令的机会。这样做,一方面能消除64位寄存器不使用的高位带来的伪依赖;另一方面能减小代码大小。
  • EvexToVexInstPass:遍历使用使用EXE前缀编码的AVX-512指令,如果可能根据VEX编码替换它们,VEX编码能少2字节。
  • FixupLEAPass:查找能被重写为LEA指令的指令,以减小流水线时延。
  • ShadowCallStackPass:检查函数prologs/epilogs,确定在该函数执行期间,返回地址没有被毁坏。
  • X86CallFrameOptimizationPass:将函数参数到栈的mov,转换为push。因为两个主要原因这是有利的:
  1. Push指令的编码远小于基于栈指针的mov
  2. 有可能直接push内存实参。因此,如果这个转换在寄存器分配前执行,它有助于减轻寄存器压力。
  • X86CmovConverterPass:在有利时,将X86 cmov指令转换为分支。
  • X86ExecutionDomainFixPass:某些X86 SSE指令,如movandorxor对不同的操作数类型有不同的变形可用。这些变形是等价的,但在Nehalem及更新的CPU上,在整数域与浮点域之间传输数据有额外时延。这个遍尽量减少域跨越。
  • X86DomainReassignmentPass:尝试找出在一个域中的指令链(闭包),如果有利,将它们转换为不同域里等价的指令。
  • X86AvoidSFBPass:如果一个load跟着一个stroe后面,且重新载入这个store写入内存的数据,Intel微架构在许多情形里可以将这个数据从store直接转发给load。这个“store转发”通过使得 load可以直接获得数据,无需访问缓存或内存,节省了周期。

store转发阻塞”出现在store不能被转发到load的情形里。Store转发阻塞在Intel Core微架构上最常见,在这个架构上小的store不能转发给大的load。有个store转发阻塞的惩罚大约是13个周期。

在将memcpy调用降级为一系列loadstore时,这个遍尝试识别以及处理由编译器产生“store转发阻塞”的情形。

  • X86FlagsCopyLoweringPass:通过直接提前以及保留单独的标志位,降级EFLAGSCOPY节点。

InitializeAllTargetMCs()调用LLVMInitializeX86TargetMC()执行与目标机器MC相关方法的注册(记录在对应的Target对象里,比如下面的TheX86_32Target与TheX86_64Target)。

449     extern "C" void LLVMInitializeX86TargetMC() {

450       for (Target *T: {&getTheX86_32Target(), &getTheX86_64Target()}) {

451         // Register the MC asm info.

452         RegisterMCAsmInfoFn X(*T, createX86MCAsmInfo);

453    

454         // Register the MC instruction info.

455         TargetRegistry::RegisterMCInstrInfo(*T, createX86MCInstrInfo);

456    

457         // Register the MC register info.

458         TargetRegistry::RegisterMCRegInfo(*T, createX86MCRegisterInfo);

459    

460         // Register the MC subtarget info.

461         TargetRegistry::RegisterMCSubtargetInfo(*T,

462                                                 X86_MC::createX86MCSubtargetInfo);

463    

464         // Register the MC instruction analyzer.

465         TargetRegistry::RegisterMCInstrAnalysis(*T, createX86MCInstrAnalysis);

466    

467         // Register the code emitter.

468         TargetRegistry::RegisterMCCodeEmitter(*T, createX86MCCodeEmitter);

469    

470         // Register the obj target streamer.

471         TargetRegistry::RegisterObjectTargetStreamer(*T,

472                                                      createX86ObjectTargetStreamer);

473    

474         // Register the asm target streamer.

475         TargetRegistry::RegisterAsmTargetStreamer(*T, createX86AsmTargetStreamer);

476    

477         TargetRegistry::RegisterCOFFStreamer(*T, createX86WinCOFFStreamer);

478    

479         // Register the MCInstPrinter.

480        TargetRegistry::RegisterMCInstPrinter(*T, createX86MCInstPrinter);

481    

482         // Register the MC relocation info.

483         TargetRegistry::RegisterMCRelocationInfo(*T, createX86MCRelocationInfo);

484       }

485    

486       // Register the asm backend.

487       TargetRegistry::RegisterMCAsmBackend(TheX86_32Target,

488                                            createX86_32AsmBackend);

489       TargetRegistry::RegisterMCAsmBackend(TheX86_64Target,

490                                            createX86_64AsmBackend);

491     }

其中255行的createX86MCInstrInfo()调用InitX86MCInstrInfo(),258行的createX86MCRegisterInfo()会调用InitX86MCRegisterInfo(),462行的createX86MCSubtargetInfo()会调用InitX86MCSubtargetInfo()。这三个函数是在前面由TableGen根据.td文件生成。

InitializeAllAsmPrinters()类似地对X86目标机器调用下面的方法:

703     extern "C" void LLVMInitializeX86AsmPrinter() {

704       RegisterAsmPrinter<X86AsmPrinter> X(TheX86_32Target);

705       RegisterAsmPrinter<X86AsmPrinter> Y(TheX86_64Target);

706     }

InitializeAllAsmParser()调用的LLVMInitializeX86AsmPrinter()通过RegisterAsmPrinter的构造函数将X86AsmPrinter()注册为TheX86_32Target及TheX86_64Target的汇编输出器。

3449   extern "C" void LLVMInitializeX86AsmParser() {

3450     RegisterMCAsmParser<X86AsmParser> X(TheX86_32Target);

3451     RegisterMCAsmParser<X86AsmParser> Y(TheX86_64Target);

3452   }

方法LLVMInitializeX86AsmParser()将X86AsmParser()注册为TheX86_32Target及TheX86_64Target的汇编解析器。

Main()的293~307行注册与代码生成及IR相关的遍。我们稍后一点再来看。文章来源地址https://www.toymoban.com/news/detail-737737.html

到了这里,关于LLVM学习笔记(57)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用 LLVM clang C/C++ 编译器编译 OpenSSL 3.X库

    1、下载 OpenSSL 3.X 库的源代码放到待编译目录 2、解压并接入 OpenSSL 3.X 库源码的根目录 3、复制 ./Configure 一个取名为 ./Configure-clang 4、修改 ./Configure-clang 找到配置段: CC= CXX= CPP= LD= 把它们改成 CC          = \\\"/usr/bin/clang-8\\\", CXX         = \\\"/usr/bin/clang++-8\\\", CPP         = \\\"/usr/bin/

    2024年02月02日
    浏览(45)
  • LLVM编译报错解决:collect2: fatal error: ld terminated with signal 9 [Killed]

    克隆代码到本地 配置编译选项 generator一般使用Ninja,而 options 中必须要传入的参数是构建类型 CMAKE_BUILD_TYPE 不同的CMAKE_BUILD_TYPE区别如下: Build Type Optimization Debug Info Assertion Release For Speed No No Debug None Yes Yes RelWithDebInfo For Speed Yes No MinSizeRel For Size No No Release适合LLVM和Clang的用户

    2024年02月11日
    浏览(39)
  • SPEC CPU 2017 x86_64 Ubuntu 22.04 LTS LLVM 16.0.6 编译 intrate intspeed

    编译成功日志 安装openmp,其中有日志 -- Installing: /usr/local/lib/libomp.so  

    2024年02月15日
    浏览(89)
  • LLVM系列(1): 在微软Visual Studio下编译LLVM

    参考链接: Getting Started with the LLVM System using Microsoft Visual Studio — LLVM 18.0.0git documentation 1.安装visualstudio,版本需要大于vs2019 本机环境已安装visual studio2022,省略 2安装Makefile,版本需要大于3.21 本机环境已经安装cmake3.26 3. 用Cmake配置llvm 4.编译LLVM(有多个选项,例如选release,可

    2024年01月16日
    浏览(33)
  • Macos安装LLVM

    LLVM项目是模块化、可重用的编译器和工具链技术的集合。用LLVM可以创建编译器,著名的编译器Clang就是LLVM项目的子项目 平台:MacBook 按下键盘上的🔍键,输入“终端”,打开第一个结果。 在终端里面输入以下命令: /usr/bin/ruby -e \\\"$(curl -fsSL https://raw.githubusercontent.com/Homebrew

    2024年02月21日
    浏览(34)
  • LLVM 与代码混淆技术

    项目源码 LLVM 计划启动于2000年,开始由美国 UIUC 大学的 Chris Lattner 博士主持开展,后来 Apple 也加入其中。最初的目的是开发一套提供中间代码和编译基础设施的虚拟系统。 LLVM 命名最早源自于底层虚拟机(Low Level Virtual Machine)的缩写,随着 LLVM 项目的不断发展,原先的全称

    2024年02月09日
    浏览(54)
  • LLVM代码内容

    LLVM库包含所有LLVM顶层项目,可以分为以下几类: • LLVM核心库和附加内容 • 编译器和工具 • 运行时库         LLVM是一个编译器框架。LLVM作为编译器框架,是需要各种功能模块支撑起来的。可以将clang和lld都看做是LLVM的组成部分。框架的意思是,你可以基于LLVM提供的功能

    2024年01月20日
    浏览(33)
  • LLVM安装教程

    llvm下载页面:https://releases.llvm.org/download.html 方法一:从官网上下载预编译好的包 在Ubuntu 20.04安装LLVM 13.0.0 sudo mkdir -p /usr/local cd /usr/local sudo wget https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz sudo tar xvf clang+llvm-13.0.0-x86_64-linux-g

    2024年02月15日
    浏览(34)
  • PWN学习之LLVM入门

    ①找到runOnFunction函数时如何重写的,一般来说runOnFunction都会在函数表最下面,找PASS注册的名称,一般会在README文件中给出,若是没有给出,可通过对__cxa_atexit函数\\\"交叉引用\\\"来定位: ②通过逆向,找到函数名及参数,编写基本exp ③找到漏洞,写利用exp.c,其中的pwn的目标是

    2024年02月05日
    浏览(23)
  • 2401llvm,clang的libtooling

    LibTooling 是个支持基于 Clang 编写 独立工具 的库. 在此,为 LLVM 安装 Clang 工具 用 LibTooling 构建的工具(如 Clang 插件)通过代码运行 FrontendActions . 这里演示运行 Clang 的快速检查 一堆代码语法 的 SyntaxOnlyAction 的不同方法. 如果想对,如对 ClangAST 的某些部分 单元测试 的 代码 运行 F

    2024年01月23日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包