0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

【GCC编译优化系列】前后编译的两版本固件bin大小不一样?

嵌入式物联网开发 来源:嵌入式物联网开发 作者:嵌入式物联网开发 2022-09-09 09:01 次阅读

文章目录

  • 1、问题描述
  • 2、排查思路
  • 3、如何获取预编译文件、汇编文件等中间文件?
  • 4、object文件如何对比?
  • 5、关于链接顺序对elf文件的影响
  • 6、还有什么其他的东西可以辅助分析?
  • 7、总结
  • 8、更多分享


1、问题描述

这两天在论坛收到一个朋友的问题回答邀请,我仔细读了下该问题,跟我之前在论坛上发布的好几个问题关联还挺大的,所以抽空带着这个问题,重新梳理下思路,也希望这些思路能帮到这位朋友尽快解决问题。

它的问题描述如下,感兴趣的可以参考原文链接:RT-Thread4.1.0工程用scons连续编译生成的map文件差异很大

poYBAGMZ0dGAE9G_AAHoIbQ0iiE728.png

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RWep0HnX-1662636304782)(C:/Users/takeout.NEWNEW/AppData/Roaming/Typora/typora-user-images/image-20220908142659151.png)]

2、排查思路

我之前也遇到类似的工程编译出来的bin文件变大的一个问题:【GCC编译优化系列】从KEIL转战GCC,一个C库函数bin文件增大了十几KB

不过稍微不同的是,我之前的那个问题是编译器与自带的系统库(C库)的差异引入的,但这其中的排查思路倒是可以参考借鉴。

我先总结一下我的思路,参考如下:

  1. 既然是编译出来的bin固件大小不一,那我们需要抓一下生成固件bin的流程中,究竟是哪一个环节引入的变化?
  2. 笼统地说【编译】,其实有4个子环节:我在 【GCC编译优化系列】一文带你了解C代码到底是如何被编译的? 这篇文章中有介绍,主要分为 预编译、编译、汇编、链接
  3. 我们说两份一模一样的代码,理论上应该对比 预编译处理之后的代码,因为这个环节之后的代码,是没得变了,那些什么 __FILE__ __DATE__ __TIME__ 等等各种宏定义已经完全被展开了,下一步就直接送到 编译器 去执行编译,得到 汇编代码
  4. 上边对比预编译之后的代码,大概就能看出两次编译的代码,有哪些不同了;下一步,如果感兴趣,可以同样去对比下两份代码 生成的汇编代码,但是我不建议直接走这一步,因为难度会比较大,建议先往下走,到最后真的无路可走了,再回来这一步对比;
  5. 跳过对比 汇编代码,我们直接对比汇编代码之后的生成文件,叫 object文件 ,这类文件基本就已经把各个C文件的函数给捆起来了,我们是可以通过 linux 下的命令行工具 size 来查看的,类似会有这样的输出:
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文件。

最后一步,把所有的object文件执行链接(注意:obj的链接顺序也有可能会引起elf文件的变化,后面细讲),才是得到编译输出的固件文件,其实这里说的固件文件常见的分为3种:elf文件、hex文件、bin文件,其中elf文件是最原始的输出文件,而后面的hex文件、bin文件都可以由elf文件导出生成。这里顺便提一句,单单对比bin文件的大小,意义不是很大,如果仅仅是相差几个字节或者十几字节,我觉得是正常;真正我们需要比较的是 elf文件的 大小,这个大小不是说它占磁盘的大小,而是使用 size 命令查出来的大小,类似这样:

size rtthread.elf 
   text    data     bss     dec     hex filename
 557886    2100   87160  647146   9dfea rtthread.elf

​ 这里还有说明一下,如果前后的elf文件差异几个字节这种,很有可能是某些内存地址对齐导致的,4个字节或8个字节这样的差异。

  1. 总结一下,排查顺序:预编译后的代码文件 -》汇编代码文件(可暂时跳过)-》object文件 -> elf 文件 -> bin文件。主要采用的是对比法,至于如何对比这些文件,见下文分解。

3、如何获取预编译文件、汇编文件等中间文件?

env 开发环境为例(如果是以 RT-Thread Studio 为开发环境的,自行查找相关方法),bsp选用 qemu-vexpress-a9 作为参考:

rtthread.py 中的 CFLAGS 和 AFLAGS 添加 -save-temps=obj 如下所示:

    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脚本的调用:

    POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' +\
                  SIZE + ' $TARGET \n ' + \
                  'python size.py build ' + SIZE + '\n' 

size.py 脚本的内容如下:

#!/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打出来:

poYBAGMZ0fOAUf5bAAFxy9Clnzw723.png

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQYQXcIa-1662636304791)(C:/Users/takeout.NEWNEW/AppData/Roaming/Typora/typora-user-images/image-20220908134546908.png)]

抓取前后两次的大小对比,即可大致知道哪几个 C文件 编译出来的size变了。

其实,如果是在Linux下的开发环境,就不需要python脚本的协助了,直接命令行就能搞定。

find ./build -name "*.o" | xargs size

5、关于链接顺序对elf文件的影响

我之前有写过一篇因链接顺序引入的问题,可以参考下:【GCC编译优化系列】另类的链接报错undefined reference to

虽然我的案例中,讲述的是 undefin reference to 问题,但本质也是跟 链接有关,这里也提到了obj的链接顺序的问题。

回到本案例的问题,既然 怀疑是链接顺序不一样,导致最后链接处理的elf文件大小不一样,那些我们需要找到证据来支撑,两次链接的顺序真的不一样吗?

可以这样去对比分析。

在env开发环境下,scons编译是支持 VERBOSE 输出,我们利用VERBOSE输出就可以知道最后的链接顺序是怎么样的。

在env中执行,scons --verbose 代替 scons:

> 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 内容如下,仅供参考,需要跟进实际情况修改:

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的修改如下:

    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文件是一样的:

pYYBAGMZ0gmAKW3nAAEPeNkL87Y878.png

也有可能类似这样,存在差异:

poYBAGMZ0hyASOm5AAOZCu1fX-A505.png

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w1dynEKL-1662636304801)(C:/Users/takeout.NEWNEW/AppData/Roaming/Typora/typora-user-images/image-20220908141847669.png)]

需要注意的是,比较MAP文件的时候,一定要学会 抓大放小,不能太抠细节,有些差异是可以忽略的。

通过MAP文件的差异,也能得出一些线索,再回过头来找代码。

另一个方面,如果整个工程中,链接了一些 第三方库或者原厂的SDK库文件,这部分虽然在我们的代码中是看不到的,但是最终会链接进我们的固件,也有可能会产生固件的不一样,这个就要具体问题具体分析了。

至于有没有链接第三方库,从scons的VERBOSE输出就可以知道,找到那些 -l 开头的,就是库名称。


7、总结

  • 排查问题,需要保持清晰的思路,层层突破
  • 拆解问题的能力,很关键,逐步缩小问题的范围,方可快速出击
  • 不同固件导致运行结果不一样这类问题,可能有多个方面引起的:代码写得不规范、编译不严谨或者优化等级太高、链接问题这几个环境都可能引入,需要做的是找到根源;
  • 链接了第三方库或原厂SDK库,也不得不考虑它的引入问题;毕竟它们都是闭源的,出问题也不容易发现;
  • 祝早日解决bug。

8、更多分享

架构师李肯

架构师李肯全网同名),一个专注于嵌入式IoT领域的架构师。有着近10年的嵌入式一线开发经验,深耕IoT领域多年,熟知IoT领域的业务发展,深度掌握IoT领域的相关技术栈,包括但不限于主流RTOS内核的实现及其移植、硬件驱动移植开发、网络通讯协议开发、编译构建原理及其实现、底层汇编及编译原理、编译优化及代码重构、主流IoT云平台的对接、嵌入式IoT系统的架构设计等等。拥有多项IoT领域的发明专利,热衷于技术分享,有多年撰写技术博客的经验积累,连续多月获得RT-Thread官方技术社区原创技术博文优秀奖,荣获CSDN博客专家、CSDN物联网领域优质创作者、2021年度CSDN&RT-Thread技术社区之星、2022年RT-Thread全球技术大会讲师、RT-Thread官方嵌入式开源社区认证专家、RT-Thread 2021年度论坛之星TOP4、华为云云享专家(嵌入式物联网架构设计师)等荣誉。坚信【知识改变命运,技术改变世界】!


欢迎关注我的gitee仓库01workstation ,日常分享一些开发笔记和项目实战,欢迎指正问题。

同时也非常欢迎关注我的CSDN主页和专栏:

【CSDN主页-架构师李肯】

【RT-Thread主页-架构师李肯】

【C/C++语言编程专栏】

【GCC专栏】

信息安全专栏】

【RT-Thread开发笔记】

freeRTOS开发笔记】

有问题的话,可以跟我讨论,知无不答,谢谢大家。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • GCC
    GCC
    +关注

    关注

    0

    文章

    105

    浏览量

    24818
  • 编译
    +关注

    关注

    0

    文章

    652

    浏览量

    32800
  • RT-Thread
    +关注

    关注

    31

    文章

    1271

    浏览量

    39901
收藏 人收藏

    评论

    相关推荐

    种形式电路咪头拾音的信号大小不一样,为什么?

    如上图所示,种形式电路,用示波器测试,相同条件下测得咪头的信号大小不一样,请问是为什么呢?下面那种情况咪头信号大。
    发表于 09-20 08:23

    TLV320AIC3104在没有输入声音的时候,采集出来的信号底噪大小不一样,差异比较大是为什么?

    我们使用aic3104碰到以下问题,在没有输入声音的时候,采集出来的信号底噪大小不一样,差异比较大。 客户那边的测试情况是这样。
    发表于 10-10 06:18

    怎么让选项卡的大小不一样

    用选项卡的时候,选项卡1和选项卡2的内容多少不同,怎么分别让选项卡1选项卡2的大小不一样
    发表于 05-06 21:57

    cyclone iv的m9k使用大小不一样

    芯片使用的是EP4CE15F17C8,为啥个提示的M9K大小不一样呢?
    发表于 03-19 04:55

    keil自带的ARMCC V5和V6 和 GCC编译编译用时和目标文件的大小对比

    CMSIS需要不一样的头文件之外,所有用户代码完全致。2:用秒表计时,开始计时和全部重新编译按钮同时按下,编译完成时停止。因为手动掐表,肯定会有误差,但是大致的可以参考。(正常使用的
    发表于 09-06 23:46

    请问在输入信号和地之间接电容是滤波吗,这个电容大小不一样有什么区别吗?

    在输入电压和地之间接电容是滤波吗,这个电容大小不一样有什么区别吗?
    发表于 06-18 13:49

    GCC和ARMCC编译后生成BIN文件大小不一样是什么原因造成的呢

    最近发现个细节。同样的工程文件,使用ENV工具生成keil的工程,编译后转成bin文件后是80k.同样的工程使用scons编译后用GCC
    发表于 06-28 15:10

    GCC编译优化前后编译版本固件bin大小不一样

    1、前后编译版本固件bin大小不一样怎么办既然
    发表于 09-09 16:12

    gcc编译优化系列】如何获取gcc默认的链接脚本

    我们都知道在般的嵌入式开发中,使用gcc编译固件般流程是,先把所有的.c文件和.s文件编译
    的头像 发表于 07-11 09:15 3372次阅读

    GCC编译优化系列】实战分析C代码遇到的编译问题及解决思路

    GCC编译优化系列】实战分析C工程代码可能遇到的编译问题及其解决思路
    的头像 发表于 07-10 23:15 1361次阅读
    【<b class='flag-5'>GCC</b><b class='flag-5'>编译</b><b class='flag-5'>优化</b><b class='flag-5'>系列</b>】实战分析C代码遇到的<b class='flag-5'>编译</b>问题及解决思路

    GCC编译优化系列】multiple-definition

    GCC编译优化系列】这种让人看不懂的multiple-definition真的有点让人头疼
    的头像 发表于 07-11 09:26 6920次阅读
    【<b class='flag-5'>GCC</b><b class='flag-5'>编译</b><b class='flag-5'>优化</b><b class='flag-5'>系列</b>】multiple-definition

    GCC编译优化系列】-specs=kernel.specs

    GCC编译优化系列GCC编译链接时候--specs=kernel.specs链接属性究竟是个
    的头像 发表于 07-11 09:25 3306次阅读
    【<b class='flag-5'>GCC</b><b class='flag-5'>编译</b><b class='flag-5'>优化</b><b class='flag-5'>系列</b>】-specs=kernel.specs

    色环电感供应商科普为什么同款插件色环电感的电流大小不一样

    色环电感供应商科普为什么同款插件色环电感的电流大小不一样 编辑:谷景电子 电感对很多人来说真的是既熟悉又陌生,即便是很多经常接触电子产品人来说,围绕电感应用方面的知识也不一定知道的很多。比如本篇要跟
    的头像 发表于 12-12 15:15 932次阅读

    电容容量一样大小不一样能用吗

    有时候家里面电器中的电容损坏,很多人很难找到一模一样的来更换,能找到容量致的电容器就不容易了,电容容量一样大小不一样能用吗?
    的头像 发表于 09-21 09:54 2352次阅读

    电容容量一样大小不一样能用吗?

    电容容量一样大小不一样能用吗? 电容器(Capacitor)是种用来存储电荷能量的电子元件。它是由个导体板(般是金属)和
    的头像 发表于 09-22 16:30 6343次阅读