1.ld是源码什么意思
2.Linuxçlinuxçmemory
3.在debian里装了gcc4.4 现在想安装gcc3.4.6,因为要利用低级gcc的源码特性。 现在怎么装老板本的源码gcc而不导致冲
4.Cè¯è¨å·¥ä½åç
5.充分理解Linux GCC 链接生成的Map文件
ld是什么意思
ld的意思主要是“链接器(Linker)”或“动态链接库(Dynamic Link Library)”。
首先,源码ld在计算机科学中常被用作“链接器”的源码缩写。在软件开发过程中,源码eslipse app源码链接器是源码一个至关重要的工具,它负责将编译器生成的源码多个目标文件(object files)合并成一个可执行文件或库文件。这个过程中,源码链接器会处理目标文件之间的源码符号引用,确保程序在运行时能够正确找到并调用各个部分。源码例如,源码在C或C++项目开发中,源码编译器会将源代码编译成目标文件,源码然后由链接器将这些目标文件链接成最终的源码可执行程序。
其次,ld也被用来指代“动态链接库”,尤其是在Unix和类Unix系统中。动态链接库是一种包含可执行代码和数据的文件,它可以在多个程序之间共享,从而节省内存空间并提高代码的可重用性。与静态链接库不同,动态链接库在程序运行时被加载到内存中,而不是在编译时。这意味着多个程序可以同时使用同一个动态链接库的副本,实现资源的ddis源码论坛高效利用。在Linux系统中,动态链接库通常具有.so(Shared Object)的扩展名,并由ld动态链接器在程序运行时进行加载和管理。
总的来说,ld这个缩写可以根据上下文的不同而具有不同的含义。在软件开发领域,它通常指的是链接器或动态链接库,这两个概念都是构建和运行复杂软件系统所不可或缺的组成部分。链接器确保程序的各个部分能够正确组装在一起,而动态链接库则提供了在多个程序之间共享代码和数据的机制。
无论是作为链接器还是动态链接库的简称,ld都体现了计算机科学中对于资源整合和高效利用的追求。通过理解和应用这些概念,开发者能够创建出更加健壮、灵活且高效的软件解决方案。例如,在开发一个大型项目时,合理利用链接器可以确保项目各个模块之间的紧密集成;而通过使用动态链接库,则可以实现代码的重用和更新,从而降低维护成本并提高软件质量。
Linuxçlinuxçmemory
linuxdmaåçï¼è®¡ç®æºç»æåçä¸çDMA
以å¾çI/O设å¤å主å交æ¢ä¿¡æ¯é½è¦ç»è¿CPUçæä½ãä¸è®ºæ¯ææ©ç轮询æ¹å¼ï¼è¿æ¯æ们å¦è¿çä¸ææ¹å¼ãè½ç¶ä¸ææ¹å¼ç¸æ¯è½®è¯¢æ¹å¼å·²ç»èçäºå¤§éçCPUèµæºãä½æ¯å¨å¤ç大éçæ°æ®æ¶ï¼DMAç¸æ¯ä¸ææ¹å¼è¿ä¸æ¥è§£æ¾äºCPUã
DMAå°±æ¯DirectMemoryAccessï¼æææ¯I/O设å¤ç´æ¥åå¨å¨è®¿é®ï¼å ä¹ä¸æ¶èCPUçèµæºãå¨I/O设å¤å主åä¼ éæ°æ®çæ¶åï¼CPUå¯ä»¥å¤çå ¶ä»äºã
linuxå æ ¸æ åæ件ä¸æ®éçELFæ件æä»ä¹åºå«ï¼
å ¶å®å æ¬shell以åmakeåºçä¸ç³»åæ件*.o*.soçä½æ¯*.aä¸æ¯
Linuxå æ ¸æå¤ç§æ ¼å¼çéåï¼å æ¬vmlinuxãImageãzImageãbzImageãuImageãxipImageãbootpImageç.
vmlinuzæ¯å¯å¼å¯¼çãå¯å缩çå æ ¸éåï¼vm代表VirtualMemory.Linuxæ¯æèæå åï¼å æ¤å¾åvm.å®æ¯ç±ç¨æ·å¯¹å æ ¸æºç ç¼è¯å¾å°ï¼å®è´¨æ¯elfæ ¼å¼çæ件.ä¹å°±æ¯è¯´ï¼vmlinuxæ¯ç¼è¯åºæ¥çæåå§çå æ ¸æ件ï¼æªå缩.è¿ç§æ ¼å¼çéåæ件å¤åæ¾å¨PCæºä¸.
èImageæ¯ç»è¿objcopyå¤ççåªå å«äºè¿å¶æ°æ®çå æ ¸ä»£ç ï¼å®å·²ç»ä¸æ¯elfæ ¼å¼äºï¼ä½è¿ç§æ ¼å¼çå æ ¸éåè¿æ²¡æç»è¿å缩.
å ¶ä»ç±»åçæ件就æ´ä¸æ¯äº
åªè½è¯´Linuxå æ ¸éåæä¸ç§æ¯elfæ ¼å¼çï¼å 为elfé常é½æ¯è¢«ç¼è¯çæçï¼æ以linuxå æ ¸æ åæ件ä¸æ®éçELFæ件å®ç°çåè½ä¸åé¿
Linuxç³»ç»ä¸çå åæ¸ çåéæ¾å½ä»¤å½çº³ï¼
#æ¸ çæ¥éª¤
#æ¸ çåå å使ç¨æ åµ
代ç å¦ä¸:
free-m
#å¼å§æ¸ ç
代ç å¦ä¸:
echo1/proc/sys/vm/drop_caches
#æ¸ çåå å使ç¨æ åµ
代ç å¦ä¸:
free-m
å®æ!
å¤å¶ä»£ç
代ç å¦ä¸:
dmidecode|grep-AMemoryDevice$
Tofreepagecache:
echo1/proc/sys/vm/drop_caches
Tofreedentriesandinodes:
echo2/proc/sys/vm/drop_caches
Tofreepagecache,dentriesandinodes:
echo3/proc/sys/vm/drop_caches
sync
#éæ¾åæ好syncä¸ä¸ï¼é²æ¢ä¸¢æ°æ®ãå 为LINUXçå æ ¸æºå¶ï¼ä¸è¬æ åµä¸ä¸éè¦ç¹æå»éæ¾å·²ç»ä½¿ç¨çcacheãè¿äºcacheèµ·æ¥çå 容å¯ä»¥å¢å æ件以åç读åé度ã
linuxcached为ä»ä¹ä¸ç´ä¸éæ¾ï¼
å½è¯»åæ件çæ¶åï¼Linuxå æ ¸ä¸ºäºæé«è¯»åæçä¸é度ï¼ä¼å°æ件å¨å åä¸è¿è¡ç¼åï¼è¿é¨åå åå°±æ¯CacheMemory(ç¼åå å)ãå³ä½¿ä½ çç¨åºè¿è¡ç»æåï¼CacheMemoryä¹ä¸ä¼èªå¨éæ¾ãç¼åå å(CacheMemory)å¨ä½ éè¦ä½¿ç¨å åçæ¶åä¼èªå¨éæ¾ï¼æ以ä¸å¿ æ å¿æ²¡æå åå¯ç¨ãå½ç¶ä¹å¯ä»¥æå¨éæ¾ï¼
echo1>/proc/sys/vm/drop_caches
echo2>/proc/sys/vm/drop_caches
echo3>/proc/sys/vm/drop_caches
注æï¼ç产ç¯å¢è¯·è°¨æ æä½ã
linuxæ±ç¼ï¼ldtoupper.o-lc-dynamic-linker/lib/ld-linux.so.2æ§è¡a.outåºç°memoryfaultæ±æ大ç¥ï¼
ä½ æºå¨æ¯ä½cpuå§ï¼ä½ æä½æ±ç¼ææä¸çä¾åï¼ä½æºå¨ä¸ç´æ¥è·ä¸æ¦æ¶åå°å åå°åå¿ ç¶ä¼æ¥æ®µé误çãä½æºå¨ä¸å½æ°è°ç¨æ¹æ³ä¹åä½ä¸åäºï¼å³ä½¿ä¸æ¯å°å åå°åï¼ä½ çç¨åºä¹æ²¡æ³è¾¾å°ç®ççã
在debian里装了gcc4.4 现在想安装gcc3.4.6,因为要利用低级gcc的特性。 现在怎么装老板本的gcc而不导致冲
一、先安装gcc3.4.6,为了避免麻烦,map源码阅读或者和原来的gcc4.4造成冲突,请用源代码安装方式安装gcc3.4.6,就是 make make install的方式,而不要用deb包的方式安装。
二、一种方法是手动用ln -s创建符号链接来管理,但这样费时费力,而且容易导致toolchain混乱。
幸好有update-alternatives实用软件!它可以方便管理好同一软件的各个不同版本。
1.一般情况下,编译程序路径都是使用
/usr/bin/gcc
其实这个/usr/bin/gcc只是个符号链接,它指向了/etc /alternatives/gcc,而/etc/alternatives/gcc是指向了/usr/bin/gcc-4.3,可以用ls命令查看
z@GODSON:~$ ls -l /usr/bin/gcc
lrwxrwxrwx 1 root root -- : /usr/bin/gcc -> /etc/alternatives/gcc
z@GODSON:~$ ls -l /etc/alternatives/gcc
lrwxrwxrwx 1 root root -- : /etc/alternatives/gcc -> /usr/bin/gcc-4.3
2.现在我们使用 update-alternatives管理我们的GCC版本:
z@GODSON:~$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/gcc-4.4.0/bin/gcc
z@GODSON:~$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.3
z@GODSON:~$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.1
这样,我们就已经把我们安装的三个GCC版本向update-alternatives注册了,接下来我们便可以方便地管理各版本切换。
3. 切换版本
切换版本到gcc-4.4.0:
z@GODSON:~$ sudo update-alternatives --config gcc
[sudo] password for z:
现有 3 个可选项,它们都提供了“gcc”<
选择 可选项
-----------------------------------------------
*+ 1 /usr/gcc-4.4.0/bin/gcc
2 /usr/bin/gcc-4.3
3 /usr/bin/gcc-4.1
要维持缺省值[*],按回车键,或者键入选择的编号:
输入想要切换的版本,回车之后就OK了,然后你可以用gcc --version查看版本。
Cè¯è¨å·¥ä½åç
ããä½ä¸ºä¸ç§ç¼ç¨è¯è¨ï¼æ¬èº«æ¯è°ä¸ä¸å·¥ä½åççï¼å®é ä¸Cè¯è¨ææçè¯æ³ï¼æ£æ¯Cè¯è¨ç¼è¯å¨çå·¥ä½åçæè å·¥ä½æºå¶çå ·ä½å®ç°ãè¦ç»è´ç讨论起æ¥æ¯ä¸å¯è½ï¼ä½æ¯ä½ä¸ºCè¯è¨ç¨åºåï¼å¿ é¡»äºè§£è¿ä¸ªå¤§è´çæµç¨ãä¸ä¸ªç¨åºï¼ä»Cè¯è¨æºç ï¼å°ç³»ç»å¯æ§è¡çæ件ï¼ä¸è¬ç»åå个è¿ç¨ã
ãã1ãé¢å¤çé¶æï¼è¿ä¸ªé¶ææ¯ææ¬å¤çé¶æï¼æé¢å¤çå¨æ¥å®æï¼ä¼å°æºç ä¸ç带"#"å¼å¤´çé¢å¤çå½ä»¤è¿è¡ç¸åºçå¤çï¼å¨Linuxä¸Cè¯è¨çé¢å¤çå¨ç¨åºæ¯cpå½ä»¤ã
ãã2ãç¼è¯é¶æï¼è¿ä¸ªé¶ææ¯æCè¯è¨ç¼è¯é¶æï¼å¨Linuxä¸Cè¯è¨çç¼è¯å¨æ¯ccå½ä»¤ï¼å®å°Cè¯è¨æºç 转æ¢ææ±ç¼æ令ã
ãã3ãæ±ç¼é¶æï¼è¿ä¸ªé¶ææ¯æ±ç¼ç¼è¯é¶æï¼å¨Linuxä¸Cè¯è¨çæ±ç¼å¨æ¯aså½ä»¤ï¼è¿ä¸ªé¶æä¼å°æ±ç¼æ令ç¼è¯æäºè¿å¶æºå¨ç ã
ãã4ãé¾æ¥é¶æï¼è¿ä¸ªé¶ææ¯ä¼å°æ±ç¼é¶æçæçæºå¨ç ç®æ æ件ï¼è£ è½½æä¸ä¸ªç³»ç»å¯æ§è¡çæ件ï¼å¨Linuxå¹³å°ä»¥ELFæ ¼å¼è¿è¡ç»è£ ï¼å¨Windowså¹³å°ä¸ä»¥PEæ ¼å¼è¿è¡ç»è£ ãå¨Linuxå¹³å°ä¸çé¾æ¥å¨å½ä»¤ä¸ºldï¼å¨windowså¹³å°ä¸çé¾æ¥å¨å½ä»¤ä¸ºlinkerã
充分理解Linux GCC 链接生成的Map文件
简单来说,map文件就是linxs备份源码通过编译器编译之后,生成的程序、数据及IO空间信息的一种映射文件,里面包含函数大小,入口地址等一些重要信息。从map文件我们可以了解到:
生成map文件是链接器ld的功能,有两种方式可以生成map文件:
使用GNU binutils,必须通过设置正确的标志来显式地请求生成映Map文件。使用LD将Map打印到输出到output.map:
作为一个简单程序的例子,你可以使用以下命令链接编译单元:
为什么要了解Map文件:
在本文中,我想突出说明链接器Map文件是多么简单,以及它可以教给我们关于正在处理的程序的一些知识。
固件工程师很少在调试时使用构建过程生成的Map文件。然而,答案有时就在这个Map文件中。
Map文件提供了有价值的信息,可以帮助您理解和优化内存。我强烈建议为在生产环境中运行的任何固件保存该文件。
Map文件是整个程序的符号表。让我们深入研究它,看看它有多简单,以及如何有效地使用它。我将尝试用一些例子来说明,这些例子都是用GNU binutils来描述的。
LED闪烁程序:
还有什么比我们的老朋友LED闪烁程序示例解释一下Map文件的基础知识更好的呢?
为了了解Map文件,我们使用Nordic SDK中的vix指标源码LED闪烁程序来编译,并修改它以添加对atoi的调用。然后,我们将使用Map文件来分析这两个程序之间的差异。
下面就是示例的main.c文件:
编译:
生成的Map文件有多行 ,尽管它只是在闪烁发光二极管。这么多行不可能看不见,里面一定有一些重要的信息……
现在让我们修改程序,添加对atoi的调用,我们不直接使用整数作为延迟函数的参数,而是将其编码为字符串并使用atoi解码,然后作为参数传给延时函数。
经过编译,整个程序从字节变成了字节。
我们能够想到调用atoi会带来更多的代码,但是%程序大小的增加是巨大的!
深入研究Map文件:
在下面的部分中,我将使用代码片段来解释Map文件的不同部分。
Archives linked:
下面是Map文件的第一行内容:
上述信息的格式如下:
上面内容的意思是crt0这个文件中会调用exit函数,exit函数在exit.o这个目标文件中,exit.o目标文件是被链接在libc_nano.a这个库文件里的。
为什么是这样,不在本文的讨论范围内,但是你的工具链(这里是GNU工具链)确实提供了一些标准库。它们可用于提供atoi等标准功能,在这个例子中,我指定链接器使用nano.spec文件,这就是为什么标准函数都来自libc_nano.a。
现在,比较两个生成的map文件,发现的第一个区别是程序中包含了一些其他的存档成员:atoi,它本身需要_strtol_r,_strtol_r本身又需要_ctype_:
现在,我们对实际包含在程序中的文件以及它们存在的原因有了更好的理解。让我们来看看这个文件里面还有什么!
Memory configuration:
Map文件中最直接的信息是实际的内存区域,这些区域具有位置、大小和访问权限:
Linker script and memory map:
内存配置之后是Linker script and memory map,这个很有趣,因为它给出了程序中符号的详细信息。在我们的例子中,它首先指示text区域的大小及其内容(text是我们编译的代码,而data是程序数据)。
在这里,中断向量(在.isr_vector下)出现在可执行文件的开头,定义在gcc_startup_nrf.S中:
这些行给出了每个函数的地址和大小。在上面,你可以读取bsp_board_led_invert的地址,它来自boards.c.o(如你所猜测的,board.c的编译单元),在text区域中它的大小为0x字节。这样,我们就可以定位程序中使用的每个函数。
我的常量字符串_delay_ms_str在程序初始化时显然包含在程序中,只读数据作为rodata保存在链接器脚本中指定的FLASH区域中(存储在Flash中,而不是复制在RAM中,因为它是常量)。我可以在这行下面找到:
我还注意到_ctype_的包含在text区域中增加了0x字节的只读数据
标准库是开源的( 链接),我们很容易就能找出它占用那么多空间的原因。我深入到atoi的内部(可重入版本的atoi_r,见下文),它是直接调用的strtol_r:
对于strtol_r,它实际上比仅仅将字符转换为整数更复杂,因为还使用ctype来执行类型检查。ctype的工作方式是使用一个表,其中ASCII符号类型存储在一个数组中。下面是ctype的主要部分,并附上我的注释:
有趣的是,atoi的添加不仅增加了代码的大小(text区域),还增加了数据的大小(data区域)。分析两个Map文件,我可以很容易地发现之前被链接器丢弃的数据:
现在你可能已经注意到函数名以_r结尾,例如在调用strtol_r时,该后缀表示可重入性。有关可重入性的文档可以在 newlib源代码中找到。总而言之,即使同一函数已经在另一个进程中执行,也可以调用可重入函数,而不会干涉执行。从文档中可以看到如下描述:
Each function which uses the global reentrancy structure uses the global variable _impure_ptr, which points to a reentrancy structure.
在我们的例子中,我们需要新的全局变量来调用可重入函数:atoi_r。
最后要记住的一点信息是:初始化变量必须保存在Flash中,但它们在Map文件中会出现在RAM中,因为它们在进入主函数之前被复制到RAM中。在这里,符号__data_start__和__data_end__跟踪RAM中用于保存初始化变量的区域,这些值存储在Flash中,起始位置为0xd0:
Discarded sections:
如果链接器没有找到对函数和变量的任何引用,编译后包含在程序中的函数和变量并不总是最终二进制文件的一部分,它们将会被删除但是仍然会出现在Map文件的Discarded input sections 部分。例如,下面是一些定义在boards.c中的函数,它们永远不会被调用并因此被丢弃:
Common symbols:
这个部分没有出现在我们的Map文件中,但它值得一提。
Common symbols(通用符号)是可以在代码中的任何地方使用的非常量全局变量(non-constant global variables)。您可能知道,使用全局变量通常不是一个好的实践,因为它们使代码更难维护。确实如此,作用域是全局的,每个外部模块可以修改任何全局变量的值,访问时必须考虑到这一点。将变量隔离到一个模块中,使用static关键字,通常更好地确保创建变量的模块完全负责其状态。
现在,如果您希望使程序更安全并防止访问某些全局变量,请查看Map文件部分。如果某些变量不需要声明为全局变量,您可能希望将它们转换为静态变量。
Map文件有几种可能的用法:大多数时候,一个地址后面对应着一个函数,我们希望通过这个地址去了解一些问题。例如,它可以是硬故障处理程序(Hard Fault handler)中的程序计数器(Program Counter)。其他时候,你也会遇到调试一些不明确的行为,最终发现你的程序意外地写入了一个出界数组(数组越界)。当有了ELF文件时,arm-none-eabi-nm对于这些事情也非常有用,它提供了按大小排序符号的选项。
但有些时候,它甚至在你有可执行文件之前就很有用了……
Debugging a linking error:
Map文件是在构建代码(.o文件)链接在一起的时候生成的,这意味着它可以有助于解决链接过程中出现的错误。我记得在几个Flash页面中包含一个引导加载程序,在某些情况下,我想使用atoi,但引导加载程序不再编译,因为没有更多的可用空间。
使用前面的示例,假设我现在只有0x字节的Flash。编译第一个示例时,如果没有atoi,就不会出现问题,但是第二个例子会溢出我们的Flash:
是不是很讨厌?atoi只是一个很简单的函数而已,居然就出现这种问题。但正如我们前面所提到的,使用libc_nano.a需要比预期更多的Flash空间。
让我们来实现自己版本的atoi,其实也没那么难。以下是编译后的结果(config CUSTOM_ATOI):
这个方法是不是很好?现在可以将代码塞进0x字节的Flash,以满足我们的(假)需求。
分析Map文件可以让我们了解很多正在编写的代码,这是改进固件的第一步。
可以使用一些工具来解析Map文件并获得程序的汇总视图,后面有时间和大家好好聊聊。