GCC 3
Section: GNU Tools (1)
Updated: 2003/12/05
调试选项
(DEBUGGING OPTION)
GNU CC
拥有许多特别选项
,
既可以调试用户的程序
,
也可以对
GCC
排错
:
-
以操作系统的本地格式
(stabs, COFF, XCOFF,
或
DWARF).
产生调试信息
. GDB
能够使用这些调试信息
.
在大多数使用
stabs
格式的系统上
, `
-g
‘
选项启动只有
GDB
才使用的额外调试信息
;
这些信息使
GDB
调试效果更好
,
但是有可能导致其他调试器崩溃
,
或拒绝读入程序
.
如果你确定要控制是否生成额外的信息
,
使用
`
-gstabs+
‘, `
-gstabs
‘, `
-gxcoff+
‘, `
-gxcoff
‘, `
-gdwarf+
‘,
或
`
-gdwarf
‘ (
见下文
).
和大多数
C
编译器不同
, GNU CC
允许结合使用
`
-g
‘
和
`
-O
‘
选项
.
优化的代码偶尔制造 一些惊异的结果
:
某些声明过的变量根本不存在
;
控制流程直接跑到没有预料到的地方
;
某些语句因为计算结果是常量或已经确定而 没有执行
;
某些语句在其他地方执行
,
因为他们被移到循环外面了
.
然而它证明了调试优化的输出是可能的
.
对可能含有错误的程序使用优化器是合理的
.
-g
如果
GNU CC
支持输出多种调试信息
,
下面的选项则非常有用
.
-
以本地格式
(
如果支持
)
输出调试信息
,
尽可能包括
GDB
扩展
.
-
以
stabs
格式
(
如果支持
)
输出调试信息
,
不包括
GDB
扩展
.
这是大多数
BSD
系统上
DBX
使用的格式
.
-
以
stabs
格式
(
如果支持
)
输出调试信息
,
使用只有
GNU
调试器
(GDB)
理解的
GNU
扩展
.
使用这些扩展有可能导致 其他调试器崩溃或拒绝读入程序
.
-
以
COFF
格式
(
如果支持
)
输出调试信息
.
这是在
System V
第四版以前的大多数
System V
系统上
SDB
使用的 格式
.
-
以
XCOFF
格式
(
如果支持
)
输出调试信息
.
这是
IBM RS/6000
系统上
DBX
调试器使用的格式
.
-
以
XCOFF
格式
(
如果支持
)
输出调试信息
,
使用只有
GNU
调试器
(GDB)
理解的
GNU
扩展
.
使用这些扩展有可能导致 其他调试器崩溃或拒绝读入程序
.
-
以
DWARF
格式
(
如果支持
)
输出调试信息
.
这是大多数
System V
第四版系统上
SDB
使用的格式
.
-
以
DWARF
格式
(
如果支持
)
输出调试信息
,
使用只有
GNU
调试器
(GDB)
理解的
GNU
扩展
.
使用这些扩展有可能导致 其他调试器崩溃或拒绝读入程序
.
-ggdb
-gstabs
-gstabs+
-gcoff
-gxcoff
-gxcoff+
-gdwarf
-gdwarf+
-g
level
-ggdb
level
-gstabs
level
-gcoff
level
-gxcoff
level
-
请求生成调试信息
,
同时用
level
指出需要多少信息
.
默认的
level
值是
2.
Level 1
输出最少量的信息
,
仅够在不打算调试的程序段内
backtrace.
包括函数和外部变量的描述
,
但是 没有局部变量和行号信息
.
Level 3
包含更多的信息
,
如程序中出现的所有宏定义
.
当使用
`
-g3
‘
选项的时候
,
某些调试器支持 宏扩展
.
-
产生额外代码
,
用于输出
profile
信息
,
供分析程序
prof
使用
.
-
产生额外代码
,
用于输出
profile
信息
,
供分析程序
gprof
使用
.
-
产生额外代码
,
用于输出基本块
(basic block)
的
profile
信息
,
它记录各个基本块的执行次数
,
供诸如
tcov
此类的程序分析
.
但是注意
,
这个数据格式并非
tcov
期待的
.
最终
GNU
gprof
将处理这些数据
.
-
产生额外代码
,
用于从
‘bb.in’
文件读取基本块的
profile
参数
,
把
profile
的结果写到
‘bb.out’
文件
. `bb.in’
包含一张函数列表
.
一旦进入列表中的某个函数
, profile
操作就开始
,
离开最外层的函数后
, profile
操作就结束
.
以
`-‘
为前缀名的函数排除在
profile
操作之外
.
如果函数名不是唯一的
,
它可以写成
`/path/filename.d:functionname’
来澄清
. `bb.out’
将列出一些有效的文件名
.
这四个函数名具有 特殊含义
: `__bb_jumps__’
导致跳转
(jump)
频率写进
`bb.out’. `__bb_trace__’
导致基本块序列通过 管道传到
`gzip’,
输出
`bbtrace.gz’
文件
. `__bb_hidecall__’
导致从跟踪
(trace)
中排除
call
指令
. `__bb_showret__’
导致在跟踪中包括返回指令
.
-
编译的时候
,
在
letters
指定的时刻做调试转储
(dump).
用于调试编译器
.
大多数转储的文件名 通过源文件名添加字词获得
(
例如
`
foo.c.rtl
‘
或
`
foo.c.jump
‘).
-
预处理结束的时候转储所有的宏定义
,
不输出到文件
.
-
预处理结束的时候转储所有的宏名
.
-
预处理结束的时候转储所有的宏定义
,
同时进行正常输出
.
-
语法分析
(parse)
的时候在标准错误转储调试信息
.
-
RTL
阶段后转储到
`
file
.rtl
‘.
-
仅对函数生成
RTL,
而不是编译
.
通常和
`
r
‘
联用
.
-
第一次跳转优化后转储到
`
file
.jump
‘.
-
CSE (
包括有时候跟在
CSE
后面的跳转优化
)
后转储到
`
file
.cse
‘.
-
循环优化后转储到
`
file
.loop
‘.
-
第二次
CSE
处理
(
包括有时候跟在
CSE
后面的跳转优化
)
后转储到
`
file
.cse2
‘.
-
流程分析
(flow analysis)
后转储到
`
file
.flow
‘.
-
指令组合
(instruction combination)
后转储到
`
file
.combine
‘.
-
第一次指令安排
(instruction schedule)
后转储到
`
file
.sched
‘.
-
局部寄存器分配后转储到
`
file
.lreg
‘.
-
全局寄存器分配后转储到
`
file
.greg
‘.
-
第二次指令安排
(instruction schedule)
后转储到
`
file
.sched2
‘.
-
最后一次跳转优化后转储到
`
file
.jump2
‘.
-
推迟分支调度
(delayed branch scheduling)
后转储到
`
file
.dbr
‘.
-
寄存器
–
堆栈转换后转储到
`
file
.stack
‘.
-
产生以上所有的转储
.
-
运行结束后
,
在标准错误显示内存使用统计
.
-
在汇编输出加注指明使用了哪些模式
(pattern)
及其替代模式
.
-
交叉编译的时候
,
假定目标机和宿主机使用同样的浮点格式
.
它导致输出错误的浮点常数
,
但是在目标机上运行的时候
,
真实的指令序列有可能和
GNU CC
希望的一样
.
-
保存那些通常是
“
临时
”
的中间文件
;
置于当前目录下
,
并且根据源文件命名
.
因此
,
用
`
-c -save-temps
‘
选项编译
`
foo.c
‘
会生成
`
foo.cpp
‘
和
`
foo.s
‘
以及
`
foo.o
‘
文件
.
-
显示库文件
library
的全路径名
,
连接时会使用这个库
—
其他什么事情都不作
.
根据这个选项
, GNU CC
既不编译
,
也不连接
,
仅仅显示文件名
.
-
和
`
-print-file-name=libgcc.a
‘
一样
.
-
类似于
`
-print-file-name
‘,
但是查找程序
program
如
`
cpp
‘.
-gdwarf
level
-p
-pg
-a
-ax
-d
letters
-dM
-dN
-dD
-dy
-dr
-dx
-dj
-ds
-dL
-dt
-df
-dc
-dS
-dl
-dg
-dR
-dJ
-dd
-dk
-da
-dm
-dp
-fpretend-float
-save-temps
-print-file-name=
library
-print-libgcc-file-name
-print-prog-name=
program
优化选项
(OPTIMIZATION OPTION)
这些选项控制多种优化措施
:
-
优化
.
对于大函数
,
优化编译占用稍微多的时间和相当大的内存
.
不使用
`
-O
‘
选项时
,
编译器的目标是减少编译的开销
,
使编译结果能够调试
.
语句是独立的
:
如果在 两条语句之间用断点中止程序
,
你可以对任何变量重新赋值
,
或者在函数体内把程序计数器指到其他语句
,
以及从源程序中 精确地获取你期待的结果
.
不使用
`
-O
‘
选项时
,
只有声明了
register
的变量才分配使用寄存器
.
编译结果比不用
`
-O
‘
选项的
PCC
要略逊一筹
.
使用了
`
-O
‘
选项
,
编译器会试图减少目标码的大小和执行时间
.
如果指定了
`
-O
‘
选项
, `
-fthread-jumps
‘
和
`
-fdefer-pop
‘
选项将被 打开
.
在有
delay slot
的机器上
, `
-fdelayed-branch
‘
选项将被打开
.
在即使没有帧指针
(frame pointer)
也支持调试的机器上
, `
-fomit-frame-pointer
‘
选项将被打开
.
某些机器上 还可能会打开其他选项
.
-
多优化一些
.
除了涉及空间和速度交换的优化选项
,
执行几乎所有的优化工作
.
例如不进行循环展开
(loop unrolling)
和函数内嵌
(inlining).
和
-O
选项比较
,
这个选项既增加了编译时间
,
也提高了生成代码的 运行效果
.
-
优化的更多
.
除了打开
-O2
所做的一切
,
它还打开了
-finline-functions
选项
.
-
不优化
.
如果指定了多个
-O
选项
,
不管带不带数字
,
最后一个选项才是生效的选项
.
-O
-O1
-O2
-O3
-O0
诸如
`
-f
flag
‘
此类的选项描述一些机器无关的开关
.
大多数开关具有肯定和否定两种格式
; `
-ffoo
‘
开关选项的否定格式应该是
`
-fno-foo
‘.
下面的列表只展示了一种格式
—
那个不是 默认选项的格式
.
你可以通过去掉或添加
`
no-
‘
构造出另一种格式
.
-
不要在寄存器中存放浮点变量
.
这样可以防止某些机器上不希望的过高精度
,
如
68000
的浮点寄存器
(
来自
68881)
保存的精度超过了
double
应该具有的精度
.
对于大多数程序
,
过高精度只有好处
.
但是有些程序严格依赖于
IEEE
浮点数的定义
.
对这样的程序可以使用
`
-ffloat-store
‘
选项
.
-
使用探索法
(heuristic)
进行更快的编译
(
仅对
C++).
默认情况下不使用探索法
.
由于探索法只对某些输入文件 有效
,
其他程序的编译速度会变得更慢
.
第一次编译器必须对成员函数
(
或对成员数据的引用
)
建立一个调用
.
它必须
(1)
判断出这个类是否实现了那个名字的 成员函数
; (2)
决定调用哪个成员函数
(
涉及到推测需要做哪种类型转换
); (3)
检查成员函数对调用者是否可见
.
所有这些构成 更慢的编译
.
一般情形
,
第二次对成员函数
(
或对成员数据的引用
)
建立的调用
,
必须再次经过相同长度的处理
.
这意味着象 这样的代码
cout << “This ” << p << ” has ” << n << ” legs./n”;
对整个三步骤要做六次遍历
.
通过使用软件缓存
, “
命中
”
能够显著地减少这种代价
.
然而不幸的是
,
使用这种缓存 必须实现其他机制
,
带来了它自己的开销
. `
-fmemoize-lookups
‘
选项打开软件缓存
.
因为函数的正文环境不同
,
函数对成员和成员函数的访问权
(
可见性
)
也可能不同
,
g++
可能需要刷新缓存
.
使用
`
-fmemoize-lookups
‘
选项
,
每编译完一个函数就刷新缓存
.
而
`-fsave-memoized’
选项 也启用同样的缓存
,
但是当编译器发觉最后编译的函数的正文环境产生的访问权和下一个待编译的函数相同
,
编译器就 保留缓存内容
.
这对某个类定义许多成员函数时非常有用
:
除了某些其他类的友函数
,
每个成员函数拥有和其他成员函数完全一样 的访问权
,
因而无需刷新缓存
.
-
默认为不要把成员函数内嵌
,
因为它们定义在类的作用域内
(
仅
C++).
-
一旦函数返回
,
参数就立即弹出
.
对于那些调用函数后必须弹出参数的机器
,
编译器一般情况下让几次函数调用的参数 堆积在栈上
,
然后一次全部弹出
.
-
做数学运算前把将要使用的内存操作数送入寄存器
.
通过把内存访问转换成潜在的公共子表达式
,
它可能产生较好的目标码
.
如果它们不是公共子表达式
,
指令组合应该消除各自的寄存器载荷
.
我乐意倾听不同意见
.
-
做数学运算前把将要使用的内存地址常数送入寄存器
.
它可能和
`
-fforce-mem
‘
一样产生较好的 目标码
.
我乐意倾听不同意见
.
-
对于不需要帧指针
(frame pointer)
的函数
,
不要在寄存器中保存帧指针
.
这样能够避免保存
,
设置和恢复 帧指针的指令
;
同时对许多函数提供一个额外的寄存器
.
但是在大多数机器上将无法调试
.
某些机器上
,
如
Vax,
这个选项无效
,
因为标准调用序列自动处理帧指针
,
通过假装不存在而不保存任何东西
.
机器描述宏
FRAME_POINTER_REQUIRED
控制目标机是否支持这个选项
.
-
把所有简单的函数集成进调用者
.
编译器探索式地决定哪些函数足够简单
,
值得这种集成
.
如果集成了所有给定函数的调用
,
而且函数声明为
static
,
那么一般说来
GCC
有权不按汇编代码输出函数
.
-
允许在寄存器里分配数值
,
但是这个方案通常受到各个函数调用的冲击
,
因此
GCC
生成额外的代码
,
在函数调用的 前后保存和复原寄存器内容
.
仅当生成代码看上去优于反之结果时才实现这样的分配
.
某些机器上该选项默认为允许
,
通常这些机器没有调用保护寄存器代替使用
.
-
即使集成了某个函数的所有调用
,
而且该函数声明为
static
,
仍然输出这个函数一个独立的
,
运行时可调用 的版本
.
-
不要把函数地址存入寄存器
;
让调用固定函数的指令显式给出函数地址
.
这个选项产生效率较低的目标码
,
但是如果不用这个选项
,
某些不寻常的
hack,
改变汇编器的输出
,
可能因优化而带来 困惑
.
-
禁止任何机器相关的
peephole
优化
.
-
这个选项出于速度优化
,
允许
GCC
违反某些
ANSI
或
IEEE
规则
/
规格
.
例如
,
它允许编译器假设
sqrt
函数的参数是非负数
.
这个选项不被任何
`
-O
‘
选项打开
,
因为对于严格依靠
IEEE
或
ANSI
规则
/
规格实现的数学函数
,
程序可能 会产生错误的结果
.
-ffloat-store
-fmemoize-lookups
-fsave-memoized
-fno-default-inline
-fno-defer-pop
-fforce-mem
-fforce-addr
-fomit-frame-pointer
-finline-functions
-fcaller-saves
-fkeep-inline-functions
-fno-function-cse
-fno-peephole
-ffast-math
下列选项控制特定的优化
. `
-O2
‘
选项打开下面的大多数优化项
,
除了
`
-funroll-loops
‘
和
`
-funroll-all-loops
‘
项
.
而
`
-O
‘
选项通常打开
`
-fthread-jumps
‘
和
`
-fdelayed-branch
‘
优化项
,
但是特定的机器上的默认优化项有可能改变
.
如果特别情况下非常需要
“
微调
”
优化
,
你可以使用下面的选项
.
-
执行循环强度缩小
(loop strength reduction)
优化
,
并且消除重复变量
.
-
执行优化的地点是
,
如果某个跳转分支的目的地存在另一个条件比较
,
而且该条件比较包含在前一个比较语句之内
,
那么 执行优化
.
根据条件是
true
或者
false,
前面那条分支重定向到第二条分支的目的地或者紧跟在第二条分支后面
.
-
执行循环展开
(loop unrolling)
优化
.
仅对循环次数能够在编译时或运行时确定的循环实行
.
-
执行循环展开
(loop unrolling)
优化
.
对所有循环实行
.
通常使程序运行的更慢
.
-
在公共子表达式消元
(common subexpression elimination)
的时候
,
如果没有其他路径到达某个跳转的 目的地
,
就扫过这条
jump
指令
.
例如
,
如果
CSE
遇到带有
else
从句的
if
语句
,
当条件测试为
false
时
, CSE
就跟在
jump
后面
.
-
它类似于
`
-fcse-follow-jumps
‘
选项
,
但是
CSE
跟在条件跳转后面
,
条件跳转跳过了 语句块
(block).
如果
CSE
遇到一条简单的
if
语句
,
不带
else
从句
, `
-fcse-skip-blocks
‘
选项将导致
CSE
跟在
if
产生的跳转后面
.
-
执行循环优化后
,
重新进行公共子表达式消元
.
-
如果看上去合理就省略构造子
(
仅
C++).
根据这个选项
,
对于下面的代码
, GNU C++
直接从调用
foo
初始化
y
,
而无需通过临时变量
:
A foo (); A y = foo ();
如果没有这个选项
, GNU C++
首先通过调用类型
A
合适的构造子初始化
y
;
然后把
foo
的结果赋给临时变量
;
最后
,
用临时变量替换
`
y
‘
的初始值
.
ANSI C++
标准草案规定了默认行为
(`
-fno-elide-constructors
‘).
如果程序的构造子存在 副效应
, `
-felide-constructors
‘
选项能够使程序有不同的表现
,
因为可能忽略一些构造子的调用
.
-
执行一些相对开销较大的次要优化
.
-
如果对目标机支持这个功能
,
它试图重新排列指令
,
以便利用延迟分支
(delayed branch)
指令后面的指令空隙
.
-
如果对目标机支持这个功能
,
它试图重新排列指令
,
以便消除因数据未绪造成的执行停顿
.
这可以帮助浮点运算或内存访问 较慢的机器调取指令
,
允许其他指令先执行
,
直到调取指令或浮点运算完成
.
-
类似于
`
-fschedule-insns
‘
选项
,
但是在寄存器分配完成后
,
需要一个额外的指令调度过程
.
对于 寄存器数目相对较少
,
而且取内存指令大于一个周期的机器
,
这个选项特别有用
.
-fstrength-reduce
-fthread-jumps
-funroll-loops
-funroll-all-loops
-fcse-follow-jumps
-fcse-skip-blocks
-frerun-cse-after-loop
-felide-constructors
-fexpensive-optimizations
-fdelayed-branch
-fschedule-insns
-fschedule-insns2
目标机选项
(TARGET OPTION)
缺省情况下
, GNU CC
编译出本机类型的目标码
.
然而也可以把他安装成交叉编译器
,
为其他机型编译程序
.
事实上
,
针对不同的目标机
,
可以同时安装
GNU CC
相应的配置
.
然后用
`
-b
‘
选项指定 目标机种
.
顺便提一下
,
新版本和旧版本的
GNU CC
可以共存
.
其中一个版本
(
可能是最新的那个
)
为缺省版本
,
但是有时候你希望使用 其他版本
.
-
参数
machine
指出编译的目标机种
.
这个选项用于安装为交叉编译器的
GNU CC.
参数
machine
的值和配置
GNU CC
交叉编译器时设置的机器类型一样
.
例如
,
如果交叉编译器配置有
`
configure
i386v’,
意思是编译
80386
上的
System V
目标码
,
那么你可以通过
`
-b i386v
‘
运行交叉编译器
.
如果没有指定
`
-b
‘
选项
,
通常指编译本机目标码
.
-
参数
version
指出运行哪个版本的
GNU CC.
这个选项用于安装了多个版本的
GCC.
例如
,
如果
version
是
`
2.0
‘,
意味着运行
GNU CC 2.0
版
.
如果没有指定
`
-V
‘
选项
,
缺省版本取决于
GNU CC
的安装方式
,
一般说来推荐使用通用版本
.
-b
machine
-V
version