VS2005混合编译ARM汇编代码

公司HW team有人希望可以给他们写一个在WinCE上,单独读写DDR的工具,以方便他们量测Memory读写时的硬件信号。

在开发过程中,发现简单的在Storage Memory区域拷贝或粘贴文件不能达到硬件量测的要求,需要直接通过编写ARM汇编指令让CPU直接对Memory进行读写数据。

 

以前没有用VS2005编写过汇编代码,所以走了点弯路,一直试图用内嵌汇编的方式来build,可恨的VS2005死活不认ARM指令,后来请出google大神一搜,原来这条路已经有很多先行者试过了,结论是VS2005不能用内嵌汇编的方式build ARM汇编代码!

 

俗话说的好啊,机器是死的,人是活的!

google大神给我指出了一条通向光明的道路: VS2005中是可以对纯粹的arm汇编文件进行编译的,当然也可以将C编译生成的obj文件和asm汇编文件生成的obj文件进行link。

 

这种混合编译的方法,网上流传最广的一份代码出自一位叫Larry Bank的老外。

 

具体方法:

一. 创建编译规则

<?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>

将上面的代码复制到记事本中,并将其保存到vs2005安装目录的Microsoft Visual Studio 8/VC/VCProjectDefaults文件夹下,命名为armcc.rules

 

二. 在VS2005中添加编译规则

选择需要和ARM汇编代码做混合编译的Project,右键弹出的菜单中选择"Custom Build Rules...”,在弹出的对话框中点"Find Existing..."按钮,选择armcc.rules文件

 

三. 编写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);
}

混合编译 ARM 汇编

分享到:
评论加载中,请稍后...
创APP如搭积木 - 创意无限,梦想即时!
回到顶部