编译器开发入门指南

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

编译器开发入门指南GNUToolChain为例通常的选择--GNUToolChain•事实上的工业标准,绝大部分* N I X软件都用GCC编译•久经考验,代码质量还不错,bug少!•完善的生态环境,binutilsgdbglibc以及众多针对GCC开发的软件•广泛的用户群,巨大的影响•IBMAdaCoreCodeSourceryRedHatIntelGoogle等有实力的厂商支持•开发维护成本低,对中小型企业非常划算其他的选择--LLVM•非常先进的设计,非常清晰的结构,非常好懂的代码!•iOS众多app检验质量很好•OpenCL新版CUDA等最新技术都基于LLVM去开发•生态环境还不成熟•对GCC兼容还不是100%•AppleNVIDIAAMDXilinx等有实力的厂商自己开发维护得起移植就是抄抄改改•明确自己处理器的需求•找现有的相似的实现去改•基本上就是copyandmodify•结合gccint去抄•边抄边看边学边改binutils移植的要点•符号表,tc-machine后端,bfd,基本上就改这几个地方,没什么文档,自己看代码吧,不难•gas就一个工作,text2binary,牢记这个,因为现在gas有很多地方好像要做正确性检查,容易让人多想•text2binary最重要的就是position!bit的positionbfd部分修改•bfd/archures.c中#definebfd_mach_mips_XXX的定义•bfd/bfd-in2.h中#definebfd_mach_mips_XXX的定义•bfd/cpu-mips.c中匿名enum增加I-mipsXXX项,arch_info_struct数组增加对应描述•bfd/elfxx-mips.c中_bfd_elf_mips_mach和mips_set_isa_flag函数增加对应case选择分支,并在mips_mach_extensions数组中增加你的描述项elf部分修改•binutils/readelf.c中get_machine_flags函数增加一个对应的case描述选项•include/elf/mips.h中增加#defineE_MIPS_MACH_XXX的定义反汇编支持•opcodes/mips-dis.c中增加对应开关选项即可一个完整的opcode分析•{baddu,d,v,t,0x70000028,0xfc0007ff,WR_d|RD_s|RD_t,0,I1}•baddu就是指令名字,汇编代码里面的助记符•0x70000028是假设add指令的操作数都是0的情况下整条指令的编码•0xfc0007ff是用来区分操作码的,mask和match与出来的结果就是操作码•#defineIOCTINSN_OCTEON让我们找到了#defineINSN_OCTEON0x00000800•值得解释的是membership是一个32位的bit表示,每一位代表一种体系,而INSN_CHIP_MASK恰恰mask出来有效的位•dvt这些args是核心所在,#defineOP_MASK_RD0x1f代表了d这个arg描述的操作数占5位•而#defineOP_SH_RD11则表示d这个arg描述的操作数是从11位开始的•pinfo域跟args的定义是一样的,pinfo是对操作数的一个额外描述,可以用来检查操作数是否合法也可以用做自己想要的意图•pinfo如果是MACRO的话,这个指令就会先被macro函数展开成实际指令gas后端支持代码•machine_ip处理一个指令,主要工作是通过args匹配操作数并INSERT_OPRAND•validate_mips_insn从语法上检查指令是否合法•macro通过macro_build来把宏指令分解•指令表里面写的args和pinfo在这里被当做处理操作数的依据binutils的调试•出错提示仅仅是一个提示,造成这个错误的往往是你修改的opcode或者tc-machine.c•gdb-q$AS$ARGS•虽然有人很不屑,print确实是个简单直观有效的手段binutils的验证•objdump-S一条指令一条指令的查看二进制是否正确,当然,有模拟器的话,就轻松多了gcc移植要点•gcc就是text2text,很多地方就是字符串替换,没有过多的含义•gcc的port其实是一个逆向的过程,从指令去匹配rtl,而不是从rtl来匹配指令•gccint是目前最好的文档,可以看gccint-zh,理解代码是唯一的出路,文档太少了gcc外围支持代码•gcc/config/mips/driver-native.c中添加-march=XXX的开关代码•gcc/config/mips/mips.h中processor_type添加PROCESSOR_XXX,同时定义#defineTARGET_XXX(mips_arch==PROCESSOR_XXX)和#defineTUNE_XXX(mips_tune==PROCESSOR_XXX)•gcc/config/mips/mips.h中还有N多宏,根据你的处理器的情况添加相应的开关•gcc/config/mips/mips.c中的mips_cpu_info_table添加{orion,PROCESSOR_R4600,3,0}的描述项•gcc/config/mips/mips.c中的mips_rtx_cost_data添加对应的cost描述项mips.h中几个重要的宏•#defineFIRST_PSEUDO_REGISTER188•#defineFIXED_REGISTERS•#defineCALL_USED_REGISTERS•#defineCALL_REALLY_USED_REGISTERS•#defineGP_REG_FIRST0•#defineGP_REG_LAST 31•#defineGP_REG_NUM (GP_REG_LAST-GP_REG_FIRST+1)•enumreg_class•#defineREG_CLASS_NAMES•#defineREG_CLASS_CONTENTS•#defineREG_ALLOC_ORDER•#defineREGISTER_NAMES一个完整的rtl例子•(define_insnaddmode3•  [(set(match_operand:VWHB0register_operand=f)•     (plus:VWHB(match_operand:VWHB1register_operandf)•          (match_operand:VWHB2register_operandf)))]•  TARGET_HARD_FLOAT&&TARGET_LOONGSON_VECTORS•  paddV_suffix\t%0,%1,%2•  [(set_attrtypefadd)])•define_insnaddmode3•是这个模式的名字,总要有个名字吧,匿名的一般用来组成其他模式,比如define_expand定义的模式•可以映射到一个指令的define_insn,不能需要分解的define_expand•match_operand:VWHB是用来匹配操作数的•三个操作数,分别是012•=表示这个操作数是被赋值,或者说被写入的•很明显呢,都是寄存器操作数•f代表浮点数,由constraints.md中定义,用来约束操作数的•plus,明显的加模式,可以认为是RTL的内部操作•VWHB是模式,这条指令匹配的机器模式•paddV_suffix\t%0,%1,%2就是指令摸版,还记得前面的012么?•set_attr就算指令的一个分类吧•HARD_REG那个条件宏是判断有浮点寄存器并且是龙芯向量指令才会匹配这个模式,就是说满足这个宏才匹配下面的指令摸版迭代器的使用•mode是一个迭代器,使用迭代器可以大量减少重复代码,迭代器内容定义如下,最终匹配的模式被替换成对应的字符串•(define_mode_iteratorVB[V8QI])•(define_mode_iteratorVH[V4HI])•(define_mode_iteratorVW[V2SI])•(define_mode_iteratorVHB[V4HIV8QI])•(define_mode_iteratorVWH[V2SIV4HI])•(define_mode_iteratorVWHB[V2SIV4HIV8QI])•(define_mode_iteratorVWHBDI[V2SIV4HIV8QIDI])另一个字符串替换•;;TheLoongsoninstructionsuffixescorrespondingtothemodesinthe•;;VWHBDIiterator.•(define_mode_attrV_suffix[(V2SIw)(V4HIh)(V8QIb)(DId)]) •这个显然是根据模式,来替换指令模板内容的•gcc的工作就是text2text,不要想太多gcc的调试•gcc-save-temps是个有用的参数,我们可以在无法正确编译代码的时候,通过这个参数保留i和s文件以供查找线索•出错提示仅仅是提示,不要怀疑公共代码,去你修改的md里面找原因,有些东西print比gdb要方便,自己打印log出来吧•xgcc-###是个好参数,让我们知道分别给cc1ascollect2的参数是什么,就可以gdb对应的参数了•gcc-fdump-tree-all是个输出所有中间pass处理的IR供我们找线索的好参数•make的时候指定CFLAGS+=-Wno-error避免一些Warning当Error处理带来的不必要麻烦gcc的验证•gcc-S是个人尽皆知的蠢办法,但是这足够有效•模拟器,模拟器是个好东西爱好者该怎么入门•在vendor工作会有一些资源,做起来难度会比较小,但是呢,一般vendor只要求port即可,想提高也很难•专门做编译的CodeSourceryPathScale等公司没有相当的实力又无法融入•你真的想做这个么?你确定你想做,后面的内容或许会对你有一丁点儿帮助GCC社区的开发形式•committee是每年summit上开黑会的,比较高端,GCC的"命运"由他们来满足FSF对赞助商的有偿赞助•maintainer也是有level的,global的level比较高,middle的也很强悍,x86这种复杂BE的也有实力。没有review权限和非主流Arch的portmaintainer相对就不是很powerful•剩下的人就在maillist里面发patch并且等待reviewaccept被commit,或者中间再让你改几次,要不就不理你或者拒绝你的代码学习gcc的建议•有个明确的目标,针对目标去边做边学,解决问题的原理和方法很重要,而不是变化非常快的gcc代码,有了解决问题的方法之后再去查代码实现•找一个你感兴趣的模块,从目录名,文件名,函数名,变量名上理解代码才是好办法,找不到的可以grep•代码的流程用gdb跟踪几遍,用笔和纸画下来如何融入社区开发?•订阅gcc和hellogcc的maillist,加入gcc和hellogcc的irc•svn最新的代码,makecheck发现并修正错误•grepFIXME或TODO,根据自己的意愿和能力去做•很多pass实现的不够好,阅读对应paper去完善算法•做插件,邢明杰的gcc-vcg-plugin是一个很好的例子如何去解gcc的bug•发现了编译错误,internalerror,或者编译OK运行出错,怎么定位bug?•首先确定源代码没有问题,用其他编译器编译运行都OK•internalerror就根据信息去gdb吧,一般会给出代码退出在哪个文件的多少行,根据这个信息可以推测错误的原因编译OK运行出错或者性能骤降或者其他诡异的问提如何定位bug•对比排除,O1O2O3的排除,发现问题在O?•通过下面命令

1 / 36
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功