map 文件
内容
显示全局变量、函数位于哪个地址和section
链接了哪些 .o 文件
生成
通过gcc参数-Wl,-Map,:
gcc -o helloworld helloworld.c -Wl,-Map,file_name.map
或者
gcc -o helloworld helloworld.c -Wl,-Map=file_name.map
通过ld参数-Map:
ld -Map file_name.map helloworld.o -o helloworld
例子
#include <stdio.h> #include <unistd.h> #include <pthread.h> int g_var1; char *g_var2 = "hello world !"; int test_func(int arg) { static char *s_var1 = NULL; static int s_var2 = 255; int var = arg * 10; return var; } static void *pthread_proc(void *arg) { /* 线程pthread开始运行 */ printf("pthread start!\n"); /* 令主线程继续执行 */ sleep(2); return NULL; } int main(int argc, char **argv) { pthread_t tidp; g_var1 = 100; printf("%s\n", g_var2); printf("main=%016llx, func=%016llx, var=%016llx\n", (long long)main, (long long)test_func, (long long)g_var2); test_func(g_var1); pthread_create(&tidp, NULL, pthread_proc, NULL); pthread_join(tidp, NULL); printf("exit !\n"); return 0; }
程序基本包含代码的所有关键点:全局变量、静态变量、局部变量、函数、链接库。执行编译命令生成map文件和可执行文件。
gcc -o helloworld helloworld.c -Wl,-Map,helloworld.map -lpthread
程序执行结果:
$ ./helloworld hello world ! main=000055c70b2dd86e, func=000055c70b2dd82a, var=000055c70b2dd9c8 pthread start! exit !
map文件片段1:
按需库被包含以满足文件 (符号) 引用 libpthread.so.0 /tmp/ccnK3bV5.o (pthread_create@@GLIBC_2.2.5) libc.so.6 /tmp/ccnK3bV5.o (puts@@GLIBC_2.2.5) 分配公共符号 公共符号 大小 文件 g_var1 0x4 /tmp/ccnK3bV5.o
可以看到链接库(libpthread)的引用符号(pthread_create函数)、全局变量(g_var1)。
注意:静态变量和静态函数不会出现在map文件中!
map文件片段2:
.text 0x0000000000000700 0x2b /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o 0x0000000000000700 _start .text 0x000000000000072b 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o *fill* 0x000000000000072b 0x5 .text 0x0000000000000730 0xda /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o .text 0x000000000000080a 0xfc /tmp/ccnK3bV5.o 0x000000000000080a test_func 0x000000000000084e main
可以看到函数test_func和main的信息,其地址与程序运行时打印出的地址有必然联系(最后一个字节相同)。理论上打印的地址和map中的地址(物理地址)应该是一样的,但由于Linux系统的虚拟地址机制,打印出来的是虚拟地址,但是地址排列是一致的,所以最后一个字节相同。
map文件片段3:
.bss 0x0000000000201028 0x18 *(.dynbss) .dynbss 0x0000000000201028 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o *(.bss .bss.* .gnu.linkonce.b.*) .bss 0x0000000000201028 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o .bss 0x0000000000201028 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o .bss 0x0000000000201028 0x1 /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o *fill* 0x0000000000201029 0x7 .bss 0x0000000000201030 0x8 /tmp/ccnK3bV5.o .bss 0x0000000000201038 0x0 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS) .bss 0x0000000000201038 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o .bss 0x0000000000201038 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o *(COMMON) COMMON 0x0000000000201038 0x4 /tmp/ccnK3bV5.o 0x0000000000201038 g_var1
由于g_var1是未初始化的全局变量,应该被分配在bss段,从map文件也可以验证这一点。
map文件片段4:
.data 0x0000000000201010 0x14 /tmp/ccnK3bV5.o 0x0000000000201010 g_var2 .rodata 0x00000000000009c8 0x50 /tmp/ccPjpRD1.o
同理,g_var2是初始化的全局变量,分配在数据段(.data)。g_var2的初始化数据“hello world !”放在只读数据段(.rodata)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)