1. 程式人生 > >ADS簡單程式編譯分析(2)

ADS簡單程式編譯分析(2)

繼續上一篇文章的工作。上文說到已經有了原始的ucos底層系統,因此將ucos系統剝離出來,獨自編譯,下載到晶片中,注意下載方式選擇只擦除當前頁不要選全部擦除。在編譯器可以看出來,目前ucos系統大約佔140k的RO空間,26.4k的RW空間。通過觀察scf檔案,可以知道,把棧頂分配到了0x40008000,堆分配到了0x40000000。因為需要使用IAP功能,參照ARM說明書,需要把0x40008000向下的32個位元組空間保留出來,建議修改使用者堆疊,因此在Startup.s中修改分配棧的函式,原程式為:

InitStack    
        MOV     R0, LR

;Build the SVC stack
;設定中斷模式堆疊
        MSR     CPSR_c, #0xd2
        LDR     SP, StackIrq
;Build the FIQ stack    
;設定快速中斷模式堆疊
        MSR     CPSR_c, #0xd1
        LDR     SP, StackFiq
;Build the DATAABORT stack
;設定中止模式堆疊
        MSR     CPSR_c, #0xd7
        LDR     SP, StackAbt
;Build the UDF stack
;設定未定義模式堆疊
        MSR     CPSR_c, #0xdb
        LDR     SP, StackUnd
;Build the SYS stack
;設定系統模式堆疊
        MSR     CPSR_c, #0x1f
        LDR     SP, =StackUsr

        MOV     PC, R0

這裡為ARM的6種模式都分配了SP,其中我們僅關心StackUsr,因為其值為0x40008000,將其修改為

        LDR     SP, =StackUsr - 1024

這裡減去1024位元組而不是32位元組是因為留一些空間另作他用。因此修改後的棧頂變為0x40007c00。

由於ucos佔用了部分記憶體和flash,且本應用沒有用到虛擬記憶體,因此在上一篇文章中,將編譯器RO設定為0x29c00,RW設定為0x40003000,這樣可以保證燒寫得時候不會把ucos的程式覆蓋,且記憶體空間不會重疊。

將上一篇文章生成的程式碼直接燒寫入晶片,果然僅燒寫了2個page,通過除錯工具可以看到兩段程式碼並沒有重疊(512k的flash都可以當作記憶體觀察)。

在ucos燒寫前,加入呼叫使用者程式的入口:

typedef int (*UsrMain)();
...
    UsrMain p; 
    p = (UsrMain)(0x29c00); 
    (*p)();
...

通過單步除錯,程式可以正確的進入0x29c00執行。

但是,全速執行程式並不能實現想要的結果(在0x40004000中連續寫入數字)。通過觀察發現,基本上定位死在了上一篇文章中沒有分析的神祕的swi附近,彙編程式碼如下:

__user_initial_stackheap
$a
0x00029f28:    e92d4000    [email protected]    STMFD    r13!,{r14}
0x00029f2c:    e24dd014    ..M.    SUB      r13,r13,#0x14
0x00029f30:    e1a0100d    ....    MOV      r1,r13
0x00029f34:    e28d2004    . ..    ADD      r2,r13,#4
0x00029f38:    e5812000    . ..    STR      r2,[r1,#0]
0x00029f3c:    e3a00016    ....    MOV      r0,#0x16
0x00029f40:    ef123456    V4..    SWI      0x123456
0x00029f44:    e59d0004    ....    LDR      r0,[r13,#4]
0x00029f48:    e59d100c    ....    LDR      r1,[r13,#0xc]
0x00029f4c:    e59d2008    . ..    LDR      r2,[r13,#8]
0x00029f50:    e59d3010    .0..    LDR      r3,[r13,#0x10]
0x00029f54:    e3500000    ..P.    CMP      r0,#0
0x00029f58:    059f000c    ....    LDREQ    r0,0x29f6c
0x00029f5c:    e28dd014    ....    ADD      r13,r13,#0x14
0x00029f60:    e8bd4000    
[email protected]
LDMFD r13!,{r14} 0x00029f64: e12fff1e ../. BX r14

通過上篇文章分析,這些程式碼都是一些初始化記憶體空間,以及測試程式是否能正確執行的操作,因此這裡SWI 0x123456應為測試軟中斷,觀察ucos的軟中斷,發現沒有對0x123456的軟中斷進行處理,其具體影響就是系統進入了svc(系統)模式,SP切換到了系統使用的SP,而0x123456沒有對應的軟中斷,因此係統直接返回了,返回後為系統模式(這裡應該算是個bug,使用者態隨意就能切換到系統態了),sp不對,下面的出棧得到的返回地址就不對了,因此程式跑飛了。因此對ucos的swi程式作如下修改:

;軟體中斷
SoftwareInterrupt

        ;CMP        SP, #0
        ;BEQ        continue1
        ;STMFD   SP!, {R1}
        ;LDR        R1, =0x40007c00
        ;STR        SP, [R1]
        ;LDMFD   SP!, {R1}

continue1       
        LDR     SP, StackSvc            ; 重新設定堆疊指標
        STMFD   SP!, {R0-R3, R12, LR}
        MOV     R1, SP                  ; R1指向引數儲存位置

        MRS     R3, SPSR
        TST     R3, #T_bit              ; 中斷前是否是Thumb狀態
        LDRNEH  R0, [LR,#-2]            ; 是: 取得Thumb狀態SWI號
        BICNE   R0, R0, #0xff00
        LDREQ   R0, [LR,#-4]            ; 否: 取得arm狀態SWI號
        BICEQ   R0, R0, #0xFF000000

                                        ; r0 = SWI號,R1指向引數儲存位置
        LDR     R3, =0x123456
        CMP     R0, R3
        BEQ     Swi123
        MRS     R3, SPSR

        CMP     R0, #1
        LDRLO   PC, =OSIntCtxSw
        LDREQ   PC, =__OSStartHighRdy   ; SWI 0x01為第一次任務切換

        BL      SWI_Exception

        LDMFD   SP!, {R0-R3, R12, PC}^

StackSvc           DCD     (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)
Swi123          ;123456呼叫切換回使用者模式,且r1=sp+0x20
                LDMFD   SP!, {R0-R3, R12, LR}
                MRS     R0, SPSR
                BIC     R0, R0, #0x1f
                ORR     R0, R0, #USR32Mode  
                MOV     R1, R14
                MSR     CPSR_c, R0
                MOV     LR, R1
                ADD     R1, SP, #0x20
                STR     R1, [SP, #0x0c]
                MOV     PC, LR

        MOV     PC, LR

如果標號為0x123456則切換回使用者態,且根據呼叫程式碼分析,還要把SP向上12個位元組位置中寫入SP+0x20的值才能正確執行。

經過以上修改後,重新分別下載ucos和使用者程式,程式能夠正確執行。

但在添加了一些c的程式碼後,程式又不能夠正確運行了,仔細查詢的編譯後的程式裡面的swi,發現了swi 0xab這個呼叫,是一個THUMB指令,通過在網上搜索swi 0x123456 0xab,終於發現了蛛絲馬跡,原來這兩個軟中斷是ads為了與電腦上位機通訊保留的軟中斷,但我們實際的程式中並沒有實現此軟中斷,因此需要關閉這個選項。

ADS中並沒有提供關閉通訊軟中斷的選項,而swi命令又是編譯器自行新增的程式碼,我們無法控制,參照網上所說的,以及別人的程式碼的分析,進行如下步驟可以讓編譯器不產生軟中斷。下面是詳細的分析:

首先在程式加入如下程式碼:

    #include <stdio.h>

    #pragma import(__use_no_semihosting_swi);//保證使用者程式不呼叫semihostSWI;

通過stdio.h裡面觀察有如下的註解:

extern void __use_no_semihosting_swi(void);
    /*
     * Referencing this symbol will cause a link-time error if any
     * library functions that use semihosting SWI calls are also
     * present in the link, i.e. you define it if you want to make
     * sure you haven't accidentally used any such SWIs.
     */

引用此符號後,如果任何庫函式使用了swi呼叫的話,將會產生連結錯誤,也就是說,如果你不使用任何預期以外的swi的話可以使用此功能

新增此程式碼後,再次編譯程式,果然報錯了。去掉此函式(編譯報錯則不生成彙編),編譯出彙編結果,通過查詢彙編程式碼,發現swi出現的段落為:

  1. __user_initial_stackheap
  2. _sys_exit

按照網上所說的,新增如下彙編程式碼:

     AREA ||.text||, CODE, READONLY
__user_initial_stackheap
       LDR r0, =0x40003000 
       MOV PC,LR
     EXPORT __user_initial_stackheap
       END

此段程式碼將0x40003000(可根據自己的程式進行修改)作為返回值賦予r0,並匯出__user_initial_stackheap,使用者程式並沒有用到__user_initial_stackheap符號,因此匯出不匯出無所謂。
如此看來,編譯器在編譯時檢測到__user_initial_stackheap段,將會自動替代該段。

編譯後再次檢查,發現__user_initial_stackheap段果然變成了我們自己新增的內容。

將檢查swi的程式碼添加回程式,編譯,仍然報錯。檢查程式碼發現在_sys_exit段仍有呼叫。觀察底層系統的程式碼,發現如下的程式碼段:

        void _sys_exit(int returncode)
{
    returncode = returncode;
}

新增後發現因為有了_sys_exit符號,因此編譯器同樣使用我們的程式替換了彙編程式碼中的_sys_exit。

如此,再次加入檢查swi的語句,編譯成功。將此前修改的底層軟中斷處理函式恢復原樣,仍可正常執行.

相關推薦

ADS簡單程式編譯分析2

繼續上一篇文章的工作。上文說到已經有了原始的ucos底層系統,因此將ucos系統剝離出來,獨自編譯,下載到晶片中,注意下載方式選擇只擦除當前頁不要選全部擦除。在編譯器可以看出來,目前ucos系統大約佔140k的RO空間,26.4k的RW空間。通過觀察scf檔案,

編譯原理——詞法分析2

1.1串和語言        字母表是一個有限的符號集合。符號的典型例子包括字母、數位和標點符號。如集合{0,1}是二進位制字母表。 某個字母表的串(string)是該字母表符號的有窮序列,空串是長度為0的串。 語言(language):是某個給定字元表上任意的可數

微信小程式學習筆記2----HelloWorld分析

寫在前面 IDE結構 上圖是微信開發工具自動生成的一個HelloWorld,微信小程式的開發、除錯都在這個工具中完成,相比於eclipse、Idea之類的Idea,小程式顯示功能比較少,沒多少選單。 編輯 編輯選單中是存放程式碼的,可以建

DELPHI中完成端口(IOCP)的簡單分析2

ast .data 我們 ESS 我會 清空 意見 lse tla 今天我寫一下關於DELPHI編寫完成端口(IOCP)的工作者線程中的東西。希望各位能提出批評意見。上次我寫了關於常見IOCP的代碼,對於IOCP來說,接受到客戶端發送過來和自己發送出去的數據都是從工作者線程

效能分析2- 應用程式 CPU 使用率過高案例

效能分析小案例系列,可以通過下面連結檢視哦 https://www.cnblogs.com/poloyy/category/1814570.html   系統架構背景 其中一臺用作 Web 伺服器,來模擬效能問題 另一臺用作 Web 伺服器的客戶端,來給 Web 服務增加壓力請求 使用兩臺虛擬機

java實現簡單二維迷宮2

blog 成員 new 構建 push port ava amp use 這次是改良版本。 將地圖封裝,老鼠封裝。是對Java基礎的一個練習吧。 這次實現也遇到了一些問題。主要是棧。封裝的mouse類中有成員變量i,j代表了老鼠的坐標。將mouse類對象m入棧的時候,總是入

Web API應用架構設計分析2

最好 factor 狀態 是否 沒有 dot sel nal std Web API應用架構設計分析(2) 在上篇隨筆《Web API應用架構設計分析(1)》,我對Web API的各種應用架構進行了概括性的分析和設計,Web API 是一種應用接口框架,它能夠構建HTT

Android 消息處理源代碼分析2

urn msg illegal r.java roi fin 報錯 mes pri Android 消息處理源代碼分析(1)點擊打開鏈接 繼續接著分析剩下的類文件 Looper.java public final class Looper {

.net 反編譯筆記2

最終 使用 很多 項目 否則 大型 復雜 lsp 可選 自上次分享net軟件反編譯相關已一年多,今天再次分享一點幹貨。 1、net反編譯軟件已經相當成熟,具有導出項目的能力。不過大型項目導出的錯誤修復仍然是最耗時的工作,並且初級開發人員容易將一些代碼修復得不對邏輯但是這

Arm虛擬化:效能和構架分析2

微信公眾號 mindshare思享   如下圖所示,Xen和KVM採用不同的方式使用arm的硬體虛擬化支援。 Xen作為type1 hypervisor設計比較容易直接使用arm構架提供的功能,直接將hypervisor運行於EL2,將VM的users pace

Apache 流框架 Flink,Spark Streaming,Storm對比分析2

此文已由作者嶽猛授權網易雲社群釋出。 歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。 2.Spark Streaming架構及特性分析 2.1 基本架構 基於是spark core的spark streaming架構。 Spark Streaming是將流式計算分解成一系列短小的批處理作業。這裡的批處

Mybatis 原始碼分析2—— 引數處理

Mybatis對引數的處理是值得推敲的,不然在使用的過程中對發生的一系列錯誤直接懵逼了。 以前遇到引數繫結相關的錯誤我就是直接給加@param註解,也稀裡糊塗地解決了,但是後來遇到了一些問題推翻了我的假設:單個引數不需要使用 @param 。由此產生了一個疑問,Mybatis到底是怎

PackageManagerService 原始碼分析2

  一.scanPackageLI PKMS 中呼叫scanDirLI來分析APK 檔案,如果目錄下的是apk檔案或者是目錄,會繼續呼叫scanPackageLI函式: private PackageParser.Package scanPackageLI(File s

簡單的爬蟲知識2

cookie的使用 方法1: headers={ "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0

LoadRunner測試結果分析2

上一篇所述測試過程的重點在於事務,而LoadRunner生成的測試結果圖並不侷限於事務上,其中還有是關於Vusers、Errors、Web Resources、Web Page diagnostics的測試圖。 1. 對於Vusers的測試圖有3種:Running Vusers、Vuse

Python程式設計 簡單的影象處理2

有關中醫舌像的簡單分析 黑白圖的應用十分廣泛,它是深度學習影象處理的基礎,是影象分割、影象拼接、影象紋理分析等等技術的組成部分,較常見的應用在於X線圖片、CT圖片、MRI圖片、B超圖片、電鏡圖片等醫學領域。 在傳統醫學的“望聞問切”四診中,望診作為疾病視覺資訊的診察手段被譽為“四診之首”,舌

flowable EngineConfiguration的實現分析2

EngineConfiguration的實現類是一個抽象類:AbstractEngineConfiguration 一、引擎配置的分類 繼承 AbsractEngineConfiguration的子類實現不同方面的功能,包括: 1、身份管理引擎配置 2、表單引擎配置

簡單的二級購物車2

6.自定義的包 6.1 —CarTitleView public class CarTitleView extends LinearLayout implements View.OnClickListener{ private CarTitleInterface carT

_069_Java_Java的String記憶體分析2

String類的記憶體分析:         在Java之中有一種稱為共享設計模式的概念.在JVM的底層會存在有一個物件池,在物件池之中會保留有已經開闢空間的物件,那麼String就是利用了物件池的概念,當利用直接賦值的形式定義一個字串時,第一次會開闢新的堆記憶體空間,

Android進階3:Activity原始碼分析2 —— Activity啟動和銷燬流程8.0

上篇文章講述了app從啟動建立Activity呼叫onCreate,onStart, onResume方法,這篇文章講述一下Activity啟動的另一個切入點:startActivity方法,啟動Activity。 通過上一篇文章,我們總結一下: 1:A