U-Boot GOT表分析和u-boot.lds解讀

来源:http://www.cnblogs.com/julyatgalileo/archive/2016/03/02/5233428.html
-Advertisement-
Play Games

轉自:http://blog.sina.com.cn/s/blog_70dd16910100zab6.html u-boot-2010.09/arch/powerpc/cpu/mpc86xx/start.S文件中的創建GOT段的代碼片段如下: // Set up GOT: Global Offset


轉自:http://blog.sina.com.cn/s/blog_70dd16910100zab6.html

u-boot-2010.09/arch/powerpc/cpu/mpc86xx/start.S文件中的創建GOT段的代碼片段如下:

 // Set up GOT: Global Offset Table

 // Use r12 to access the GOT

       START_GOT

       GOT_ENTRY(_GOT2_TABLE_)

       GOT_ENTRY(_FIXUP_TABLE_)

       GOT_ENTRY(_start)

       GOT_ENTRY(_start_of_vectors)

       GOT_ENTRY(_end_of_vectors)

       GOT_ENTRY(transfer_to_handler)

       GOT_ENTRY(__init_end)

       GOT_ENTRY(_end)

       GOT_ENTRY(__bss_start)

       END_GOT

操作GOT表的函數在u-boot-2010.09/include/ppc_asm.tmpl文件中,相關代碼如下:

 // These definitions simplify the ugly declarations necessary for GOT

 // definitions.

 // Stolen from prepboot/bootldr.h, (C) 1998 Gabriel Paubert, [email protected]

 // Uses r12 to access the GOT

 

#define START_GOT                 \

       .section  ".got2","aw";      \

.LCTOC1 = .+32768                                 <1>

 

#define END_GOT                            \

       .text                                      <2>

 

#define GET_GOT                            \      <3>

       bl    1f           ;      \

       .text       2            ;      \

0:    .long       .LCTOC1-1f  ;      \

       .text                     ;      \

1:    mflr              r12         ;      \

       lwz  r0,0b-1b(r12) ;      \

       add  r12,r0,r12      ;

 

#define GOT_ENTRY(NAME)    .L_ ## NAME = . - .LCTOC1 ; .long NAME     <4>

#define GOT(NAME)          .L_ ## NAME (r12)                          <5>

 

分析:

<1>: START_GOT定義了段“got2”,屬性為“allocatable and writable”,並定義了變數.LCTOC1,.LCTOC1的值是表的最高地址;如果設表的起始地址為TABLE_START,則.LCTOC1的值為TABLE_START+0x8000;

<2>:END_GOT定義為子節.text 的起始處;

<3>:

GET_GOT用於初始化GOT表。首先程式跳轉到標號為“1”的地址處(bl 1f),然後將lr的值賦值給r12(此時lr的值為“1:”的地址值)。然後令r0 = 0b - 1b(r12),0b為“0:”處的地址值,1b為“1:”處的地址值。這樣r0就等於“0:”處的值,也就是.LCTOC1-1f。最後r12 = r0 + r12 = .LCTOC1 - 1f + 1f = .LCTOC1,也就是等於GOT表的最高地址。

<4>:

GOT_ENTRY定義了變數.L_NAME,其值為當前表項的地址(.)-.LCTOC1。如果設NAME的表項偏移地址為NAME_OFFSET,那麼.L_NAME = . - .LCTOC1 = TABLE_START + NAME_OFFSET – (TABLE_START + 0x8000)= NAME_OFFSET - 0x8000。之後將名字為NAME的offset值寫入當前表項,這些offset值是在編譯的時候確定的。

備註:##是字元串連接符,比如L_##TOM其實就是字元串L_TOM

<5>:

GOT(NAME)的值定義為.L_NAME(r12),這裡面r12的值為表的最高地址,也就是.LCTOC1的值。

這樣GOT(NAME) = .L_NAME + r12= .L_NAME + .LCTOC1 = NAME_OFFSET - 0x8000 + TABLE_START + 0x8000 = NAME_OFFSET + TABLE_START,也就是NAME所在表項的地址。這樣,通過查表,就可以找到當初存儲在表中的名字為NAME的offset值。

小結:

START_GOT用於定義表的開始,END_GOT用於定義表的結束,GOT_ENTRY用於將offset寫入表中,GOT用於從表中讀出 offset,GET_GOT用於將表進行初始化

動態庫要解決的一個問題是代碼/變數地址在編譯時不能確定,GOT就是用來解決這個問題的技術。 u-boot運行時要從Flash搬到RAM高端,RAM大小是運行時檢測出來的,編譯時不能確定,這和動態庫面對的問題相同,正好可以用GOT技術解決

參考資料:

http://blog.csdn.net/foriner/article/details/5847501

關於GOT表的機制可以參考我的一篇博文:

http://blog.sina.com.cn/s/blog_70dd16910100r1gi.html

 

第二部分 u-boot.lds解讀

2.1:board/freescale/mpc8641hpcn/目錄下有兩個文件:u-boot.lds和config.mk

u-boot.lds定義了整個程式編譯之後的連接過程,決定了一個可執行程式的各個段的存儲位置,從中可以找到u-boot的函數入口。config.mk文件用於設置TEXT_BASE的地址,該地址就是代碼運行的鏈接地址。

下麵我們來分析u-boot.lds和config.mk文件。

備註:我分析的U-Boot版本為:u-boot-2010.09.tar.bz2

2.2:具體分析及註解如下

OUTPUT_ARCH(powerpc)

//指定輸出的可執行文件的平臺為powerpc

SECTIONS

{

//指定各個段內容,只讀的各個節(section)均放到代碼段(text)中

  .interp : { *(.interp) }

//定義 .interp段,該段由所有代碼的.interp段共同組成

  .hash          : { *(.hash)           }

//.hash段: 由所有代碼的.hash段共同組成,hash表允許在不對全表元素進行線性搜索的情況下快速訪問所有的符合表項。

  .dynsym     : { *(.dynsym)    }

  .dynstr      : { *(.dynstr)             }

  .rel.text      : { *(.rel.text)     }

  .rela.text     : { *(.rela.text)    }

  .rel.data      : { *(.rel.data)    }

  .rela.data     : { *(.rela.data)   }

  .rel.rodata    : { *(.rel.rodata) }

  .rela.rodata   : { *(.rela.rodata)       }

  .rel.got       : { *(.rel.got)     }

  .rela.got      : { *(.rela.got)   }

  .rel.ctors     : { *(.rel.ctors)   }

  .rela.ctors    : { *(.rela.ctors) }

  .rel.dtors     : { *(.rel.dtors)   }

  .rela.dtors    : { *(.rela.dtors) }

  .rel.bss       : { *(.rel.bss)           }

  .rela.bss      : { *(.rela.bss)          }

  .rel.plt       : { *(.rel.plt)              }

  .rela.plt      : { *(.rela.plt)            }

  .init          : { *(.init)  }

  .plt : { *(.plt) }

  .text      :

//定義文本段

  {

arch/powerpc/cpu/mpc86xx/start.o      (.text)

//文本段的第一部分start.S,後跟其他做文本段

    arch/powerpc/cpu/mpc86xx/traps.o (.text)

    arch/powerpc/cpu/mpc86xx/interrupts.o (.text)

    arch/powerpc/cpu/mpc86xx/cpu_init.o (.text)

    arch/powerpc/cpu/mpc86xx/cpu.o (.text)

    arch/powerpc/cpu/mpc86xx/speed.o (.text)

    common/dlmalloc.o (.text)

    lib/crc32.o (.text)

    arch/powerpc/lib/extable.o (.text)

    lib/zlib.o (.text)

    drivers/bios_emulator/atibios.o (.text)

    *(.text)

    *(.got1)

   }

    _etext = .;

    PROVIDE (etext = .);

    .rodata    :

   {

    *(.eh_frame)

    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))

  }

  .fini      : { *(.fini)    } =0

  .ctors     : { *(.ctors)   }

  .dtors     : { *(.dtors)   }

 

 

  . = (. + 0x00FF) & 0xFFFFFF00;

//地址對齊(地址低8位為0)

  _erotext = .;

  PROVIDE (erotext = .);

  .reloc   :

//從定位段.reloc的組成

  {

    *(.got)   // got段

_GOT2_TABLE_ = .;  

//_GOT2_TABLE_值為當前地址,同時也是.got段結束地址,另外也是.got2段起始地址

    *(.got2)  // got2段

_FIXUP_TABLE_ = .;

//_FIXUP_TABLE_值為當前地址,同時也是.got2段結束地址;另外也是.fixup段起始地

    *(.fixup)

  }

  __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2;

//__got2_entries符號定義,其值為GOT表項個數,每個表項占4位元組

  __fixup_entries = (. - _FIXUP_TABLE_) >> 2;

//__fixup_entries值為.fixup的字個數

  .data    :    //數據段

  {

    *(.data)

    *(.data1)

    *(.sdata)

    *(.sdata2)

    *(.dynamic)

    CONSTRUCTORS

  }

  _edata  =  .;  //數據段結束

  PROVIDE (edata = .);

 

  . = .;

  __u_boot_cmd_start = .; //定義u-boot命令起始地址,board_init_r中有調用

  .u_boot_cmd : { *(.u_boot_cmd) }  //u_boot_cmd段

  __u_boot_cmd_end = .; //定義u-boot命令結束地址

 

  . = .;

  __start___ex_table = .;

  __ex_table : { *(__ex_table) }

  __stop___ex_table = .;

 

  . = ALIGN(256);   //256個位元組對齊

  __init_begin = .;

  .text.init : { *(.text.init) }

  .data.init : { *(.data.init) }

  . = ALIGN(256);

  __init_end = .;

// start.S中relocate_code函數計算u-boot鏡像text長度,利用了__init_end,後面不再搬運,直接清零clear_bss

  __bss_start = .;  // bss代碼段起始地址

  .bss (NOLOAD)       :

  {

   *(.sbss) *(.scommon)

   *(.dynbss)

   *(.bss)

   *(COMMON)

   . = ALIGN(4);

  }

  _end = . ;   //_end 符號定義 bss代碼段結束地址,u-boot鏡像結束地址

  PROVIDE (end = .);

}// SECTIONS 對各段定義完畢

 

同時在board/freescale/mpc8641hpcn/ config.mk文件中U-Boot在RAM中的程式入口地址,具體內容如下:

#

# mpc8641hpcn board

# default CCSRBAR is at 0xff700000

# assume U-Boot is less than 0.5MB

#

TEXT_BASE = 0xeff00000

解釋:TEXT_BASE是U-Boot在RAM中的程式入口地址,U-Boot啟動以後,在RAM中就運行在這個地址往上的空間。這個地址是U-Boot的指令最開始的地址(對很多PowerPC,例如我們的MPC8641HPCN,一般在這個地址開始的一個0x100位元組的偏移處)。在Flash中啟動的話,這個地址就在Flash中。

註意的是:TEXT_BASE是鏈接地址,UBoot第一個階段的初始化運行的時間地址,有時候會和這一地址不一致,但是MMU開啟之後,所用的地址均是鏈接地址了。


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

-Advertisement-
Play Games
更多相關文章
  • 上一篇說了一下查詢5步走~然後就幾天_(:з」∠)_ ~今天繼續說一下其中 表裡面操作符裡面的 Pivot ~ Pivot 在實現行轉列的時候灰常有用。通常一個例子 CREATE TABLE #Tbl (Emp VARCHAR(50), [WeekDay] VARCHAR(50),LoginTime
  • SQL語句分組排序,多表關聯排序總結幾種常見的方法: 案例一: 在查詢結果中按人數降序排列,若人數相同,則按課程號升序排列? 分析:單個表內的多個欄位排序,一般可以直接用逗號分割實現。 select * from tableA order by col1 desc,col2 asc; -- 先按co
  • null是什麼? 不知道。我是說,他的意思就是不知道(unknown)。 它和true、false組成謂詞的三個邏輯值,代表“未知”。與true和false相比,null最難以令人捉摸,因為它沒有明確的值,在不同的場景下,它能代表不同的含義。下文以例子的方式給大家分享下null使用的典型場景及對應的
  • samza是一個分散式的流式數據處理框架(streaming processing),它是基於Kafka消息隊列來實現類實時的流式數據處理的。(準確的說,samza是通過模塊化的形式來使用kafka的,因此可以構架在其他消息隊列框架上,但出發點和預設實現是基於kafka)
  • 一、註解方式 1. 在Spring的配置文件ApplicationContext.xml,首先添加命名空間 1 xmlns:task="http://www.springframework.org/schema/task" 2 http://www.springframework.org/schem
  • 當磁碟或者分區的容量超過16TB的時候,如何格式化呢?mkfs不能滿足需求。
  • 對於日常運維的一個簡單的經驗,做個記錄,希望幫助到一些人
  • 簡介 用簡單的話來定義tcpdump,就是:dump the traffic on a network,根據使用者的定義對網路上的數據包進行截獲的包分析工具。 tcpdump可以將網路中傳送的數據包的“頭”完全截獲下來提供分析。它支持針對網路層、協議、主機、網路或埠的過濾,並提供and、or、no
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...