newlib 中的 crt0 流程分析

来源:http://www.cnblogs.com/swyang/archive/2017/05/17/6870226.html
-Advertisement-
Play Games

最近對 newlib 中的啟動代碼 crt0 產生了興趣,於是就分析了下其代碼。crt0 的源碼位於 libgloss/arm/crt0.S,為了相容各種 ARM 架構,crt0.S 中有大量的條件判斷巨集定義,對於只關心 ARMv7e-M 的我來說很是痛苦。剛好手上有個基於 STM32F412 的 ...


最近對 newlib 中的啟動代碼 crt0 產生了興趣,於是就分析了下其代碼。crt0 的源碼位於 libgloss/arm/crt0.S,為了相容各種 ARM 架構,crt0.S 中有大量的條件判斷巨集定義,對於只關心 ARMv7e-M 的我來說很是痛苦。剛好手上有個基於 STM32F412 的 mbed 工程用的是 crt0 的啟動方式,參考 crt0.o 的反彙編我可以提煉出 crt0.S 中和 ARMv7e-M 相關的部分代碼。

crt0.o 的反彙編如下:

08008220 <_mainCRTStartup>:
 8008220:    4b15          ldr    r3, [pc, #84]    ; (8008278 <_mainCRTStartup+0x58>)
 8008222:    2b00          cmp    r3, #0
 8008224:    bf08          it    eq
 8008226:    4b13          ldreq    r3, [pc, #76]    ; (8008274 <_mainCRTStartup+0x54>)
 8008228:    469d          mov    sp, r3
 800822a:    f5a3 3a80     sub.w    sl, r3, #65536    ; 0x10000
 800822e:    2100          movs    r1, #0
 8008230:    468b          mov    fp, r1
 8008232:    460f          mov    r7, r1
 8008234:    4813          ldr    r0, [pc, #76]    ; (8008284 <_mainCRTStartup+0x64>)
 8008236:    4a14          ldr    r2, [pc, #80]    ; (8008288 <_mainCRTStartup+0x68>)
 8008238:    1a12          subs    r2, r2, r0
 800823a:    f01c fcd7     bl    8024bec <memset>
 800823e:    4b0f          ldr    r3, [pc, #60]    ; (800827c <_mainCRTStartup+0x5c>)
 8008240:    2b00          cmp    r3, #0
 8008242:    d000          beq.n    8008246 <_mainCRTStartup+0x26>
 8008244:    4798          blx    r3
 8008246:    4b0e          ldr    r3, [pc, #56]    ; (8008280 <_mainCRTStartup+0x60>)
 8008248:    2b00          cmp    r3, #0
 800824a:    d000          beq.n    800824e <_mainCRTStartup+0x2e>
 800824c:    4798          blx    r3
 800824e:    2000          movs    r0, #0
 8008250:    2100          movs    r1, #0
 8008252:    0004          movs    r4, r0
 8008254:    000d          movs    r5, r1
 8008256:    480d          ldr    r0, [pc, #52]    ; (800828c <_mainCRTStartup+0x6c>)
 8008258:    2800          cmp    r0, #0
 800825a:    d002          beq.n    8008262 <_mainCRTStartup+0x42>
 800825c:    480c          ldr    r0, [pc, #48]    ; (8008290 <_mainCRTStartup+0x70>)
 800825e:    f00f f868     bl    8017332 <__wrap_atexit>
 8008262:    f01c f805     bl    8024270 <__libc_init_array>
 8008266:    0020          movs    r0, r4
 8008268:    0029          movs    r1, r5
 800826a:    f00f f821     bl    80172b0 <__wrap_main>
 800826e:    f00f f85d     bl    801732c <__wrap_exit>
 8008272:    bf00          nop
 8008274:    00080000     .word    0x00080000
 8008278:    20040000     .word    0x20040000
 800827c:    00000000     .word    0x00000000
 8008280:    080172a3     .word    0x080172a3
 8008284:    20000c00     .word    0x20000c00
 8008288:    2000ac58     .word    0x2000ac58
 800828c:    08017333     .word    0x08017333
 8008290:    00000000     .word    0x00000000

提煉後的 crt0.S 代碼如下:

    FUNC_START  _mainCRTStartup
    FUNC_START  _start
/* Start by setting up a stack */

    /*  Set up the stack pointer to a fixed value */
    /*  Changes by toralf:
        - Allow linker script to provide stack via __stack symbol - see
          defintion of .Lstack
        - Provide "hooks" that may be used by the application to add
          custom init code - see .Lhwinit and .Lswinit  
        - Go through all execution modes and set up stack for each of them.
          Loosely based on init.s from ARM/Motorola example code.
              Note: Mode switch via CPSR is not allowed once in non-privileged
            mode, so we take care not to enter "User" to set up its sp,
            and also skip most operations if already in that mode. */

    ldr r3, .Lstack
    cmp r3, #0

    it  eq

    ldreq   r3, .LC0
    /* Note: This 'mov' is essential when starting in User, and ensures we
         always get *some* sp value for the initial mode, even if we 
         have somehow missed it below (in which case it gets the same
         value as FIQ - not ideal, but better than nothing.) */
    mov sp, r3

.LC23:
    /* Setup a default stack-limit in-case the code has been
       compiled with "-mapcs-stack-check".  Hard-wiring this value
       is not ideal, since there is currently no support for
       checking that the heap and stack have not collided, or that
       this default 64k is enough for the program being executed.
       However, it ensures that this simple crt0 world will not
       immediately cause an overflow event:  */
    sub sl, r3, #64 << 10   /* Still assumes 256bytes below sl */

    /* Zero the memory in the .bss section.  */
    movs    a2, #0          /* Second arg: fill value */
    mov fp, a2          /* Null frame pointer */
    mov r7, a2          /* Null frame pointer for Thumb */
    
    ldr a1, .LC1        /* First arg: start of memory block */
    ldr a3, .LC2    
    subs    a3, a3, a1      /* Third arg: length of block */
    
    bl  memset

/* Changes by toralf: Taken from libgloss/m68k/crt0.S
 * initialize target specific stuff. Only execute these
 * functions it they exist.
 */
    ldr r3, .Lhwinit
    cmp r3, #0
    beq .LC24
    indirect_call r3
.LC24:  
    ldr r3, .Lswinit
    cmp r3, #0
    beq .LC25
    indirect_call r3

.LC25:  
    movs    r0, #0      /*  no arguments  */
    movs    r1, #0      /*  no argv either */

    /* Some arm/elf targets use the .init and .fini sections
       to create constructors and destructors, and for these
       targets we need to call the _init function and arrange
       for _fini to be called at program exit.  */
    movs    r4, r0
    movs    r5, r1e

    /* Make reference to atexit weak to avoid unconditionally pulling in
       support code.  Refer to comments in __atexit.c for more details.  */
    ldr r0, .Latexit
    cmp r0, #0
    beq .Lweak_atexit

    ldr r0, .Lfini
    bl  atexit
.Lweak_atexit:
    bl  _init
    movs    r0, r4
    movs    r1, r5

    bl  main

    bl  exit        /* Should not return.  */
    
    /* For Thumb, constants must be after the code since only 
       positive offsets are supported for PC relative addresses.  */
.LC0:
    .word   0x80000         /* Top of RAM on the PIE board.  */
.Lstack:    
    .word   __stack
.Lhwinit:   
    .word   ardware_init_hook
.Lswinit:
    .word   software_init_hook

    /* Set up defaults for the above variables in the form of weak symbols
       - so that application will link correctly, and get value 0 in
       runtime (meaning "ignore setting") for the variables, when the user
       does not provide the symbols. (The linker uses a weak symbol if,
       and only if, a normal version of the same symbol isn't provided
       e.g. by a linker script or another object file.) */  

    .weak __stack
    .weak hardware_init_hook
    .weak software_init_hook

.LC1:
  .word __bss_start__
.LC2:
  .word __bss_end__

  .weak atexit
.Latexit:
  .word atexit

  /* Weak reference _fini in case of lite exit.  */
  .weak _fini
.Lfini:
  .word _fini

crt0 啟動流程如下:

  1. 設置 SP 為 __stack,若 __stack 未被用戶定義,則使用預設的值(0x80000處的值)。
  2. 清空 .bss 段,起始地址為 __bss_start__,結束地址為 __bss_end__ 。
  3. 若用戶定義了 hardware_init_hook 和 software_init_hook ,則調用它們。
  4. 若用戶定義了 atexit,則調用它,並將傳遞參數 _fini(_fini 被巨集定義為 __libc_fini_array)。
  5. 調用 _init(_ini 被巨集定義為 __libc_ini_array)。
  6. 調用 main(argc 和 argv 都等於 0)。
  7. 調用 exit。

其中 __stack,__bss_start__ 和 __bss_end__ 必須被定義。

hardware_init_hook 和 software_init_hook 可以實現一些需要在 main 之前的功能。

aiexit,exit,_init 和 _fini 一般是和 C++ 的全局構造和析構有關,這個放在下一節來分析。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • CSV模塊 1、CSV文件格式 要在文本文件中存儲數據,最簡單的方式是講數據作為一系列逗號分隔的值(CSV)寫入文件,這樣的文件成為CSV文件,如下: AKDT,Max TemperatureF,Mean TemperatureF,Min TemperatureF,Max Dew PointF,Me ...
  • 緩存 Laravel 給多種緩存系統提供豐富而統一的 API,緩存配置信息位於 config/cache.php,在這個文件中你可以為你的應用程式指定預設的緩存驅動,Laravel 支持當前流行的緩存系統,如非常棒的 Memcached 和 Redis 。 Memcached 1、配置 使用 Mem ...
  • 1.java概述 1. 前言 1.1 學習方法 1.2 推薦博客 當代程式員都應該養成寫博客、看博客的習慣 1.3 博客編輯神器 2. 內容:Java概述 2.1 Java語言發展史 2.1.1 電腦語言發展史 閱讀電腦語言之後回答幾個問題: 2.1.2 Java語言發展史 閱讀java語言之後 ...
  • 200 OK 請求成功。一般用於GET與POST請求 301 Moved Permanently 永久移動。請求的資源已被永久的移動到新URI,返回信息會包括新的URI,瀏覽器會自動定向到新URI。今後任何新的請求都應使用新的URI代替 302 Found 臨時移動。與301類似。但資源只是臨時被移 ...
  • 分享一個VBA的一個把一個sheet中的多個table(每一個table又hyperlinks),分配在不同的sheet中的方法,做這個真的也是耗費了不少的腦細胞。 Option Explicit ’這個是一個好習慣 ’第一種方法,通過currentregion來判斷區域,但是不是很保險 Sub G ...
  • 本節探討Java中的動態代理,介紹其用法和基本實現原理,利用它實現簡單的AOP框架 ...
  • 一、從石油工程師到IT入門 本人是石油工程師,長期在中東兩伊邊境油田工作,常年漂泊在外。眾所周知,石油行業環境艱苦,長石油的地方不是在鳥不拉屎的沙漠,深山老林,就是在驚濤駭浪的海上平臺。記得第一次到伊拉克邊境的時候,里三層,外三層全是雇佣軍,警察和士兵把手,連井場都不能隨處亂走,因為聽說兩伊戰爭的時 ...
  • https://msdn.microsoft.com/en-us/library/d4cfawwc.aspx For the latest documentation on Visual Studio 2017, see Visual Studio 2017 Documentation. Resou ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...