Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
原创征文
编译链接
【GCC编译优化系列】前后编译的两个版本固件bin大小不一样,怎么办
发布于 2022-09-08 19:19:22 浏览:1658
订阅该版
**本文目录** [TOC] --- # 1、问题描述 这两天在论坛收到一个朋友的问题回答邀请,我仔细读了下该问题,跟我之前在论坛上发布的好几个问题关联还挺大的,所以抽空带着这个问题,重新梳理下思路,也希望这些思路能帮到这位朋友尽快解决问题。 它的问题描述如下,感兴趣的可以参考原文链接:[RT-Thread4.1.0工程用scons连续编译生成的map文件差异很大](https://club.rt-thread.org/ask/question/d457e7c1e0aa43cd.html) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220908/20f17bd4b8e341c451b825a4d2982048.png.webp) # 2、排查思路 我之前也遇到类似的工程编译出来的bin文件变大的一个问题:[【GCC编译优化系列】从KEIL转战GCC,一个C库函数bin文件增大了十几KB](https://club.rt-thread.org/ask/article/866813c0a2efd608.html) 不过稍微不同的是,我之前的那个问题是编译器与自带的系统库(C库)的差异引入的,但这其中的排查思路倒是可以参考借鉴。 我先总结一下我的思路,参考如下: 1)既然是编译出来的bin固件大小不一,那我们需要抓一下生成固件bin的流程中,究竟是哪一个环节引入的变化? 2)笼统地说【编译】,其实有4个子环节:我在 [【GCC编译优化系列】一文带你了解C代码到底是如何被编译的?](https://club.rt-thread.org/ask/article/c471242bee28d268.html) 这篇文章中有介绍,主要分为 **预编译、编译、汇编、链接** ; 3)我们说两份一模一样的代码,理论上应该对比 **预编译处理之后的代码**,因为这个环节之后的代码,是没得变了,那些什么 `__FILE__ __DATE__ __TIME__` 等等各种宏定义已经完全被展开了,下一步就直接送到 **编译器** 去执行编译,得到 **汇编代码**; 4)上边对比预编译之后的代码,大概就能看出两次编译的代码,有哪些不同了;下一步,如果感兴趣,可以同样去对比下两份代码 **生成的汇编代码**,但是我不建议直接走这一步,因为难度会比较大,建议先往下走,到最后真的无路可走了,再回来这一步对比; 5)跳过对比 汇编代码,我们直接对比汇编代码之后的生成文件,叫 **object文件** ,这类文件基本就已经把各个C文件的函数给捆起来了,我们是可以通过 linux 下的命令行工具 **size** 来查看的,类似会有这样的输出: ```shell size build/kernel/src/memheap.o text data bss dec hex filename 6730 0 0 6730 1a4a build/kernel/src/memheap.o ``` 我们需要对比每一个object文件的size,找出有差异的那些object文件。 6)最后一步,把所有的object文件执行链接(**注意:obj的链接顺序也有可能会引起elf文件的变化,后面细讲**),才是得到编译输出的固件文件,其实这里说的固件文件常见的分为3种:**elf文件、hex文件、bin文件**,其中elf文件是最原始的输出文件,而后面的hex文件、bin文件都可以由elf文件导出生成。这里顺便提一句,单单对比bin文件的大小,意义不是很大,如果仅仅是相差几个字节或者十几字节,我觉得是正常;真正我们需要比较的是 elf文件的 **大小**,这个大小不是说它占磁盘的大小,而是使用 size 命令查出来的大小,类似这样: ```shell size rtthread.elf text data bss dec hex filename 557886 2100 87160 647146 9dfea rtthread.elf ``` 这里还有说明一下,如果前后的elf文件差异几个字节这种,很有可能是某些内存地址对齐导致的,4个字节或8个字节这样的差异。 7)总结一下,排查顺序:预编译后的代码文件 -》汇编代码文件(**可暂时跳过**)-》object文件 -> elf 文件 -> bin文件。主要采用的是对比法,至于如何对比这些文件,见下文分解。 --- # 3、如何获取预编译文件、汇编文件等中间文件? 以 **env** 开发环境为例(如果是以 **RT-Thread Studio** 为开发环境的,自行查找相关方法),bsp选用 **qemu-vexpress-a9** 作为参考: 在 **rtthread.py** 中的 **CFLAGS 和 AFLAGS** 添加 **-save-temps=obj** 如下所示: ```shell CFLAGS = DEVICE + ' -Wall -Werror -save-temps=obj' AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -D__ASSEMBLY__ -I. -save-temps=obj' ``` 重新clean,再编译,就可以看到build目录下,有 **.i文件(预编译后的文件)和.s文件(汇编文件)** 生成了。 前后编译的两个版本,把这些.i文件文件拎出来对比,即可。 --- # 4、object文件如何对比? # 考虑在env开发环境下使用 **find** 命令并不好使,我特意写了一个python脚本,用于批量查询object文件的size: 只需要在rtthread.py的最后加上这个python脚本的调用: ```shell POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' +\ SIZE + ' $TARGET \n ' + \ 'python size.py build ' + SIZE + '\n' ``` **size.py** 脚本的内容如下: ```python #!/usr/bin/env python # -*- coding:utf-8 -*- import os import sys import shutil file_type_list = ['o'] def get_all_object_file_size(size_cmd, folder): filelist = [] for dirpath,dirnames,filenames in os.walk(folder): for file in filenames: file_type = file.split('.')[-1] if(file_type in file_type_list): file_fullname = os.path.join(dirpath, file) file_fullname = file_fullname[2:] filelist.append(file_fullname) system_cmd = size_cmd + ' ' for file in filelist: system_cmd = system_cmd + file + ' ' print(system_cmd) os.system(system_cmd) if(__name__=="__main__"): find_path = sys.argv[1] size_cmd = sys.argv[2] os.chdir(find_path) get_all_object_file_size(size_cmd, '.') ``` 保存一下这个脚本文件,存放在与rtthread.py同级的目录下。 直接执行scons编译,编译完后,就会把所有object文件的size打出来: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220908/963f787400dc6ce04cfc0c4e25f3e0ef.png) 抓取前后两次的大小对比,即可大致知道哪几个 **C文件** 编译出来的size变了。 其实,如果是在Linux下的开发环境,就不需要python脚本的协助了,直接命令行就能搞定。 ```shell find ./build -name "*.o" | xargs size ``` --- # 5、关于链接顺序对elf文件的影响 我之前有写过一篇因链接顺序引入的问题,可以参考下:[【GCC编译优化系列】另类的链接报错undefined reference to](https://club.rt-thread.org/ask/article/6f35a7af1ffb2e61.html) 虽然我的案例中,讲述的是 **undefin reference to** 问题,但本质也是跟 **链接有关**,这里也提到了obj的链接顺序的问题。 回到本案例的问题,既然 **怀疑是链接顺序不一样,导致最后链接处理的elf文件大小不一样**,那些我们需要找到证据来支撑,两次链接的顺序真的不一样吗? 可以这样去对比分析。 在env开发环境下,scons编译是支持 **VERBOSE** 输出,我们利用VERBOSE输出就可以知道最后的链接顺序是怎么样的。 在env中执行,scons --verbose 代替 scons: ```shell > scons --verbose scons: Reading SConscript files ... Newlib version:2.4.0 scons: done reading SConscript files. scons: Building targets ... scons: building associated VariantDir targets: build arm-none-eabi-g++ -o rtthread.elf -march=armv7-a -marm -msoft-float -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors -T link.lds build\0mem_leak_debug\mem_leak_debug.o build\0mem_leak_debug\mem_heap_hook.o build\applications\main.o build\applications\mnt.o build\applications\lcd_init.o build\drivers\drv_timer.o build\drivers\board.o build\drivers\drv_smc911x.o build\drivers\secondary_cpu.o build\drivers\drv_mouse.o build\drivers\drv_sdio.o build\drivers\serial.o build\drivers\drv_keyboard.o build\kernel\src\irq.o build\kernel\src\mem.o build\kernel\src\kservice.o build\kernel\src\thread.o build\kernel\src\slab.o build\kernel\src\clock.o build\kernel\src\cpu.o build\kernel\src\scheduler.o build\kernel\src\device.o build\kernel\src\timer.o build\kernel\src\ipc.o build\kernel\src\object.o build\kernel\src\idle.o build\kernel\src\components.o build\kernel\src\memheap.o build\kernel\src\signal.o build\kernel\src\mempool.o build\kernel\libcpu\arm\common\backtrace.o build\kernel\libcpu\arm\common\div0.o build\kernel\libcpu\arm\common\showmem.o build\kernel\libcpu\arm\cortex-a\vector_gcc.o build\kernel\libcpu\arm\cortex-a\cp15_gcc.o build\kernel\libcpu\arm\cortex-a\gic.o build\kernel\libcpu\arm\cortex-a\cache.o build\kernel\libcpu\arm\cortex-a\mmu.o build\kernel\libcpu\arm\cortex-a\context_gcc.o build\kernel\libcpu\arm\cortex-a\trap.o build\kernel\libcpu\arm\cortex-a\start_gcc.o build\kernel\libcpu\arm\cortex-a\stack.o build\kernel\libcpu\arm\cortex-a\cpu.o build\kernel\libcpu\arm\cortex-a\interrupt.o build\kernel\components\dfs\src\dfs_posix.o build\kernel\components\dfs\src\dfs_fs.o build\kernel\components\dfs\src\dfs.o build\kernel\components\dfs\src\dfs_file.o build\kernel\components\dfs\filesystems\devfs\devfs.o build\kernel\components\dfs\filesystems\elmfat\dfs_elm.o build\kernel\components\dfs\filesystems\elmfat\ff.o build\kernel\components\dfs\filesystems\elmfat\ffunicode.o build\kernel\components\dfs\filesystems\ramfs\dfs_ramfs.o build\kernel\components\dfs\filesystems\romfs\romfs.o build\kernel\components\dfs\filesystems\romfs\dfs_romfs.o build\kernel\components\finsh\shell.o build\kernel\components\finsh\msh.o build\kernel\components\finsh\msh_parse.o build\kernel\components\finsh\cmd.o build\kernel\components\finsh\msh_file.o build\kernel\components\libc\compilers\common\cstdio.o build\kernel\components\libc\compilers\common\ctime.o build\kernel\components\libc\compilers\common\cctype.o build\kernel\components\libc\compilers\common\cstring.o build\kernel\components\libc\compilers\common\cstdlib.o build\kernel\components\libc\compilers\common\cwchar.o build\kernel\components\libc\compilers\newlib\syscalls.o build\kernel\components\libc\cplusplus\cxx_crt_init.o build\kernel\components\libc\cplusplus\cxx_Semaphore.o build\kernel\components\libc\cplusplus\cxx_crt.o build\kernel\components\libc\cplusplus\cxx_Mutex.o build\kernel\components\libc\cplusplus\cxx_Thread.o build\kernel\components\libc\posix\delay\delay.o build\kernel\components\libc\posix\io\aio\aio.o build\kernel\components\libc\posix\io\poll\select.o build\kernel\components\libc\posix\io\poll\poll.o build\kernel\components\libc\posix\io\stdio\libc.o build\kernel\components\libc\posix\io\termios\termios.o build\kernel\components\libc\posix\ipc\mqueue.o build\kernel\components\libc\posix\ipc\semaphore.o build\kernel\components\libc\posix\pthreads\pthread_cond.o build\kernel\components\libc\posix\pthreads\pthread_spin.o build\kernel\components\libc\posix\pthreads\pthread_attr.o build\kernel\components\libc\posix\pthreads\pthread_rwlock.o build\kernel\components\libc\posix\pthreads\pthread_mutex.o build\kernel\components\libc\posix\pthreads\pthread.o build\kernel\components\libc\posix\pthreads\pthread_barrier.o build\kernel\components\libc\posix\pthreads\pthread_tls.o build\kernel\components\libc\posix\pthreads\sched.o build\kernel\components\libc\posix\signal\posix_signal.o build\kernel\components\lwp\arch\arm\cortex-a\lwp_gcc.o build\kernel\components\lwp\lwp_memheap.o build\kernel\components\lwp\lwp_mem.o build\kernel\components\lwp\lwp_syscall.o build\kernel\components\lwp\lwp.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\netdb.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ip.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\autoip.o build\kernel\components\net\lwip\lwip-2.0.3\src\netif\ethernet.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\netif.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\sys.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\sockets.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\netifapi.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\tcpip.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\ip4_addr.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\dhcp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\init.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\etharp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\memp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\ip4.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\netbuf.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\raw.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\ip4_frag.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\tcp_out.o build\kernel\components\net\lwip\lwip-2.0.3\src\netif\lowpan6.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\icmp.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\api_lib.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\inet_chksum.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\stats.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\err.o build\kernel\components\net\lwip\lwip-2.0.3\src\apps\ping\ping.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\tcp_in.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\dns.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\timeouts.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\igmp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\udp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\pbuf.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\def.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\api_msg.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\tcp.o build\kernel\components\net\lwip\port\ethernetif.o build\kernel\components\net\lwip\port\sys_arch.o build\kernel\components\net\netdev\src\netdev_ipaddr.o build\kernel\components\net\netdev\src\netdev.o build\kernel\components\net\sal\dfs_net\dfs_net.o build\kernel\components\net\sal\socket\net_sockets.o build\kernel\components\net\sal\src\sal_socket.o build\kernel\components\net\sal\socket\net_netdb.o build\kernel\components\net\sal\impl\af_inet_lwip.o build\kernel\components\drivers\i2c\i2c-bit-ops.o build\kernel\components\drivers\i2c\i2c_core.o build\kernel\components\drivers\i2c\i2c_dev.o build\kernel\components\drivers\ipc\completion.o build\kernel\components\drivers\ipc\dataqueue.o build\kernel\components\drivers\ipc\pipe.o build\kernel\components\drivers\ipc\ringblk_buf.o build\kernel\components\drivers\ipc\ringbuffer.o build\kernel\components\drivers\ipc\waitqueue.o build\kernel\components\drivers\ipc\workqueue.o build\kernel\components\drivers\misc\pin.o build\kernel\components\drivers\mtd\mtd_nand.o build\kernel\components\drivers\mtd\mtd_nor.o build\kernel\components\drivers\rtc\rtc.o build\kernel\components\drivers\rtc\soft_rtc.o build\kernel\components\drivers\sdio\block_dev.o build\kernel\components\drivers\sdio\mmc.o build\kernel\components\drivers\sdio\mmcsd_core.o build\kernel\components\drivers\sdio\sd.o build\kernel\components\drivers\sdio\sdio.o build\kernel\components\drivers\serial\serial.o build\kernel\components\drivers\spi\sfud\src\sfud.o build\kernel\components\drivers\spi\sfud\src\sfud_sfdp.o build\kernel\components\drivers\spi\spi_core.o build\kernel\components\drivers\spi\spi_dev.o build\kernel\components\drivers\spi\spi_flash_sfud.o build\kernel\components\drivers\spi\spi_msd.o build\kernel\components\drivers\watchdog\watchdog.o -lc -lm arm-none-eabi-objcopy -O binary rtthread.elf rtthread.bin arm-none-eabi-size rtthread.elf text data bss dec hex filename 588296 2144 189636 780076 be72c rtthread.elf ``` 从输出中,就可以知道各个object文件的链接顺序,抓取前后两次的编译(第二次编译 需要 **scons -c** 清除一下),这样一对比就可以知道两次编译的obj链接顺序了。 不过,我猜测,很大可能 **链接顺序是一样的**。 如果真的发现前后两次的链接顺序不一样,而且第一次的能工作,第二次的不能工作,**我就想把链接顺序永远使用第一次那个顺序**,该怎么办? 其实说来也简单,**没有什么是一个脚本解决不了的**。 env开发环境下是支持 BAT脚本的,只需要把上面的 scons的VERBOSE输出的最后那几句(**链接elf、导出bin文件、查看size**)命令填到BAT脚本(新建一个bat后缀的脚本文件)中,然后在rtthread.py中新增这个BAT脚本的执行即可。 **relink.bat** 内容如下,仅供参考,需要跟进实际情况修改: ```shell arm-none-eabi-g++ -o rtthread.elf -march=armv7-a -marm -msoft-float -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,system_vectors -T link.lds build\0mem_leak_debug\mem_leak_debug.o build\0mem_leak_debug\mem_heap_hook.o build\applications\main.o build\applications\mnt.o build\applications\lcd_init.o build\drivers\drv_timer.o build\drivers\board.o build\drivers\drv_smc911x.o build\drivers\secondary_cpu.o build\drivers\drv_mouse.o build\drivers\drv_sdio.o build\drivers\serial.o build\drivers\drv_keyboard.o build\kernel\src\irq.o build\kernel\src\mem.o build\kernel\src\kservice.o build\kernel\src\thread.o build\kernel\src\slab.o build\kernel\src\clock.o build\kernel\src\cpu.o build\kernel\src\scheduler.o build\kernel\src\device.o build\kernel\src\timer.o build\kernel\src\ipc.o build\kernel\src\object.o build\kernel\src\idle.o build\kernel\src\components.o build\kernel\src\memheap.o build\kernel\src\signal.o build\kernel\src\mempool.o build\kernel\libcpu\arm\common\backtrace.o build\kernel\libcpu\arm\common\div0.o build\kernel\libcpu\arm\common\showmem.o build\kernel\libcpu\arm\cortex-a\vector_gcc.o build\kernel\libcpu\arm\cortex-a\cp15_gcc.o build\kernel\libcpu\arm\cortex-a\gic.o build\kernel\libcpu\arm\cortex-a\cache.o build\kernel\libcpu\arm\cortex-a\mmu.o build\kernel\libcpu\arm\cortex-a\context_gcc.o build\kernel\libcpu\arm\cortex-a\trap.o build\kernel\libcpu\arm\cortex-a\start_gcc.o build\kernel\libcpu\arm\cortex-a\stack.o build\kernel\libcpu\arm\cortex-a\cpu.o build\kernel\libcpu\arm\cortex-a\interrupt.o build\kernel\components\dfs\src\dfs_posix.o build\kernel\components\dfs\src\dfs_fs.o build\kernel\components\dfs\src\dfs.o build\kernel\components\dfs\src\dfs_file.o build\kernel\components\dfs\filesystems\devfs\devfs.o build\kernel\components\dfs\filesystems\elmfat\dfs_elm.o build\kernel\components\dfs\filesystems\elmfat\ff.o build\kernel\components\dfs\filesystems\elmfat\ffunicode.o build\kernel\components\dfs\filesystems\ramfs\dfs_ramfs.o build\kernel\components\dfs\filesystems\romfs\romfs.o build\kernel\components\dfs\filesystems\romfs\dfs_romfs.o build\kernel\components\finsh\shell.o build\kernel\components\finsh\msh.o build\kernel\components\finsh\msh_parse.o build\kernel\components\finsh\cmd.o build\kernel\components\finsh\msh_file.o build\kernel\components\libc\compilers\common\cstdio.o build\kernel\components\libc\compilers\common\ctime.o build\kernel\components\libc\compilers\common\cctype.o build\kernel\components\libc\compilers\common\cstring.o build\kernel\components\libc\compilers\common\cstdlib.o build\kernel\components\libc\compilers\common\cwchar.o build\kernel\components\libc\compilers\newlib\syscalls.o build\kernel\components\libc\cplusplus\cxx_crt_init.o build\kernel\components\libc\cplusplus\cxx_Semaphore.o build\kernel\components\libc\cplusplus\cxx_crt.o build\kernel\components\libc\cplusplus\cxx_Mutex.o build\kernel\components\libc\cplusplus\cxx_Thread.o build\kernel\components\libc\posix\delay\delay.o build\kernel\components\libc\posix\io\aio\aio.o build\kernel\components\libc\posix\io\poll\select.o build\kernel\components\libc\posix\io\poll\poll.o build\kernel\components\libc\posix\io\stdio\libc.o build\kernel\components\libc\posix\io\termios\termios.o build\kernel\components\libc\posix\ipc\mqueue.o build\kernel\components\libc\posix\ipc\semaphore.o build\kernel\components\libc\posix\pthreads\pthread_cond.o build\kernel\components\libc\posix\pthreads\pthread_spin.o build\kernel\components\libc\posix\pthreads\pthread_attr.o build\kernel\components\libc\posix\pthreads\pthread_rwlock.o build\kernel\components\libc\posix\pthreads\pthread_mutex.o build\kernel\components\libc\posix\pthreads\pthread.o build\kernel\components\libc\posix\pthreads\pthread_barrier.o build\kernel\components\libc\posix\pthreads\pthread_tls.o build\kernel\components\libc\posix\pthreads\sched.o build\kernel\components\libc\posix\signal\posix_signal.o build\kernel\components\lwp\arch\arm\cortex-a\lwp_gcc.o build\kernel\components\lwp\lwp_memheap.o build\kernel\components\lwp\lwp_mem.o build\kernel\components\lwp\lwp_syscall.o build\kernel\components\lwp\lwp.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\netdb.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ip.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\autoip.o build\kernel\components\net\lwip\lwip-2.0.3\src\netif\ethernet.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\netif.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\sys.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\sockets.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\netifapi.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\tcpip.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\ip4_addr.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\dhcp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\init.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\etharp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\memp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\ip4.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\netbuf.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\raw.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\ip4_frag.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\tcp_out.o build\kernel\components\net\lwip\lwip-2.0.3\src\netif\lowpan6.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\icmp.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\api_lib.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\inet_chksum.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\stats.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\err.o build\kernel\components\net\lwip\lwip-2.0.3\src\apps\ping\ping.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\tcp_in.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\dns.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\timeouts.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\ipv4\igmp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\udp.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\pbuf.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\def.o build\kernel\components\net\lwip\lwip-2.0.3\src\api\api_msg.o build\kernel\components\net\lwip\lwip-2.0.3\src\core\tcp.o build\kernel\components\net\lwip\port\ethernetif.o build\kernel\components\net\lwip\port\sys_arch.o build\kernel\components\net\netdev\src\netdev_ipaddr.o build\kernel\components\net\netdev\src\netdev.o build\kernel\components\net\sal\dfs_net\dfs_net.o build\kernel\components\net\sal\socket\net_sockets.o build\kernel\components\net\sal\src\sal_socket.o build\kernel\components\net\sal\socket\net_netdb.o build\kernel\components\net\sal\impl\af_inet_lwip.o build\kernel\components\drivers\i2c\i2c-bit-ops.o build\kernel\components\drivers\i2c\i2c_core.o build\kernel\components\drivers\i2c\i2c_dev.o build\kernel\components\drivers\ipc\completion.o build\kernel\components\drivers\ipc\dataqueue.o build\kernel\components\drivers\ipc\pipe.o build\kernel\components\drivers\ipc\ringblk_buf.o build\kernel\components\drivers\ipc\ringbuffer.o build\kernel\components\drivers\ipc\waitqueue.o build\kernel\components\drivers\ipc\workqueue.o build\kernel\components\drivers\misc\pin.o build\kernel\components\drivers\mtd\mtd_nand.o build\kernel\components\drivers\mtd\mtd_nor.o build\kernel\components\drivers\rtc\rtc.o build\kernel\components\drivers\rtc\soft_rtc.o build\kernel\components\drivers\sdio\block_dev.o build\kernel\components\drivers\sdio\mmc.o build\kernel\components\drivers\sdio\mmcsd_core.o build\kernel\components\drivers\sdio\sd.o build\kernel\components\drivers\sdio\sdio.o build\kernel\components\drivers\serial\serial.o build\kernel\components\drivers\spi\sfud\src\sfud.o build\kernel\components\drivers\spi\sfud\src\sfud_sfdp.o build\kernel\components\drivers\spi\spi_core.o build\kernel\components\drivers\spi\spi_dev.o build\kernel\components\drivers\spi\spi_flash_sfud.o build\kernel\components\drivers\spi\spi_msd.o build\kernel\components\drivers\watchdog\watchdog.o -lc -lm arm-none-eabi-objcopy -O binary rtthread.elf rtthread.bin arm-none-eabi-size rtthread.elf ``` rtthread.py的修改如下: ```shell POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' +\ SIZE + ' $TARGET \n ' + \ 'python size.py build ' + SIZE + '\n' +\ 'relink.bat \n' ``` 这里其实就是,后面一次链接会覆盖前一次链接的结果,达到多次编译都是同一个链接顺序。 --- # 6、还有什么其他的东西可以辅助分析? 涉及编译、内存变化这类问题,我们不得漏掉还有一个文件也非常重要,那就是 **MAP文件**: 其实,如果前后两次编译生成的elf文件大小不一,在MAP文件中就可以看得出来: 可能类似这样,两个map文件是一样的: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220908/0c9bd45f65bc0c59139ec119f8c82329.png) 也有可能类似这样,存在差异: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220908/a20e9edbd7dffde01a7e4f4f7dcece8c.png.webp) 需要注意的是,比较MAP文件的时候,一定要学会 **抓大放小**,不能太抠细节,有些差异是可以忽略的。 通过MAP文件的差异,也能得出一些线索,再回过头来找代码。 另一个方面,如果整个工程中,链接了一些 **第三方库或者原厂的SDK库文件**,这部分虽然在我们的代码中是看不到的,但是最终会链接进我们的固件,也有可能会产生固件的不一样,这个就要具体问题具体分析了。 至于有没有链接第三方库,从scons的VERBOSE输出就可以知道,找到那些 **-l** 开头的,就是库名称。 --- # 7、总结 - 排查问题,需要保持清晰的思路,层层突破 - 拆解问题的能力,很关键,逐步缩小问题的范围,方可快速出击 - 不同固件导致运行结果不一样这类问题,可能有多个方面引起的:代码写得不规范、编译不严谨或者优化等级太高、链接问题这几个环境都可能引入,需要做的是找到根源; - 链接了第三方库或原厂SDK库,也不得不考虑它的引入问题;毕竟它们都是闭源的,出问题也不容易发现; - 祝早日解决bug。 # 8、更多分享 > **[架构师李肯](https://recan.blog.csdn.net/?type=blog)** > > **架构师李肯**(**全网同名**),一个专注于嵌入式IoT领域的架构师。有着近10年的嵌入式一线开发经验,深耕IoT领域多年,熟知IoT领域的业务发展,深度掌握IoT领域的相关技术栈,包括但不限于主流RTOS内核的实现及其移植、硬件驱动移植开发、网络通讯协议开发、编译构建原理及其实现、底层汇编及编译原理、编译优化及代码重构、主流IoT云平台的对接、嵌入式IoT系统的架构设计等等。拥有多项IoT领域的发明专利,热衷于技术分享,有多年撰写技术博客的经验积累,连续多月获得RT-Thread官方技术社区原创技术博文优秀奖,荣获[CSDN博客专家](https://recan.blog.csdn.net/?type=blog)、[CSDN物联网领域优质创作者](http://yyds.recan-li.cn)、[2021年度CSDN&RT-Thread技术社区之星](https://blog.csdn.net/szullc/article/details/123860472)、[2022年RT-Thread全球技术大会讲师](https://club.rt-thread.org/ask/article/afa56894c113369a.html)、[RT-Thread官方嵌入式开源社区认证专家](https://club.rt-thread.org/ask/experts.html)、[RT-Thread 2021年度论坛之星TOP4](https://club.rt-thread.org/ask/article/3317.html)、[华为云云享专家(嵌入式物联网架构设计师)](https://bbs.huaweicloud.com/community/usersnew/id_1573655458316259)等荣誉。坚信【知识改变命运,技术改变世界】! --- 欢迎关注我的[gitee仓库01workstation](https://gitee.com/recan-li/coding-01workstation) ,日常分享一些开发笔记和项目实战,欢迎指正问题。 同时也非常欢迎关注我的CSDN主页和专栏: [【CSDN主页-架构师李肯】](http://yyds.recan-li.cn) [【RT-Thread主页-架构师李肯】](https://club.rt-thread.org/u/18001) [【C/C++语言编程专栏】](https://blog.csdn.net/szullc/category_8450784.html) [【GCC专栏】](https://blog.csdn.net/szullc/category_8626555.html) [【信息安全专栏】](https://blog.csdn.net/szullc/category_8452787.html) [【RT-Thread开发笔记】](https://blog.csdn.net/szullc/category_11461616.html) [【freeRTOS开发笔记】](https://blog.csdn.net/szullc/category_11467856.html) 有问题的话,可以跟我讨论,知无不答,谢谢大家。
4
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
李肯陪你玩赚嵌入式
2022年度和2023年度RT-Thread社区优秀开源布道师,COC深圳城市开发者社区主理人,专注于嵌入式物联网的架构设计
文章
47
回答
504
被采纳
82
关注TA
发私信
相关文章
1
RT-Thread Studio在编译 Nano项目时报错?
2
文件夹没纳入编译,只能强制解锁
3
在程序添加完fal_init()接口之后,编译就报错了
4
怎样设置RT_studio编译时将代码从指定地址存放
5
rt-smart SCONS 怎么把kernel文件夹编译进去的
6
链接时找不到 exit 和 sbrk 等符号
7
使用ENV scons -j8编译和keil编译同一份工程目标bin文件差异很大
8
RT-Thread有没有像keil这样的编译前自定义执行的操作
9
rtthread studio编译问题
10
链接脚本中使用 ENTRY 的功能?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
出出啊
1518
个答案
343
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
813
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
3
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部