0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【GCC編譯優(yōu)化系列】前后編譯的兩版本固件bin大小不一樣?

嵌入式物聯(lián)網(wǎng)開發(fā) ? 來(lái)源:嵌入式物聯(lián)網(wǎng)開發(fā) ? 作者:嵌入式物聯(lián)網(wǎng)開發(fā) ? 2022-09-09 09:01 ? 次閱讀

文章目錄

  • 1、問(wèn)題描述
  • 2、排查思路
  • 3、如何獲取預(yù)編譯文件、匯編文件等中間文件?
  • 4、object文件如何對(duì)比?
  • 5、關(guān)于鏈接順序?qū)lf文件的影響
  • 6、還有什么其他的東西可以輔助分析?
  • 7、總結(jié)
  • 8、更多分享


1、問(wèn)題描述

這兩天在論壇收到一個(gè)朋友的問(wèn)題回答邀請(qǐng),我仔細(xì)讀了下該問(wèn)題,跟我之前在論壇上發(fā)布的好幾個(gè)問(wèn)題關(guān)聯(lián)還挺大的,所以抽空帶著這個(gè)問(wèn)題,重新梳理下思路,也希望這些思路能幫到這位朋友盡快解決問(wèn)題。

它的問(wèn)題描述如下,感興趣的可以參考原文鏈接:RT-Thread4.1.0工程用scons連續(xù)編譯生成的map文件差異很大

poYBAGMZ0dGAE9G_AAHoIbQ0iiE728.png

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-RWep0HnX-1662636304782)(C:/Users/takeout.NEWNEW/AppData/Roaming/Typora/typora-user-images/image-20220908142659151.png)]

2、排查思路

我之前也遇到類似的工程編譯出來(lái)的bin文件變大的一個(gè)問(wèn)題:【GCC編譯優(yōu)化系列】從KEIL轉(zhuǎn)戰(zhàn)GCC,一個(gè)C庫(kù)函數(shù)bin文件增大了十幾KB

不過(guò)稍微不同的是,我之前的那個(gè)問(wèn)題是編譯器與自帶的系統(tǒng)庫(kù)(C庫(kù))的差異引入的,但這其中的排查思路倒是可以參考借鑒。

我先總結(jié)一下我的思路,參考如下:

  1. 既然是編譯出來(lái)的bin固件大小不一,那我們需要抓一下生成固件bin的流程中,究竟是哪一個(gè)環(huán)節(jié)引入的變化?
  2. 籠統(tǒng)地說(shuō)【編譯】,其實(shí)有4個(gè)子環(huán)節(jié):我在 【GCC編譯優(yōu)化系列】一文帶你了解C代碼到底是如何被編譯的? 這篇文章中有介紹,主要分為 預(yù)編譯、編譯、匯編、鏈接 ;
  3. 我們說(shuō)兩份一模一樣的代碼,理論上應(yīng)該對(duì)比 預(yù)編譯處理之后的代碼,因?yàn)檫@個(gè)環(huán)節(jié)之后的代碼,是沒(méi)得變了,那些什么 __FILE__ __DATE__ __TIME__ 等等各種宏定義已經(jīng)完全被展開了,下一步就直接送到 編譯器 去執(zhí)行編譯,得到 匯編代碼;
  4. 上邊對(duì)比預(yù)編譯之后的代碼,大概就能看出兩次編譯的代碼,有哪些不同了;下一步,如果感興趣,可以同樣去對(duì)比下兩份代碼 生成的匯編代碼,但是我不建議直接走這一步,因?yàn)殡y度會(huì)比較大,建議先往下走,到最后真的無(wú)路可走了,再回來(lái)這一步對(duì)比;
  5. 跳過(guò)對(duì)比 匯編代碼,我們直接對(duì)比匯編代碼之后的生成文件,叫 object文件 ,這類文件基本就已經(jīng)把各個(gè)C文件的函數(shù)給捆起來(lái)了,我們是可以通過(guò) linux 下的命令行工具 size 來(lái)查看的,類似會(huì)有這樣的輸出:
size build/kernel/src/memheap.o
   text    data     bss     dec     hex filename
   6730       0       0    6730    1a4a build/kernel/src/memheap.o

? 我們需要對(duì)比每一個(gè)object文件的size,找出有差異的那些object文件。

最后一步,把所有的object文件執(zhí)行鏈接(注意:obj的鏈接順序也有可能會(huì)引起elf文件的變化,后面細(xì)講),才是得到編譯輸出的固件文件,其實(shí)這里說(shuō)的固件文件常見的分為3種:elf文件、hex文件、bin文件,其中elf文件是最原始的輸出文件,而后面的hex文件、bin文件都可以由elf文件導(dǎo)出生成。這里順便提一句,單單對(duì)比bin文件的大小,意義不是很大,如果僅僅是相差幾個(gè)字節(jié)或者十幾字節(jié),我覺(jué)得是正常;真正我們需要比較的是 elf文件的 大小,這個(gè)大小不是說(shuō)它占磁盤的大小,而是使用 size 命令查出來(lái)的大小,類似這樣:

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

? 這里還有說(shuō)明一下,如果前后的elf文件差異幾個(gè)字節(jié)這種,很有可能是某些內(nèi)存地址對(duì)齊導(dǎo)致的,4個(gè)字節(jié)或8個(gè)字節(jié)這樣的差異。

  1. 總結(jié)一下,排查順序:預(yù)編譯后的代碼文件 -》匯編代碼文件(可暫時(shí)跳過(guò))-》object文件 -> elf 文件 -> bin文件。主要采用的是對(duì)比法,至于如何對(duì)比這些文件,見下文分解。

3、如何獲取預(yù)編譯文件、匯編文件等中間文件?

env 開發(fā)環(huán)境為例(如果是以 RT-Thread Studio 為開發(fā)環(huán)境的,自行查找相關(guān)方法),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文件(預(yù)編譯后的文件)和.s文件(匯編文件) 生成了。

前后編譯的兩個(gè)版本,把這些.i文件文件拎出來(lái)對(duì)比,即可。


4、object文件如何對(duì)比?

考慮在env開發(fā)環(huán)境下使用 find 命令并不好使,我特意寫了一個(gè)python腳本,用于批量查詢object文件的size:

只需要在rtthread.py的最后加上這個(gè)python腳本的調(diào)用:

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

size.py 腳本的內(nèi)容如下:

#!/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, '.')

保存一下這個(gè)腳本文件,存放在與rtthread.py同級(jí)的目錄下。

直接執(zhí)行scons編譯,編譯完后,就會(huì)把所有object文件的size打出來(lái):

poYBAGMZ0fOAUf5bAAFxy9Clnzw723.png

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-dQYQXcIa-1662636304791)(C:/Users/takeout.NEWNEW/AppData/Roaming/Typora/typora-user-images/image-20220908134546908.png)]

抓取前后兩次的大小對(duì)比,即可大致知道哪幾個(gè) C文件 編譯出來(lái)的size變了。

其實(shí),如果是在Linux下的開發(fā)環(huán)境,就不需要python腳本的協(xié)助了,直接命令行就能搞定。

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

5、關(guān)于鏈接順序?qū)lf文件的影響

我之前有寫過(guò)一篇因鏈接順序引入的問(wèn)題,可以參考下:【GCC編譯優(yōu)化系列】另類的鏈接報(bào)錯(cuò)undefined reference to

雖然我的案例中,講述的是 undefin reference to 問(wèn)題,但本質(zhì)也是跟 鏈接有關(guān),這里也提到了obj的鏈接順序的問(wèn)題。

回到本案例的問(wèn)題,既然 懷疑是鏈接順序不一樣,導(dǎo)致最后鏈接處理的elf文件大小不一樣,那些我們需要找到證據(jù)來(lái)支撐,兩次鏈接的順序真的不一樣嗎?

可以這樣去對(duì)比分析。

在env開發(fā)環(huán)境下,scons編譯是支持 VERBOSE 輸出,我們利用VERBOSE輸出就可以知道最后的鏈接順序是怎么樣的。

在env中執(zhí)行,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

從輸出中,就可以知道各個(gè)object文件的鏈接順序,抓取前后兩次的編譯(第二次編譯 需要 scons -c 清除一下),這樣一對(duì)比就可以知道兩次編譯的obj鏈接順序了。

不過(guò),我猜測(cè),很大可能 鏈接順序是一樣的。

如果真的發(fā)現(xiàn)前后兩次的鏈接順序不一樣,而且第一次的能工作,第二次的不能工作,我就想把鏈接順序永遠(yuǎn)使用第一次那個(gè)順序,該怎么辦?

其實(shí)說(shuō)來(lái)也簡(jiǎn)單,沒(méi)有什么是一個(gè)腳本解決不了的。

env開發(fā)環(huán)境下是支持 BAT腳本的,只需要把上面的 scons的VERBOSE輸出的最后那幾句(鏈接elf、導(dǎo)出bin文件、查看size)命令填到BAT腳本(新建一個(gè)bat后綴的腳本文件)中,然后在rtthread.py中新增這個(gè)BAT腳本的執(zhí)行即可。

relink.bat 內(nèi)容如下,僅供參考,需要跟進(jìn)實(shí)際情況修改:

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' 

這里其實(shí)就是,后面一次鏈接會(huì)覆蓋前一次鏈接的結(jié)果,達(dá)到多次編譯都是同一個(gè)鏈接順序。


6、還有什么其他的東西可以輔助分析?

涉及編譯、內(nèi)存變化這類問(wèn)題,我們不得漏掉還有一個(gè)文件也非常重要,那就是 MAP文件

其實(shí),如果前后兩次編譯生成的elf文件大小不一,在MAP文件中就可以看得出來(lái):

可能類似這樣,兩個(gè)map文件是一樣的:

pYYBAGMZ0gmAKW3nAAEPeNkL87Y878.png

也有可能類似這樣,存在差異:

poYBAGMZ0hyASOm5AAOZCu1fX-A505.png

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-w1dynEKL-1662636304801)(C:/Users/takeout.NEWNEW/AppData/Roaming/Typora/typora-user-images/image-20220908141847669.png)]

需要注意的是,比較MAP文件的時(shí)候,一定要學(xué)會(huì) 抓大放小,不能太摳細(xì)節(jié),有些差異是可以忽略的。

通過(guò)MAP文件的差異,也能得出一些線索,再回過(guò)頭來(lái)找代碼。

另一個(gè)方面,如果整個(gè)工程中,鏈接了一些 第三方庫(kù)或者原廠的SDK庫(kù)文件,這部分雖然在我們的代碼中是看不到的,但是最終會(huì)鏈接進(jìn)我們的固件,也有可能會(huì)產(chǎn)生固件的不一樣,這個(gè)就要具體問(wèn)題具體分析了。

至于有沒(méi)有鏈接第三方庫(kù),從scons的VERBOSE輸出就可以知道,找到那些 -l 開頭的,就是庫(kù)名稱。


7、總結(jié)

  • 排查問(wèn)題,需要保持清晰的思路,層層突破
  • 拆解問(wèn)題的能力,很關(guān)鍵,逐步縮小問(wèn)題的范圍,方可快速出擊
  • 不同固件導(dǎo)致運(yùn)行結(jié)果不一樣這類問(wèn)題,可能有多個(gè)方面引起的:代碼寫得不規(guī)范、編譯不嚴(yán)謹(jǐn)或者優(yōu)化等級(jí)太高、鏈接問(wèn)題這幾個(gè)環(huán)境都可能引入,需要做的是找到根源;
  • 鏈接了第三方庫(kù)或原廠SDK庫(kù),也不得不考慮它的引入問(wèn)題;畢竟它們都是閉源的,出問(wèn)題也不容易發(fā)現(xiàn);
  • 祝早日解決bug。

8、更多分享

架構(gòu)師李肯

架構(gòu)師李肯全網(wǎng)同名),一個(gè)專注于嵌入式IoT領(lǐng)域的架構(gòu)師。有著近10年的嵌入式一線開發(fā)經(jīng)驗(yàn),深耕IoT領(lǐng)域多年,熟知IoT領(lǐng)域的業(yè)務(wù)發(fā)展,深度掌握IoT領(lǐng)域的相關(guān)技術(shù)棧,包括但不限于主流RTOS內(nèi)核的實(shí)現(xiàn)及其移植、硬件驅(qū)動(dòng)移植開發(fā)、網(wǎng)絡(luò)通訊協(xié)議開發(fā)、編譯構(gòu)建原理及其實(shí)現(xiàn)、底層匯編及編譯原理、編譯優(yōu)化及代碼重構(gòu)、主流IoT云平臺(tái)的對(duì)接、嵌入式IoT系統(tǒng)的架構(gòu)設(shè)計(jì)等等。擁有多項(xiàng)IoT領(lǐng)域的發(fā)明專利,熱衷于技術(shù)分享,有多年撰寫技術(shù)博客的經(jīng)驗(yàn)積累,連續(xù)多月獲得RT-Thread官方技術(shù)社區(qū)原創(chuàng)技術(shù)博文優(yōu)秀獎(jiǎng),榮獲CSDN博客專家、CSDN物聯(lián)網(wǎng)領(lǐng)域優(yōu)質(zhì)創(chuàng)作者、2021年度CSDN&RT-Thread技術(shù)社區(qū)之星、2022年RT-Thread全球技術(shù)大會(huì)講師、RT-Thread官方嵌入式開源社區(qū)認(rèn)證專家、RT-Thread 2021年度論壇之星TOP4、華為云云享專家(嵌入式物聯(lián)網(wǎng)架構(gòu)設(shè)計(jì)師)等榮譽(yù)。堅(jiān)信【知識(shí)改變命運(yùn),技術(shù)改變世界】!


歡迎關(guān)注我的gitee倉(cāng)庫(kù)01workstation ,日常分享一些開發(fā)筆記和項(xiàng)目實(shí)戰(zhàn),歡迎指正問(wèn)題。

同時(shí)也非常歡迎關(guān)注我的CSDN主頁(yè)和專欄:

【CSDN主頁(yè)-架構(gòu)師李肯】

【RT-Thread主頁(yè)-架構(gòu)師李肯】

【C/C++語(yǔ)言編程專欄】

【GCC專欄】

信息安全專欄】

【RT-Thread開發(fā)筆記】

freeRTOS開發(fā)筆記】

有問(wèn)題的話,可以跟我討論,知無(wú)不答,謝謝大家。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • GCC
    GCC
    +關(guān)注

    關(guān)注

    0

    文章

    105

    瀏覽量

    24798
  • 編譯
    +關(guān)注

    關(guān)注

    0

    文章

    647

    瀏覽量

    32746
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1251

    瀏覽量

    39751
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    種形式電路咪頭拾音的信號(hào)大小不一樣,為什么?

    如上圖所示,種形式電路,用示波器測(cè)試,相同條件下測(cè)得咪頭的信號(hào)大小不一樣,請(qǐng)問(wèn)是為什么呢?下面那種情況咪頭信號(hào)大。
    發(fā)表于 09-20 08:23

    TLV320AIC3104在沒(méi)有輸入聲音的時(shí)候,采集出來(lái)的信號(hào)底噪大小不一樣,差異比較大是為什么?

    我們使用aic3104碰到以下問(wèn)題,在沒(méi)有輸入聲音的時(shí)候,采集出來(lái)的信號(hào)底噪大小不一樣,差異比較大。 客戶那邊的測(cè)試情況是這樣。
    發(fā)表于 10-10 06:18

    怎么讓選項(xiàng)卡的大小不一樣

    用選項(xiàng)卡的時(shí)候,選項(xiàng)卡1和選項(xiàng)卡2的內(nèi)容多少不同,怎么分別讓選項(xiàng)卡1選項(xiàng)卡2的大小不一樣
    發(fā)表于 05-06 21:57

    cyclone iv的m9k使用大小不一樣

    芯片使用的是EP4CE15F17C8,為啥個(gè)提示的M9K大小不一樣呢?
    發(fā)表于 03-19 04:55

    keil自帶的ARMCC V5和V6 和 GCC編譯編譯用時(shí)和目標(biāo)文件的大小對(duì)比

    CMSIS需要不一樣的頭文件之外,所有用戶代碼完全致。2:用秒表計(jì)時(shí),開始計(jì)時(shí)和全部重新編譯按鈕同時(shí)按下,編譯完成時(shí)停止。因?yàn)槭謩?dòng)掐表,肯定會(huì)有誤差,但是大致的可以參考。(正常使用的
    發(fā)表于 09-06 23:46

    請(qǐng)問(wèn)在輸入信號(hào)和地之間接電容是濾波嗎,這個(gè)電容大小不一樣有什么區(qū)別嗎?

    在輸入電壓和地之間接電容是濾波嗎,這個(gè)電容大小不一樣有什么區(qū)別嗎?
    發(fā)表于 06-18 13:49

    GCC和ARMCC編譯后生成BIN文件大小不一樣是什么原因造成的呢

    最近發(fā)現(xiàn)個(gè)細(xì)節(jié)。同樣的工程文件,使用ENV工具生成keil的工程,編譯后轉(zhuǎn)成bin文件后是80k.同樣的工程使用scons編譯后用GCC
    發(fā)表于 06-28 15:10

    GCC編譯優(yōu)化前后編譯個(gè)版本固件bin大小不一樣

    1、前后編譯個(gè)版本固件bin大小不一樣怎么辦既然
    發(fā)表于 09-09 16:12

    gcc編譯優(yōu)化系列】如何獲取gcc默認(rèn)的鏈接腳本

    我們都知道在般的嵌入式開發(fā)中,使用gcc編譯固件般流程是,先把所有的.c文件和.s文件編譯
    的頭像 發(fā)表于 07-11 09:15 ?3205次閱讀

    GCC編譯優(yōu)化系列】實(shí)戰(zhàn)分析C代碼遇到的編譯問(wèn)題及解決思路

    GCC編譯優(yōu)化系列】實(shí)戰(zhàn)分析C工程代碼可能遇到的編譯問(wèn)題及其解決思路
    的頭像 發(fā)表于 07-10 23:15 ?1323次閱讀
    【<b class='flag-5'>GCC</b><b class='flag-5'>編譯</b><b class='flag-5'>優(yōu)化</b><b class='flag-5'>系列</b>】實(shí)戰(zhàn)分析C代碼遇到的<b class='flag-5'>編譯</b>問(wèn)題及解決思路

    GCC編譯優(yōu)化系列】multiple-definition

    GCC編譯優(yōu)化系列】這種讓人看不懂的multiple-definition真的有點(diǎn)讓人頭疼
    的頭像 發(fā)表于 07-11 09:26 ?6782次閱讀
    【<b class='flag-5'>GCC</b><b class='flag-5'>編譯</b><b class='flag-5'>優(yōu)化</b><b class='flag-5'>系列</b>】multiple-definition

    GCC編譯優(yōu)化系列】-specs=kernel.specs

    GCC編譯優(yōu)化系列GCC編譯鏈接時(shí)候--specs=kernel.specs鏈接屬性究竟是個(gè)
    的頭像 發(fā)表于 07-11 09:25 ?3218次閱讀
    【<b class='flag-5'>GCC</b><b class='flag-5'>編譯</b><b class='flag-5'>優(yōu)化</b><b class='flag-5'>系列</b>】-specs=kernel.specs

    色環(huán)電感供應(yīng)商科普為什么同款插件色環(huán)電感的電流大小不一樣

    色環(huán)電感供應(yīng)商科普為什么同款插件色環(huán)電感的電流大小不一樣 編輯:谷景電子 電感對(duì)很多人來(lái)說(shuō)真的是既熟悉又陌生,即便是很多經(jīng)常接觸電子產(chǎn)品人來(lái)說(shuō),圍繞電感應(yīng)用方面的知識(shí)也不一定知道的很多。比如本篇要跟
    的頭像 發(fā)表于 12-12 15:15 ?895次閱讀

    電容容量一樣大小不一樣能用嗎

    有時(shí)候家里面電器中的電容損壞,很多人很難找到一模一樣的來(lái)更換,能找到容量致的電容器就不容易了,電容容量一樣大小不一樣能用嗎?
    的頭像 發(fā)表于 09-21 09:54 ?2220次閱讀

    電容容量一樣大小不一樣能用嗎?

    電容容量一樣大小不一樣能用嗎? 電容器(Capacitor)是種用來(lái)存儲(chǔ)電荷能量的電子元件。它是由個(gè)導(dǎo)體板(般是金屬)和
    的頭像 發(fā)表于 09-22 16:30 ?5945次閱讀