gcc 杂项

来源:互联网 发布:淘宝 发票 搜索什么 编辑:程序博客网 时间:2024/05/22 11:57
----------------------------------------
gcc 的一些技巧。

----------------------------------------

查找,查看连接的库位置: gcc -v

预处理过程:gcc -E, 可以看到头文件及宏展开后的形态。

查找,查看宏定义位置,

cpp -dD 可以显示宏定义过程。 -dM 还能显示预定义宏。 cpp -dM /dev/null 显示纯系统定义宏

虽然我不能确定gcc 是否调用了cpp 来进行预处理(也许不是), 但把gcc 换成cpp, 再加上-dD 选项

确实可以达到目的。然后你可以按提示直接去浏览文件,以解除心中的疑惑!

什么都不用动,把gcc 换成 cpp, 加上-g3 选项,可以看到细节。

还有一个有用的技巧。向gcc 传递了-Wa,-alh 参数,生成了汇编列表文件,使我很欣慰!

不仅.s文件,.c 文件也可以,令我惊讶。用法很简单。有什么用呢?有用,...慢慢再说。 还可以有-dn选项,详细man as

另外: objdump -S <目标文件> 带c 源码的汇编文件, 内容比较简洁! 但是... 各有各的优缺点。

----------------------------------------

gcc -g3 能够使我们在gdb 中看到宏定义和宏值。

gdb 中: 对宏的用法

p XXXX

info macro XXXX

macro expand XXXX

----------------------------------------

gcc 生成map 文件,
-Wl,-map,<map-file>
传给ld 的选项 -Wl 后面的参数不能有空格。
举例:
gcc -o op_test op_test.o end.o  -Wl,-Map,1.map
----------------------------------------

gcc 生成prof. gcc -pg

man gcc 有对-pg 选项的说明, gcc --help 没有对该项的说明

需要运行程序,正常退出,才能生成gmon.out, 供gprof 分析

gprof (默认为-p -q) -p 统计,本职功能, -q call graph, -b 简短的,不输出对各参数的解释。

-A[symspec], 只关联指定函数

用法举例:

gprof ./test gmon.out -b

生成调用图片:

gprof ./test | gprof2dot.py -n0 -e0 | dot -Tpng -o output.png

gprof2dot 默认是部分函数调用图 -n0.5, 即影响小于5%的函数就不显示了。

-n0 -e0 显示全部函数调用,当然这样可能因为内容太多,显示比较混乱。

-s 选项, 不显示诸如模板,函数入口参数等,使函数名称显示更加简洁。


----------------------------------------

由以上命令可以解决程序中的符号定位问题。


gcc -M -MP -MF -MD -MT 是什么意思?

gcc -M 不是输出预处理结果,而是输出源文件的依赖关系,包括include 的头文件,

gcc -MF abc.Tpo 把依赖关系输出到指定的输出文件, 否则会输出到屏幕上, abc.Tpo是输出文件名

gcc -MP 对每一个头文件也生成  target.,这样当make 的时候,每个头文件必需存在,编译更严谨

上面三项常连用。

gcc -MD: 相当于 -M -MF, 使用了默认文件名--目标文件名加.d , 保存依赖关系

可见,它们都是为了target 的依赖关系而生。


gcc -MT: 指定一个新的target 名。


----------------------------------------
消除 warning: "unused parameter xxxx"警告
----------------------------------------
如下定义一个宏即可:
#define UNUSED(x) (void)x
举例:
UNUSED(argc);
UNUSED(argv);

----------------------------------------
在64位机器上,整形数不能直接转化为指针。提示如下警告:
cast to pointer from integer of different size
----------------------------------------
有时候由于参数定义等原因确实需要强制转换,如下形式可用。
先转为long, 再转为指针。
(void *)(long)int_value
~                                                               
----------------------------------------

判断gcc 到底连接的是哪一个库,是动态库还是静态库,库的全路径是什么?

我目前采用的办法是strace.


对于exe 或 或 so, 判断其动态库依赖关系可以用ldd,

例如:

[/pts/1@hjj ~/work/cube_httpd]$ ldd httpd
    linux-vdso.so.1 =>  (0x00007fff0fdff000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003a13c00000)
    libc.so.6 => /lib64/libc.so.6 (0x0000003a13800000)
    /lib64/ld-linux-x86-64.so.2 (0x0000003a13400000)


------------------------------------------------------------
问题. gcc 版本不一致出现的问题,查看gcc 版本,strings 命令
------------------------------------------------------------
./app_ref: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./app_ref)
软件编译时使用了较高版本的glibc: 要求glibc_2.14,  这是是gcc 4.6 编译的.
当前系统的glibc版本太低,
查看当前的glibc.
$ strings /lib64/libc.so.6 |grep -i glibc
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_PRIVATE
glibc 2.12
*** glibc detected *** %s: %s: 0x%s ***
发现最高支持到glibc 2.12.
这个是gcc 4.4 支持到的版本

降低app_ref 的gcc, 或升级本系统gcc, 问题可以解决.


----------------------------------------
volatile 变量:  禁止编译器优化选项。
----------------------------------------
例如:int i; for(i=0;i<1000;i++);
被优化为i=1000
mem[2]=0x1;mem[2]=0x2;mem[2]=0x3;
被优化为mem[2]=0x3;
大部分优化是可行的,它缩短了执行时间,同样达到了效果。但有时不是我们需要的。

void main(int argc,char *argv[])
{
    int i = 10;
    int a = i;
    printf("i=%d",a);
    //下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道
    __asm
    {
        mov dword ptr[ebp-4],20h
    }
    int b = i;
    printf("i=%d",b);
}
如上代码,编译器可能把b 直接优化成10. 因为编译器可能把i 读入寄存器中,例如%edx
然后把%edx 付给内存a, 又付给内存b, 它不知道内存i 内容已经变了。这不是我们所要的
告诉编译器i 是volatile, 编译器将不对i进行优化,将忠实于代码执行流程。



0 0
原创粉丝点击