VS2005混合編譯ARM彙編代碼

在開發過程當中,發現簡單的在Storage Memory區域拷貝或粘貼文件不能達到硬件量測的要求,須要直接經過編寫ARM彙編指令讓CPU直接對Memory進行讀寫數據。

之前沒有用VS2005編寫過彙編代碼,因此走了點彎路,一直試圖用內嵌彙編的方式來build,可恨的VS2005死活不認ARM指令,後來請出 google大神一搜,原來這條路已經有不少先行者試過了,結論是VS2005不能用內嵌彙編的方式build ARM彙編代碼!windows

俗話說的好啊,機器是死的,人是活的!函數

google大神給我指出了一條通向光明的道路: VS2005中是能夠對純粹的arm彙編文件進行編譯的,固然也能夠將C編譯生成的obj文件和asm彙編文件生成的obj文件進行link。ui

這種混合編譯的方法,網上流傳最廣的一份代碼出自一位叫Larry Bank的老外。this

具體方法:google

一. 建立編譯規則code

<?xml version="1.0" encoding="utf-8"?>
<VisualStudioToolFile Name="Arm ASM" Version="8.00">
   <Rules>
      <CustomBuildRule
         Name="Arm asm" DisplayName="Arm asm"
         CommandLine="armasm -o &quot;$(IntDir)\$(InputName).obj&quot; [$Inputs] "
         Outputs="$(IntDir)\$(InputName).obj"
         FileExtensions="*.asm"
         ExecutionDescription="Executing tool..."
      >
      <Properties></Properties>
      </CustomBuildRule>
   </Rules>
</VisualStudioToolFile>orm

將上面的代碼複製到記事本中,並將其保存到vs2005安裝目錄的Microsoft Visual Studio 8\VC\VCProjectDefaults文件夾下,命名爲armcc.rulesxml

二. 在VS2005中添加編譯規則ip

選擇須要和ARM彙編代碼作混合編譯的Project,右鍵彈出的菜單中選擇"Custom Build Rules...」,在彈出的對話框中點"Find Existing..."按鈕,選擇armcc.rules文件utf-8

三. 編寫ARM彙編代碼,並將其加入VS2005的Project中(以Larry Bank的code爲例)

ARM彙編代碼,文件命名爲armtest.asm:

;      TITLE("Sample App")
;++
        AREA sample, CODE, READONLY ; name this block of code
       
   EXPORT TEST
IMPORT iGlobal
;
; Called from C as int ARMTEST1(int, int, int, int);
; The first 4 parameters are passed in r0-r3, more parameters would be passed on the stack
;
TEST proc
    add r0,r0,r1     ; add all of the inputs together
    add r0,r0,r2
    add r0,r0,r3
    ldr r1,=iGlobal ; get the value of our global variable
    ldr r1,[r1]   ; dereference the pointer (I know there's a pipe stall here)
    add r0,r0,r1 ; we're not concerned with performance in this example
    mov pc,lr     ; return to C with the value in R0   
    endp

    LTORG      ; allow room for the address constant of our global (loaded relative to PC)
    END

將armtest.asm加入VS2005的Project中,編寫調用代碼:

// Windows CE Sample Application

// File Name: MAIN.C
// Demonstrations how to use ARM assembly language within a C program
// Written by Larry Bank 3/25/2007

#include <windows.h>

int iGlobal;

int TEST(int, int, int , int);

/****************************************************************************
*                                                                          *
* FUNCTION   : WinMain(HANDLE, HANDLE, LPSTR, int)                        *
*                                                                          *
* PURPOSE    : Program entrypoint                                         *
*                                                                          *
****************************************************************************/
int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
int iResult;
TCHAR szTemp[256];

   iGlobal = 5;
   iResult = TEST(1,2,3,4);
   wsprintf(szTemp, L"Result = %d", iResult);
   MessageBox(HWND_DESKTOP, szTemp, L"ASM Result", MB_OK);
      
   return 0;

} /* WinMain() */

四. Build VS2005的Project,當你看到以下信息時,恭喜你~~~你成功了!

========= Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

到這裏,可能你們以爲結束了,呵呵,其實才是作了一半!

仔細的朋友可能也發現了,Larry Bank調用armtest.asm中函數的文件MAIN.C在VS2005編譯時調用的是C編譯器,可是如今不少項目工程會以C++代碼編寫(*.cpp),在VS2005中會用C++編譯器Compile。

若是不注意這點的話,就會出現下面的結果:

error LNK2001: unresolved external symbol iGlobal
error LNK2019: unresolved external symbol "int __cdecl TEST1(int,int,int,int)" (?TEST1@@YAHHHHH@Z) referenced in function wmain
fatal error LNK1120: 2 unresolved externals

出現這個問題緣由是:

彙編源文件再編譯之後,函數名稱以及變量名稱沒有作任何的更改,而C++源碼在通過C++編譯器編譯之後,函數名稱和變量名稱都已經有過變化(可查看編譯後的object文件),因此鏈接的時候會報錯。

解決的辦法有下列幾種:

方法一

將彙編中的函數名稱和變量名稱都更改成C++編譯器編譯過的函數名稱和變量名稱,即?TEST1@@YAHHHHH@Z?iGlobal@@3HA。注意這種方式在名稱前面要加上「|」符號。

;      TITLE("Sample App")
;++
        AREA armtest, CODE, READONLY ; name this block of code

    IMPORT |?iGlobal@@3HA|
    EXPORT |?TEST1@@YAHHHHH@Z|
;
; Called from C as int ARMTEST1(int, int, int, int);
; The first 4 parameters are passed in r0-r3, more parameters would be passed on the stack
;
|?TEST1@@YAHHHHH@Z| proc
    add r0,r0,r1     ; add all of the inputs together
    add r0,r0,r2
    add r0,r0,r3
    ldr r1,=iGlobal;|?iGlobal@@3HA| ; get the value of our global variable
    ldr r1,[r1]   ; dereference the pointer (I know there's a pipe stall here)
    add r0,r0,r1 ; we're not concerned with performance in this example
    mov pc,lr     ; return to C with the value in R0   
    endp

    LTORG      ; allow room for the address constant of our global (loaded relative to PC)
    END

方法二

在C++源程序中聲明變量和函數的時候用extern "C"修飾,直接告訴編譯器這是C函數。

extern "C"
{

     int iGlobal;      int TEST1(int, int, int , int); }

相關文章
相關標籤/搜索