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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...