Electronic Joint Business

Solution for E-Business

GCC工具链

Binutils 移植指南 (一)

本文是对 binutils 现有文档的补充,旨在帮助那些第一次将 binutils 工具移植到新的硬件架构的软件工程师。本文是根据作者的实际经验编写的。难免会有疏漏,欢迎读者提出任何改善建议。1

一、 为什么编写本文?
虽然 binutils 项目包含了 100 多页的内部指南, 但本文主要针对那些初次进行 binutils 开发/移植的人。Binutils 内部指南存在一些缺陷:

  • 它倾向于对每个函数进行详细描述,但缺乏宏观大局。
  • 文档并不完整,有许多有用的章节尚待编写。(例如relocation详细信息) 。

因此,当工程师初次尝试将 binutils 移植到新的架构上时,他总要不断阅读源代码来弄明白 binutils 如何工作,进而了解如何移植到其他体系架构。

本文将讨论如何将紧凑 RISC (又称 CR16) 体系结构植入 binutils , 希望这些学习经验可以帮助到其他人, 特别是那些正在寻找将 binutils 工具移植到新架构的工程师。CR16 的相关代码可以在 binutils 中获得。

二、Binutils 文件的组织结构
binutils 源代码按目录进行组织,其中的一些组件是类库,在内部或其他项目中使用。比如 GNU GDB 调试器会用到 BDF 类库。这些类库大多有自己的顶层目录。主要的目录列举如下:

这些目录包含如下组件:

>>> 阅读全文

 

LLVM 简介

本文将讨论让 LLVM 成型的一些设计策略。LLVM 是个一揽子项目(a umbrella project),用于支持和开发一系列紧密相关的底层工具组件(例如汇编器、编译器、调试器等等),从设计之初,LLVM 就考虑兼容现在广泛使用的 Unix 系统工具。 起初 “LLVM” 这个名字是个缩写,现在则是这个一揽子项目的品牌。虽然 LLVM 提供了独特的功能,并因其强大的工具而闻名(例如 Clang 编译器, 一个比 GCC 更强大的 C/C++/Objective-C 编译器),但真正让 LLVM 有别于其他编译器的地方是在其内部架构。

从诞生之初(2000年12月),LLVM 就被设计成一组具有定义良好接口的、可重用的库。当时,开源的编程语言的实现通常按专用工具来设计的,一般只能不可分割地运行(monolithic executables)。比方说,很难从类似 GCC 这样的静态编译器中将解析器分离出来用在静态分析或者重构。而脚本语言大多都提供了将运行时或解释器嵌入大型应用的方法,该运行时也是一个完整的、不可分割的可以被嵌入或者单独使用的代码块。不同语言实现项目之间根本无法重用部件,代码也很难共享。

除了编译器本身的组成外,围绕流行语言的社区往往呈现出很强的两极化倾向:有些实现提供了传统的静态编译器(如 GCC, Free Pascal 和 FreeBasic), 而有的实现则以解释器或JIT(Just-In-Time)编译器的形式提供了运行时编译器。但是很少有实现同时提供两者,即使有的话,两者也极少共享代码。

过去十多年中,LLVM 慢慢改变了这种困境。现在,LLVM 被作为一个通用的基础框架实现了很多静态编译或运行时编译的语言(例如,GCC 支持的语言族、Java、.NET、Python、Ruby、Scheme、Haskell、D语言以及许多的知名度稍低的语言)。它也取代了很多专用编译器,像苹果公司 OpenGL 栈中的运行时特化引擎(runtime specialization engine)以及 Adobe 公司 After Effects 产品中的图形处理库。最后,LLVM 也用来创建各种新产品,最出名的应该算是 OpenCL GPU 编程语言和运行时了。

传统编译器设计简介
传统的静态编译器设计(如大多数 C 编译器)中采用的最普遍的方案就是三阶段编译,该设计主要由三个组件组成,分别是前端、优化器和后端(如图1-1所示)。前端负责解析源代码,检查错误,并构建语言相关的抽象语法树(AST)。AST 可根据情况转换为便于优化的新表示方式, 优化器和后端针对这种新表示而运行。

>>> 阅读全文

 

, , , , , ,

阅读 Grub 源代码 (一) X86 汇编及 GAS 语法

文章评价:

简介
本文的例子采用 AT&T 汇编语法编写,并用 GNU AS 编译的。该语法的主要优点是它与 GCC 内嵌汇编保持着语法兼容性。不过,这并不是表示 X86 操作符唯一语法。例如,NASM、MASM 就使用了完全不同的语法来表示助记符,操作数和寻址模式及其他高级汇编特性。 AT&T 的语法是类 Unix 系统上的标准,但其他使用 Intel 语法的汇编器,比如 GAS 本身,两种语法都可以接受。

GAS 是 GNU 项目的一部分,它具有可以自由使用、适用于多种操作系统、和 GNC 编译器 (gcc) 和 GNU 链接器 (ld) 等编程工具接口良好等等特点。

如果使用安装了 Linux 操作系统的电脑,通常默认就安装了 GAS。如果使用的是 Windows 操作系统,则可以安装 Cygwin 或者 MinGW 来获得 GAS 和其他编程工具。

GAS 指令一般都采用“ 助记符 源,目的地 ”的格式。例如,下面的 mov 指令:

>>> 阅读全文

 

, , , , , ,

用 autoconf 和 automake 生成 makefile

文章评价:
在 Unix/Linux 上编写程序的人大都遇到过 Makefile,尤其是使用 C/C++ 语言的开发者。用 make 来开发和编译程式的确很方便,可是要编写一个 Makefile 就不那么简单了。而且介绍 Makefile 的资料并不多,GNU Make 那份打印出来要几百页的文件,光看完序言就是花不少时间,难怪许多人谈 Unix 编程而色变。

本文将介绍如何利用 GNU Autoconf 及 Automake 这两套软件来帮助我们“自动”生成 Makefile 文件,让开发出来的软件可以像 Apache,MySQL 等常见应用一样,只要输入 “ ./configure ”, “ make ”,“ make install” 就可以把编译结果安装到系统中。

如果您有心开发开源软件,或主要是在 Unix/Linux 系统下编写程序。希望这份介绍文件能帮助您轻松地进入 Unix/Linux 编程的殿堂。

简介
Makefile 基本上就是“目标”(target), “依赖”(dependencies) 和“动作”三者所组成的一连串规则。而 make 就会根据 Makefile 的规则来决定如何编译 (compile) 和链接 (link) 程序。实际上,make 可做的不只是编译和链接程序,例如 FreeBSD 的 port collection 中,Makefile 可以自动去下载原始程式包,解压缩 (extract) ,打补丁 (patch),然后运行设定并编译,最后安装至系统中。

Makefile 基本构造虽然简单,但如能妥善运用这些规则就也可以玩出许多不同的花样。却也因此,许多人刚开始学习写 Makefile 时会感到没有规范可循,每个人写出来的 Makefile 长得都不太一样,不知道从何下手,而且常常会受限于自己的开发环境,只要环境参数不同或路径被修改一下,可能就需要跟着修改 Makefile。虽然有 GNU Makefile Conventions (GNU Makefile 惯例) 订出一些使用 GNU 程序设计时撰写 Makefile 的一些标准和规范,但是内容很长而且很复杂, 并且经常调整。为了减轻程序设计师维护 Makefile 的负担, GNU 推出了 Automake 这个工具。

>>> 阅读全文

 

, , , ,

GCC 4.6.0 编译优化选项

应该谨记在心的是,:“使用编译器优化得到的小幅度性能提升,与它带来的风险相比微不足道” — 源自 LFS-Book.

追求极致的优化是一件既耗时又麻烦的事情,你会陷入无止尽的测试、测试、再测试…所以优化应当适可而止为好,将精力留出来用在程序算法的优化上会有更有意义。此本文的主旨是针对 GCC 4.6.0 的优化选项给出一个完整和清晰的脉络,仅仅作为参考。

GCC 编译的基本过程
在 Unix 环境下(包括 Unix、Linux、MSYS 和 Cygwin 等等),软件源代码大多提供了 configure 脚本,该脚本一般都会有许多配置选项,其中有不少选项是与性能息息相关的。对于每个特定的软件包,在编译前应该使用 configure –help 查看所有选项,并精心选择有关选项。运行 configure 脚本后会生成有关项目的 Makefile。将源代码编译为二进制文件是在 Makefile 文件的指导下,由 make 程序调用一条条编译命令完成的。而将源代码编译为二进制文件又需要经过以下四个步骤:预处理(cpp) → 编译(gcc或g++) → 汇编(as) → 连接(ld) ;括号中表示每个阶段所使用的程序,它们分别属于 GCC 和 Binutils 软件包。

尽管将源代码编译为二进制文件的四个步骤由不同的程序( cpp,gcc/g++,as,ld)完成,但是事实上 cpp, as, ld 都是由 gcc/g++ 进行间接调用的。换句话说,控制了 gcc/g++ 就等于控制了所有四个步骤。

显然的,优化应当从编译工具自身的选择以及控制编译工具的行为入手。本文以 Binutils-2.21.1 和 GCC-4.6.1为例进行说明。

>>> 阅读全文

 

,

了解Linux操作系统 (二)Linux内存架构

文章评分:

为了执行进程,Linux 内核会为请求的进程分配一段内存区域。进程用这段内存作为工作区来执行所请求的工作。这就像你申请了一张办公桌,你可以在桌面上摆放工作所需的纸张、文件和备忘录。不同之处是 Linux 内核采用动态的方法来分配内存空间。在内存大小通常是有限的情况下有时进程的数量会达到数万个,Linux 内核必须有效地来管控内存。在本章节中,我们会介绍内存的结构、地址分布,以及Linux是怎样有效地管理内存空间的。

物理内存与虚拟内存

如今我们面临选择 32 位系统或者 64 位系统的问题。对于企业级用户来说,最重要的区别就是虚拟内存地址是否可以超过 4GB。从性能角度来看,弄明白32 位和64 位 Linux 内核是怎么样将物理内存映射到虚拟内存是非常有意思的。

在图1-10中,你可以很明显的看出 32 位系统和 64 位系统在内存地址分配上的不同之处。关于物理内存映射到虚拟内存的详细内容已超出本文的范畴,本文将只着重介绍Linux内存结构的部分细节。

>>> 阅读全文

 

,

Gnu Binutils 命令小结

我们知道, gcc(gnu collect compiler)是一组编译工具的总称,包括c,c++等等,它主要完成的工作任务是“预处理”和“编译”,以及提供了与编译器紧密相关的运行库的支持,如libgcc_s.so、libstdc++.so等。

而binutils提供了一系列用来创建、管理和维护二进制目标文件的工具程序,binutils与gcc是紧密相集成的,没有binutils的话,gcc是不能正常工作的。 Binutils提供了一下的工具,主要有:
addr2line 把程序地址转换为文件名和行号。在命令行中给它一个地址和一个可执行文件名,它就会使用这个可执行文件的调试信息指出在给出的地址上是哪个文件以及行号。

ar建立、修改、提取归档文件。归档文件是包含多个文件内容的一个大文件,其结构保证了可以恢复原始文件内容。

as主要用来编译GNU C编译器gcc输出的汇编文件,产生的目标文件由连接器ld连接。

c++filt 连接器使用它来过滤 C++ 和 Java 符号,防止重载函数冲突。

>>> 阅读全文

 

, ,

从MinGW交叉编译出MinGW64

MinGW一直没有推出64位的版本,因此在SF.NET上又有一个新的项目叫 MinGW64,虽然大家支持的都是 GCC,但是两个项目是有一些区别的,除了前面提及的32位版和64位版的问题外,主要是二者的运行时不尽相同,MinGW64 重写了自己的 MinGW 运行时,称为 MinGW-W64,和 MinGW 相比,其运行时支持的 Windows API 更多一些。

但是 MinGW64 上发布的二进制包中,缺少一些很有意思的语言工具,比如 ada。而编译ada要求GCC中一定要有 gnat(即 ada 编译器)存在,而目前只有 MinGW 才提供了 ADA 编译器,所以我们必须回到起点,从32位的 MinGW 逐步交叉编译 MinGW64。

这个过程会用到的工具有:MinGW 和 MSYS 的二进制包和以下源代码包,包括:binutils (2.22), GCC (4.7.0),MinGW-W64运行时(2.0.2), gmp (5.0.1), mpfr (3.1.0), MPC (0.9)。 要求 MinGW 中 GCC 工具的版本,最好要编译的源代码一直,避免出现低版本的 GNAT 无法识别高版本的 ADA 语法而报错。

一切就绪之后,可以开始解压源代码包,并将 gmp,mpfr 和 mpc 拷贝到 gcc-4.7.0 的目录中,并去掉名字中的版本号。 我们下来首先会构造出交叉编译的工具来。

创建32位交叉编译环境
1. 创建临时工作目录
我们的32位交叉编译环境将要被发布到 C:\\tools 目录下,打开DOS窗口,创建一个文件夹 tools。之后在 MSYS 安装目录下找到 etc 文件夹里的 fstab 文件,添加一行:

>>> 阅读全文

 

, , , ,

使用MinGW64编译GCC 4.6和4.7

gcc 4.6.0简介
GNU在3月25日正式放出了GCC 4.6.0的Tarball,不过在GNU的站点上也可以下载到GCC 4.7的Snapshot,你可以从GCC SnapShot站点, 下载到最新的版本。GCC 4.7的编译过程和GCC 4.6一致。

GCC 4.6支持以下这样一些新特性。除了支持一些新的鸡肋语言,比如Go,主要更新亮点有:

  • 大大改进了过程间分析和链接时优化。
  • 增加了128位浮点数支持,这个在科学计算领域应该很有用,X86和安腾系的芯片首先得益。
  • 一些详细的细节包括:

  • 增加更强力的编译优化选项-ofast,这个选项除了打开-O3的所有优化外,还开启了所有能开启的优化,以获得更好的性能,如-ffast-mast优化
  • 改进链接时优化(LTO): ◦全局可扩展优化器已经足够稳定。打开LTO后会默认开启此优化。该优化器可以自动分割成几个并行的编译过程,可以用选项-flto=n指定并行编译进程个数。
  • 增加-fstack-usage选项。编译器可以输出程序的栈使用信息
  • 你还可以参考GCC 4.6的release notes,该页面上有更详细的信息。

    准备工作
    为了开始编译GCC,你需要安装一份MinGW64的拷贝和MSYS。我们首先安装MinGW64,将其压缩包解开即可,在本文中MinGW64为C:\MinGW64。

    >>> 阅读全文

     

    , ,

    在 Eclipse 中集成 MinGW64 开发环境

    文章评价:

    本文主要讨论如何集成 Eclipse 和 MinGW64 来进行 C/C++ 应用程序的开发。由于不同版本 Eclipse CDT 的稳定性表现不一,因此需要你合理选择 Eclipse 的版本,现在已知 Helios (Eclipse 3.6) 的 CDT 在开发中会频繁崩溃,不建议使用。本文选择的是 Eclipse 4.3.1 来讲解,其他版本方法基本相同。

    GCC编译器
    首先要做的是下载一个合适的 MinGW64 编译器。要开发并运行 64 位的 Windows 应用,你可以选择 32 位的 GNU C/C++ 编译器并通过交叉编译来产生 64 位应用, 也可以选择纯 64 位的编译器。在 MinGW64 的官方站点上提供了许多不同的版本,你可以在 EJB.CC 下载到 GCC 4.6.1 for Windows ,或者在SourceForge.net上选择最新的版本。

    同时还需用到 MSYS(在 MinGW 的站点上提供),MSYS 提供一些常见的 Linux 命令工具用于 Windows GCC 的编程开发,目前只有 32 位版本,不过不会对代码生成有任何影响。

    接下里要做的就是为 Eclipse 安装最新的 CDT,目前 Galieo 只支持 CDT 6.0,Helios 则支持 CDT 7.0,而 Indigo 则支持 CDT 8.0,以此类推。如果你下载的 Eclipse 并未集成 CDT,你可以从 “Help” 菜单下选择 “install new software”,之后在 “avaiable software” 中的 “programming languages” 中选择各个 C++ 子项并安装。

    >>> 阅读全文

     

    , , , , ,