gcc useage

C 语言经典的入门例子是 Hello World,下面是一示例代码:

#include <stdio.h>
int main(void)
{
printf(“Hello, world!n”);
return 0;
}

我们假定该代码存为文件‘hello.c’。要用 gcc 编译该文件,使用下面的命令:

$ gcc -g -Wall hello.c -o hello

默认情况下GCC 不会产生任何警告信息,选项 -Wall开启编译器几乎所有常用的警告──强烈建议你始终使用该选项

多个c文件编译时为:

$ gcc -Wall hello.c hello_fn.c -o newhello



写一个简单的 makefile 文件:

CC=gcc
CFLAGS=-Wall
hello: hello.o hello_fn.o
clean:
rm -f hello hello.o hello_fn.o

输入make。不加参数调用make时,makefile文件中的第一个目标被建立,从而生成可执行文件‘hello’:$ make
gcc -Wall -c -o hello.o hello.c
gcc -Wall -c -o hello_fn.o hello_fn.c
gcc hello.o hello_fn.o -o hello


一个源文件被修改要重新生成可执行文件,简单地再次输入 make即可。通过检查目标文件和依赖文件的时间戳,程序 make 可识别哪些文件已经修改并依据对应的规则更新其对应的目标文件:

$ vim hello.c (打开编辑器修改一下文件)
$ make
gcc -Wall -c -o hello.o hello.c
gcc hello.o hello_fn.o -o hello




创建文件calc.c

#include <math.h>
#include <stdio.h>

int main (void)
{
double x = 2.0;
double y = sin (x);
printf (“The value of sin(2.0) is %fn”, y);
return 0;
}

尝试单独从该文件生成一个可执行文件将导致一个链接阶段的错误:

$ gcc -Wall calc.c -o calc
/tmp/ccbR6Ojm.o: In function ‘main’:
/tmp/ccbR6Ojm.o(.text+0×19): undefined reference to ‘sin’

显式地指定它:

$ gcc -Wall calc.c /usr/lib/libm.a -o calc

可执行文件包含主程序的机器码以及函数库‘libm.a’中 sin 对应的机器码。

为避免在命令行中指定长长的路径,编译器为链接函数库提供了快捷的选项‘-l’。例如,下面的命令

$ gcc -Wall calc.c -lm -o calc

与我们上面指定库全路径‘/usr/lib/libm.a’的命令等价



尝试编译简单的 C++ 的经典程序 Hello world

#include <iostream>
int main(int argc,char *argv[])
{
std::cout << “hello, world”<< std::endl;
return 0;
}

将文件保存为‘hello.cpp’,用 gcc 编译,结果如下:

$ gcc -Wall hello.cpp -o hello
/tmp/cch6oUy9.o: In function`__static_initialization_and_destruction_0(int, int)’:
hello.cpp:(.text+0×23): undefined reference to`std::ios_base::Init::Init()’
/tmp/cch6oUy9.o: In function `__tcf_0′:
hello.cpp:(.text+0×6c): undefined reference to`std::ios_base::Init::~Init()’
/tmp/cch6oUy9.o: In function `main’:
hello.cpp:(.text+0×8e): undefined reference to `std::cout’
hello.cpp:(.text+0×93): undefined reference to`std::basic_ostream<char,std::char_traits<char>>&std::operator<<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>>&, char const*)’
/tmp/cch6oUy9.o:(.eh_frame+0×11): undefined reference to`__gxx_personality_v0′
collect2: ld returned 1 exit status

出错了!!而且错误还很多,很难看懂,这可怎么办呢?在解释之前,我们先试试下面的命令:

$ gcc -Wall hello.cpp -o hello -lstdc++

噫,加上-lstdc++选项后,编译竟然通过了,而且没有任何警告。运行程序,结果如下:

$ ./hello
hello, world

通过上节,我们可以知道,-lstdc++ 选项用来通知链接器链接静态库libstdc++.a。而从字面上可以看出,libstdc++.a 是C++ 的标准库,这样一来,上面的问题我们就不难理解了──编译C++ 程序,需要链接 C++ 的函数库 libstdc++.a。

不过幸运的是,GCC 包含专门为 C++ 、Fortran等语言的编译器前端。于是,上面的例子,我们可以直接用如下命令编译:

$ g++ -Wall hello.cpp -o hello



<think>好的,用户想了解如何让GCC生成map文件以及如何解析其中的信息。首先,我需要回忆一下之前提供的步骤和相关引用,确保回答准确。 用户之前的问题是关于用grep查找map文件中的标准库引用,现在他转向如何生成和解析map文件。根据之前的引用,比如引用[3]和[5]提到使用-Wl,-Map参数来生成map文件。所以生成方法应该包括在编译命令中加入这个选项。 生成map文件的方法可能包括基本命令和进阶选项,比如添加详细符号信息或者交叉引用。需要分步骤说明,确保用户能跟着操作。 解析map文件的部分,用户需要知道如何查找关键信息,如内存分布、符号表、库依赖等。之前回答中用了grep命令来筛选内容,这里可以延续类似的方法,指导用户如何定位重要部分。 另外,用户可能关心map文件的结构,比如各个部分的含义,如内存段、符号地址、库引用等。需要结合引用[1]中的内容,解释map文件的结构,帮助用户理解各部分的作用。 可能的问题包括生成map文件的不同参数选项,或者解析时的常见问题。需要确保回答覆盖这些点,并提供相关的示例命令,如使用grep或结合readelf工具。 还要注意用户可能的应用场景,比如调试或优化程序内存使用,因此需要强调这些解析步骤的实际用途。例如,查看内存分布有助于优化内存分配,检查符号冲突可以解决链接错误。 最后,确保引用正确的来源,比如引用[3]和[5]关于生成map文件的方法,引用[1]关于map文件的结构,引用[4]的例子中的编译命令。保持回答结构清晰,分步骤说明,并附上相关问题,帮助用户深入理解。</think>根据GCC编译器的工作机制和.map文件的结构特性,我将分步骤说明生成和解析.map文件的具体方法: ### 一、生成.map文件 #### 1. 基础生成方法 ```bash gcc -o myprog source.c -Wl,-Map=output.map ``` 通过`-Wl`参数向链接器传递`-Map=文件名`指令,这是生成.map文件的核心参数[^3][^5] #### 2. 进阶生成方法 ```bash gcc -o myprog src/*.c -Wl,-Map=detail.map,-cref,-print-memory-usage ``` * `-cref`:生成交叉引用表 * `-print-memory-usage`:显示内存使用统计 * 添加`-ffunction-sections -fdata-sections`可获取更详细的段信息[^1] #### 3. 调试增强版 ```bash gcc -g -Wa,-adhln=asm.lst -Wl,-Map=debug.map,-cref source.c ``` 同时生成汇编列表文件(.lst)和带调试符号的.map文件[^2] ### 二、解析.map文件 .map文件通常包含以下核心结构: ``` Memory Configuration <-- 内存区域定义 Linker script and memory map <-- 关键内存分布 Allocating common symbols <-- 公共符号分配 Discarded input sections <-- 被丢弃的段 Cross Reference Table <-- 符号交叉引用[^1] ``` #### 关键解析步骤: 1. **查看内存分布** ```bash grep -A 20 "Memory Configuration" output.map ``` 显示代码/数据段的起始地址和大小,例如: ``` .text 0x0000000000401000 0x1500 .data 0x0000000000403000 0x400 ``` 2. **提取符号表** ```bash grep -E '^0x[0-9a-f]+\s+\S+' output.map | sort -k 1 ``` 按地址排序显示所有符号,输出示例: ``` 0x0000000000401120 main 0x0000000000401150 printf@plt ``` 3. **分析库依赖** ```bash grep 'LOAD.*/usr/lib' output.map | awk '{print $3}' ``` 显示链接的共享库路径,如: ``` /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 ``` 4. **检查符号冲突** ```bash grep 'multiple definition' output.map -C 3 ``` 检测多定义的全局符号,这类错误会导致链接失败 5. **计算段使用率** ```bash awk '/Memory region/ {flag=1} /=======/ {flag=0} flag' output.map ``` 显示各内存区域的使用统计: ``` region size used available FLASH: 256 KB 152 KB 104 KB RAM: 64 KB 58.2 KB 5.8 KB ``` ### 三、典型应用场景 1. **调试内存溢出**:通过`.bss`段大小判断静态变量占用 2. **优化程序体积**:识别占用大的目标文件(如`libm.a`中的数学函数) 3. **分析启动过程**:查找`_start`符号确定程序入口地址[^4] 4. **检查链接顺序**:查看库加载顺序对符号解析的影响
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值