nm和map文件

编程入门 行业动态 更新时间:2024-10-18 01:42:08

nm和map<a href=https://www.elefans.com/category/jswz/34/1771438.html style=文件"/>

nm和map文件

在Linux中,我们可以使用nm命令来查看程序的符号表,包括全局变量。这个命令可以帮助我们查看全局变量的地址。然而,全局变量的地址是否相邻取决于编译器的实现和优化。

下面是一个简单的例子:首先,我们创建一个C程序,定义两个全局变量:

int global_var1;
int global_var2;int main() {return 0;
}

然后,我们编译这个程序并生成map文件:

gcc -o test test.c -Wl,-Map,test.map

最后,我们使用nm命令查看全局变量的地址:

nm test | grep 'global_var'

这将显示全局变量的地址。你可以比较这两个地址来看它们是否相邻。但是请注意,即使这两个变量在源代码中是相邻的,它们在内存中的地址也可能不是相邻的,这取决于编译器如何分配内存。此外,全局变量的大小也会影响它们的地址。例如,如果一个变量是int类型,另一个变量是double类型,那么它们的地址就不可能是相邻的,因为double类型的变量需要更多的内存空间。所以,即使两个全局变量在源代码中是相邻的,它们在内存中的地址也可能不是相邻的。这就是为什么我们需要使用nm命令来查看实际的内存地址。


我定义了一个static的变量,如:static unsigned int global_var8;通过nm test | grep 'global_var'查找的时候能看到,但是在map文件里找不到,是什么问题呢?

在Linux中,static关键字会使变量的作用域限制在声明它的文件内。因此,static变量不会出现在链接器的符号表中,也就不会出现在map文件中。这是因为链接器只需要处理全局符号,即那些可能需要在一个文件中定义,在其他文件中引用的符号。

然而,你可以使用nm命令查看包含static变量的目标文件(.o文件),这样就可以看到static变量了。但是请注意,这些地址是在链接前分配的,所以它们在最终的可执行文件中可能会有所不同。

此外,如果你的static变量没有被使用,编译器可能会优化掉它,因此即使在目标文件中也看不到它¹。你可以尝试关闭优化选项,看看是否能在目标文件中看到你的static变量。


global_var10是一个在函数xiaomi_func内部定义的静态变量。这意味着这个变量只在这个函数内部可见,而在函数外部是看不到的。然而,由于它是静态的,所以它在程序的整个生命周期内都存在。

当你使用nm命令查看符号时,你会看到global_var10.0。这是因为编译器对局部静态变量进行了名字修饰(name mangling)。这是一种编译器用来确保每个符号名称在内部都是唯一的技术。编译器会在变量名后面添加一个点和一个序列号。这就是你看到的.0

所以,global_var10.0实际上就是你在xiaomi_func函数内部定义的静态变量global_var10


在嵌入式系统中,我们可以使用链接脚本来配置特定的段(section),并使用特定的属性来将变量设置为归属于特定的段。以下是一个简单的示例,展示了如何在GCC编译器中进行操作:

// 链接脚本
SECTIONS
{. = 0x20000000;.data : { *(.data) }.my_section : { *(.my_section) }.bss : { *(.bss) }
}// C代码
int var1 __attribute__((section(".data"))) = 0;        // 将var1放在.data段
int var2 __attribute__((section(".my_section"))) = 0;  // 将var2放在.my_section段

在这个例子中,我们首先定义了一个链接脚本,它指定了内存的起始地址(0x20000000),然后定义了三个段:.data.my_section.bss。然后,在C代码中,我们使用__attribute__((section(".section_name")))来指定变量应该放在哪个段中。

请注意,这只是一个基本的示例,实际的链接脚本可能会更复杂,并且可能需要包含更多的信息,例如段的大小,对齐要求等。此外,不同的编译器可能会有不同的语法,所以请确保查阅您所使用的编译器的文档。


在Keil中配置段,通常需要通过链接脚本(Linker Script)来完成。链接脚本可以定义内存区域的布局,包括代码段(.text)、数据段(.data)、未初始化数据段(.bss)等。以下是一个简单的示例:

LR_IROM1 0x08000000 0x00040000  {    ; load region size_regionER_IROM1 0x08000000 0x00040000  {  ; load address = execution address*.o (RESET, +First)*(InRoot$$Sections).ANY (+RO)}RW_IRAM1 0x20000000 0x00010000  {  ; RW data.ANY (+RW +ZI)}
}

在这个例子中,我们定义了两个内存区域:一个是Flash(从0x08000000开始,大小为0x00040000),另一个是RAM(从0x20000000开始,大小为0x00010000)。在Flash区域中,我们存储了代码和只读数据,在RAM区域中,我们存储了读写数据和未初始化数据。

然后,你可以使用__attribute__((section(".section_name")))来将特定的变量或函数放入特定的段中。例如:

int var __attribute__((section("ER_IROM1"))) = 0;

这将会把变量var放入ER_IROM1段中。

请注意,这只是一个基本的示例,实际的链接脚本可能会更复杂,并且可能需要包含更多的信息,例如段的大小,对齐要求等。此外,不同的编译器可能会有不同的语法,所以请确保查阅您所使用的编译器的文档。


在嵌入式系统中,可以将data段和bss段配置到SRAM或PSRAM中。这通常涉及到链接脚本的修改,以便在链接过程中将特定的段定位到特定的内存区域。

以下是一个简单的示例,展示了如何在链接脚本中配置段的位置。这个示例假设你正在使用GNU链接器,并且你的链接脚本可能看起来像这样:

MEMORY
{sram (rwx) : ORIGIN = 0x20000000, LENGTH = 64Kpsram (rwx) : ORIGIN = 0x60000000, LENGTH = 4M
}SECTIONS
{.data : {*(.data)} >sram.bss : {*(.bss)} >psram
}

在这个示例中,我们首先定义了两个内存区域,一个是SRAM,起始地址为0x20000000,长度为64KB;另一个是PSRAM,起始地址为0x60000000,长度为4MB。

然后,在SECTIONS部分,我们指定.data段应该链接到SRAM中,.bss段应该链接到PSRAM中。*(.data)*(.bss)是通配符,匹配所有的.data.bss输入段。

这只是一个基本的示例,实际的链接脚本可能会更复杂,包括处理初始化数据、复制到SRAM的数据等。

请注意,这需要对链接脚本有深入的理解,并且可能需要根据你的具体硬件和编译器进行调整。如果你不熟悉这个过程,可能需要寻求专业的嵌入式系统开发人员的帮助。在进行这些更改时,请务必谨慎,因为错误的配置可能会导致程序无法正确运行。

更多推荐

nm和map文件

本文发布于:2023-11-15 23:01:55,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1608488.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:文件   nm   map

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!