gcc编译链接之Map文件分析

最近在研究MiCO OS项目的时候,发现编译目录build下有一个xxxx.map文件,打开一看,感觉都是一些内存段和符号信息,由此想到应该是编译链接过程中输出的一些信息。之前没有接触过,今天就来学习一下map文件是个什么东西、有什么作用。

map文件片段:

Allocating common symbols
Common symbol       size              file

errno               0x4               d:/programs/micoder/compiler/arm-none-eabi-5_4-2016q2-20160622/win32/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_nano.a(lib_a-reent.o)

Discarded input sections

 .text          0x00000000        0x0 ./build/mico-iot-module@mx1290@moc/libraries/App_IoT_Module.a(app_main.o)
 .data          0x00000000        0x0 ./build/mico-iot-module@mx1290@moc/libraries/App_IoT_Module.a(app_main.o)
 .bss           0x00000000        0x0 ./build/mico-iot-module@mx1290@moc/libraries/App_IoT_Module.a(app_main.o)
 .comment       0x00000000       0x6f ./build/mico-iot-module@mx1290@moc/libraries/App_IoT_Module.a(app_main.o)
 .ARM.attributes
                0x00000000       0x39 ./build/mico-iot-module@mx1290@moc/libraries/App_IoT_Module.a(app_main.o)
 .text          0x00000000        0x0 ./build/mico-iot-module@mx1290@moc/libraries/App_IoT_Module.a(mqtt_interface.o)
 .data          0x00000000        0x0 ./build/mico-iot-module@mx1290@moc/libraries/App_IoT_Module.a(mqtt_interface.o)
 .bss           0x00000000        0x0 ./build/mico-iot-module@mx1290@moc/libraries/App_IoT_Module.a(mqtt_interface.o)
 .comment       0x00000000       0x6f ./build/mico-iot-module@mx1290@moc/libraries/App_IoT_Module.a(mqtt_interface.o)
 .ARM.attributes
1 什么是Map文件?

简单来说,map文件就是通过编译器编译之后,生成的程序、数据及IO空间信息的一种映射文件,里面包含函数大小,入口地址等一些重要信息。从map文件我们可以了解到:

  • 程序各区段的寻址是否正确
  • 程序各区段的size,即目前存储器的使用量
  • 程序中各个symbol的地址
  • 各个symbol在存储器中的顺序关系(这在调试时很有用)
  • 各个程序文件的存储用量
2 如何生成?

生成map文件是链接器ld的功能,有两种方式可以生成map文件:

  • 通过gcc参数-Wl,-Map,:
    gcc -o helloworld helloworld.c -Wl,-Map,file_name.map

  • 通过ld参数-Map:
    ld -Map file_name.map helloworld.o -o helloworld

3 有啥用?

做出可执行文件下载到机器上,你如何知道程序段或数据段会不会太大,会不会超过ROM或RAM的size?你如何知道Link脚本有没有写错,每个程序区段都确实寻址到符合机器的存储器设定?当然你可以下载进机器运行就知道了吗?但是认为负责整合的工程师一定要检查下map文件,有些问题只会造成系统的不稳定,而不会马上死机,这种问题最麻烦。

4 例子

写了一段简单的代码,测试一下map文件:

#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;
}

程序基本包含代码的所有关键点:全局变量、静态变量、局部变量、函数、链接库。执行编译命令gcc -o helloworld helloworld.c -Wl,-Map,helloworld.map -lpthread,生成map文件和可执行文件。
程序执行结果:

$  ./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)。

以上~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,780评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,424评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,397评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,576评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,997评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,945评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,107评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,850评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,625评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,804评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,285评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,613评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,291评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,164评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,963评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,096评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,886评论 2 278

推荐阅读更多精彩内容

  • 动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载库。大多数操作系统将解析外部引用(比如库)作为加载过...
    小5筒阅读 5,372评论 0 3
  • 在链接阶段中,所有对应于源文件的.o文件、"-l"选项指定的库文件、无法识别的文件名(包括指定的.o目标文件和.a...
    Mr_Bluyee阅读 18,419评论 2 5
  • 所有知识点已整理成app app下载地址 J2EE 部分: 1.Switch能否用string做参数? 在 Jav...
    侯蛋蛋_阅读 2,358评论 1 4
  • layout: posttitle: OllyDbg插件深入分析categories: Reverse_Engin...
    超哥__阅读 4,254评论 1 0
  • 十月三十日 我十分感激我生命中拥有的一切,谢谢、谢谢、谢谢! 感恩健康的稿赏让我存活于世,谢谢、谢谢、谢谢! 我十...
    婕茗羽阅读 303评论 14 1