之前沒有用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 "$(IntDir)\$(InputName).obj" [$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); }