打印

请教在 汇编中 调用 C问题

[复制链接]
4107|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
itelectron|  楼主 | 2009-8-26 22:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
itelectron|  楼主 | 2009-8-26 22:31 | 只看该作者
移植UBOOT  中 参照 VIVI  准备用NAND  启动!!!!
ARM  汇编 很菜 要不然 直接用 汇编写 了.

使用特权

评论回复
板凳
itelectron|  楼主 | 2009-8-27 16:21 | 只看该作者
最佳答案用汇编调用C函数,比较简单一点。
把C程序编译成obj。

在汇编语言调用C函数之前,这样声明一下:
extrn XXXX:far(其中XXXX是C写的函数,依据实际情况,可能要加一个前导下划线,写成_XXXX:far)

然后call就可以了,很好用
链接时和C的obj一起链接

很简单的,你不妨试试

使用特权

评论回复
地板
itelectron|  楼主 | 2009-8-27 16:23 | 只看该作者
好文转http://hengch.blog.163.com/blog/static/10780067200922411010890/http://hengch.blog.163.com/blog/static/10780067200922411010890/


从汇编调用C程序

杂七杂八   2009-03-24 13:10   阅读468   评论1   字号: 大大  中中  小小     最近有台湾的网友写EMAIL给我说从汇编语言调用C程序的时候遇到了一些麻烦,我想了一下,确实,可能介绍C程序调用汇编程序的**相对要多一些,而反过来的情况可能用到的人不多,所以决定以此为题写一个短篇。

    首先,如果想从MASM编译的汇编程序调用DJGPP的GCC编译的C程序,这个可能性不大,两个编译出的差异恐怕太大了,本文使用MASM 6.11和TURBO C 3.0作为例子,完成一个从汇编调用C的小范例,这样的调用比较靠谱。

    使用过TURBO C的人都知道,TC把编译出来的程序结构分成6种模式:Tiny、Small、Medium、Compact、Large和Huge,不管是汇编调C还是C调用汇编,都首先要搞清楚使用什么模式,必须要保证汇编编译出的模式和TC编译出的模式一致,否则调用是要出问题;其次要搞清楚参数调用规则,比如f(a,b),a、b这两个参数是如何传到C程序中f函数下的,解决了这两个问题,剩下的就是如何链接的问题了。

    先说第一个问题,TC中的编译模式。

    汇编程序的大致模式是这样的:

    <code>      segment      byte public 'code'
                assume       cs:<code>, ds:<dseg>
                <------------代码段------------------------------------->
    <code>      ends

    <dseg>      group        _data, _bss
    <data>      segment      word public 'data'
                <------------初始化的数据段---------------------------->
    <data>      ends

    _bss        segment      word public 'bss'
                <------------未初始化的数据段-------------------------->
    _bss        ends

                end

    这些段在TC下各种模式的对应名称如下:

    存储模式        在TC下的名称
    --------------------------------------------------------------------------
    Tiny, Small     <code> = _TEXT    <data> = _DATA    <dseg> = DGROUP
    Compact         <code> = _TEXT    <data> = _DATA    <dseg> = DGROUP
    Medium          <code> = _TEXT    <data> = _DATA    <dseg> = DGROUP
    Large           <code> = filename_TEXT    <data> = _DATA    <dseg> = DGROUP
    Huge            <code> = filename_TEXT
                    <data> = filename_DATA
                    <dseg> = filename_DATA

    所以在编写汇编程序时,一定要使用TC中的名称来确定各个段,否则无法链接到一起

    第二个问题,参数的传递,TC使用所谓的“C协议”来传递参数,即:将要传递的参数的值,按照逆序(从右向左)压入堆栈,后接返回地址。

    比如函数f(a,b),为一个近(near)调用,a和b均为整数(int),调用f后,堆栈中的内容依次为:返回地址、a和b,所以当我们在汇编中使用call f时,要先运行push b和push a两条指令,否则,必然出现混乱。

    下面我们实现一个范例。

    程序实现了2 + 6 = 8的计算,汇编语言中,向C程序中的函数add_c传递两个参数:a和b,在C程序中完成运算并返回结果给汇编程序。使用Small模式进行编译,下面是汇编部分的程序:

    文件名:test.asm

    DGROUP      GROUP   _DATA
                ASSUME  CS:_TEXT, DS:DGROUP, SS:DGROUP
    EXTERN      _add_c:near
    _DATA       SEGMENT WORD PUBLIC 'DATA'
                PUBLIC  _a
    _a          dw      02h                 ; int a=2
                PUBLIC  _b
    _b          dw      06h                 ; int b=6
                PUBLIC  _c
    _c          dw      00h                 ; int c=0
    _DATA       ENDS

    _TEXT       SEGMENT BYTE PUBLIC 'CODE'
                PUBLIC  _main
    _main       proc    near
                push    bp
                mov     bp, sp
                push    _b
                push    _a
                call    _add_c
                add     sp, 4
                mov     _c, ax
                mov     sp, bp
                pop     bp
                ret
    _main       endp
    _TEXT       ENDS
                END

    其中的_main是对应C语言里的main()函数,这样和C程序链接到一起时才有启动位置(后面可以看到,我们要使用TC下的启动代码)。

    下面是C程序。

    文件名:add_c.c

    add_c(int x, int y) {
      printf("in the add_c(x, y); \n");
      printf("x = %d\n", x);
      printf("y = %d\n", y);
      printf("%d + %d = %d\n", x, y, x + y);
      return(x + y);
    }

    这段程序实在没有什么好解释的。

    下面我们要编译这两个程序,汇编程序的编译没有什么特别的,使用masm编译即可。

    C程序其实也没什么特别的,只是要注意设成Small模式即可,只编译不要链接。

    下面我们来把这两个编译好的OBJ文件链接到一起。

    tlink \tc\lib\c0s.obj test add_c, test, test, \tc\lib\emu \tc\lib\cs

    这个是我们前面提到的要解决的三个问题的最后一个,我们来解释一下:

    tlink:TC下的链接程序
    \tc\lib\c0s.obj:TC的Small模式下的启动代码,如果在TC下编译会自动加进来,如果你的TURBO C不是存放在\tc目录下,请使用正确的路径。

    test add_c:指两个已经编译好的OBJ文件test.obj和add_c.obj
    test:链接好后的EXE文件为test.exe
    test:声称的MAP文件为test.map

    \tc\lib\emu \tc\lib\cs:是我们这个程序需要的TC下的库函数,这两个库在\tc\lib目录下可以找到。

    执行结果:



    希望此文能给**开头提到的那位台湾朋友一些帮助。

使用特权

评论回复
5
itelectron|  楼主 | 2009-8-27 16:30 | 只看该作者
4. 在汇编中调用C的函数

       在汇编中调用C的函数,需要在汇编中IMPORT 对应的C函数名,然后将C的代码放在一个独立的C文件中进行编译,剩下的工作由连接器来处理。

;the details of parameters transfer comes from ATPCS

;if there are more than 4 args, stack will be used

EXPORT asmfile

AREA asmfile, CODE, READONLY

IMPORT cFun

ENTRY

mov r0, #11

mov r1, #22

mov r2, #33

BL cFun

END

/*C file, called by asmfile */

int cFun(int a, int b, int c)

{

return a + b + c;

}

  在汇编中调用C的函数,参数的传递也是通过ATPCS来实现的。需要指出的是当函数的参数个数大于4时,要借助stack,具体见ATPCS规范。

使用特权

评论回复
6
itelectron|  楼主 | 2009-8-27 16:40 | 只看该作者
7
itelectron|  楼主 | 2009-8-27 16:41 | 只看该作者
汇编程序调用C程序
o      汇编程序的设置要遵循ATPCS 规则,保证程序调用时参数的正确传递.
o      在汇编程序中使用IMPORT 伪指令声明将要调用的C 程序函数.
o      在调用C 程序时,要正确设置入口参数,然后使用BL 调用.
o      汇编调用C 程序的C 函数:
  int sum5(int a,lit b, int c,int d,int e)
{
  return(a+b+c+d+e); //返回5 个变量的和
}
o      汇编调用C 程序的汇编程序
       AREA  sample, CODE,READONLY
       IMPORT sum5      ;声明外部标号sum5,即C 函数sum5()
CALLSUM
       STMFD SP!  {LR} ;LR 寄存器放栈
       ADD R1,R0,R0     ;设置sum5 函数入口参数,R0 为参数a
       ADD R2,R1,R0     ;R1 为参数b,R2 为参数c
       ADD R3,R1,R2,
       STR R3,[SP,# -4]!   ;参数e 要通过堆栈传递
       ADD R3,R1,R1        ;R3 为参数d
       BL sum5                ;调用sum5(),结果保存在R0
       ADD SP,SP#4         ;修正SP 指针
       LDMFD SP,PC          ;子程序返回
     
      END

使用特权

评论回复
8
barryyan| | 2009-8-27 22:44 | 只看该作者
学习了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:MARK: zhi kan ji shu

274

主题

2762

帖子

8

粉丝