21856|7

66

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

.c文件和.asm文件怎么连接起来? [复制链接]

恩,大家好,
我现在用C编了一段程序,用汇编编了一段程序,我想把它们连接起来运行,请问应该怎么办呢?
我用的是C8051F系列的单片机,Keil Cx51编译器。
看了Cx51的帮助文档,但还是不明白。
不好意思啊,我再看看,也请大家指点。
此帖出自单片机论坛

最新回复

gba
学习了!!mark~~~  详情 回复 发表于 2014-4-30 01:09
点赞 关注
 

回复
举报

229

帖子

0

TA的资源

纯净的硅(初级)

沙发
 
好像有个ASM嵌入c的格式的 我找找
此帖出自单片机论坛
 
 

回复

229

帖子

0

TA的资源

纯净的硅(初级)

板凳
 
我找到了一些资料 希望对你有用
下周就要做实验了,由于听老师说机房位子可能比较少,对我这种蹭课的学生来说也就不敢奢望同选这门课的同学一样能够正常的在机房调试程序了,因此,我决定提前先在自己的工作室里把实验内容给过一遍。第一个实验是关于嵌入式编程的,这个实验目的一方面是为了让我们熟悉ARM下编程的编译环境ADS和调试器ATX,另一方面是让我们掌握如何将c语言和汇编语言在实际编程中相互调用。经过这两天靠自己不断的摸索,终于掌握了如何在编译环境中进行ARM编程,另外,还学会了在c中调用汇编程序的方法,以及如何通过linux自带的gcc编译嵌有汇编的c程序,总之,收获还是蛮多的哦,下面就总结一下吧。

1、c嵌汇编

首先说一下关于GCC编译嵌有汇编语言的c语言吧,GCC编译的汇编语言不是我们上课时学的Intel x86汇编,而是AT&T汇编,两者的区别可以查看《Gcc使用的内嵌汇编语法格式小教程》。

下面是内嵌汇编的几种格式:

语法

__asm__(“instruction

         . ……

            instruction”);   //Linux gcc中支持(注意asm的下划线均为两个否则GCC将会无法编译)



__asm{

       instruction



    instruction

      };       //ADS中支持(注意asm的下划线均为两个否则GCC将会无法编译)



asm(“instruction [; instruction]”);   //ARM C++中使用   



例1是我在linux环境下,编的嵌有汇编程序的c语言,并通过了GCC的编译:

例1:

#include



int plus(int a,int b)

{

__asm__

              (

              “add %1,%0\n\t”:”+r”(a):”r”(b)

              );

return (c);

}



int main()

{int a,b,c;

a=2;

b=1;

c=plus(a,b);

printf(“c=%d\n”,c);

}

这个程序应该是很简单的,但关键是子函数中嵌入的那段汇编程序,具体的写法可以参看其他文章。

例2同样是c语言中嵌入了汇编,与例1不同的是,这个程序的编译环境为ADS。

例2

#include

void  my_strcpy(char* src, const char* dst){

         int ch;

         __asm{

loop:

       LDRB    ch, [src], #1

       STRB   ch, [dst], #1

       CMP      ch, #0

       BNE      loop

        };

}



int main(void){

    const char* a = "Hello World!";

    char   b[20];

    __asm{

       MOV     R0, a

       MOV     R1, b

       BL     my_strcpy, {R0, R1}

    };

    printf("Original String: %s\n",a);

    printf("Copied String: %s\n",b);

    return 0;

}

一定要注意例1与例2中汇编语言的语法格式。

2、C语言调用汇编

再说一下如何将一个c语言文件与一个汇编文件通过ADS环境编译,并通过ATX进行DEBUG调试的。先看一下下面的例3

例3

Cfile.c

#include

extern void strcopy(char *d, const char *s);



int main()

{       const char *srcstr = "abcde";

        char dststr[32];

        /* dststr is an array since we're going to change it */



        printf("Before copying:\n");

        printf("  '%s'\n  '%s'\n",srcstr,dststr);

        strcopy(dststr,srcstr);

        printf("After copying:\n");

        printf("  '%s'\n  '%s'\n",srcstr,dststr);

        return 0;

}



Asmfile.s

AREA    SCopy, CODE, READONLY



        EXPORT strcopy

strcopy                 

        ; r0 points to destination string

        ; r1 points to source string

        LDRB    r2, [r1],#1     ; load byte and update address

        STRB    r2, [r0],#1     ; store byte and update address;

        CMP     r2, #0          ; check for zero terminator

        BNE     strcopy         ; keep going if not

        MOV     pc,lr           ; Return



        END            ;注意!!汇编代码编写时一定要缩进,否则编译将会出错

这是一个c语言调用汇编的例子,功能是为了实现字符串的拷贝,其中汇编文件为字符串拷贝的功能子函数。在这里需要说明的是c语言调用汇编语言的一些基本规则,首先是参数传递的规则,c语言的函数前4个参数通过R0-R3来传递,其它参数通过堆栈(FD)传递,且这种传递是单项的,即汇编语言中的R0-R3的值不会再回传给c语言。拿例3举例来说,当在语言中调用strcopy(dststr,srcstr);时,字符串dststr的首地址将会传给r0,srcstr的首地址将会传给r1,当汇编语言拿到这两个寄存器时,就会通过地址依次加1的形式进行地址内容的复制也就是字符串的复制,当复制到最后一个字母e时,通过比较r2寄存器中的值是否为0来判断是否调出汇编程序(因为在c语言中声明字符串时末尾被自动的添加了一个\0),这里需要注意的是,此时寄存器r0的值为指向源字符串末尾的’\0’的地址值,而寄存器r1的值为指向已经拷贝过的目的字符串中的”e”的地址值,当调出汇编程序时,r0,r1这两个值将不会回传给strcopy(dststr,srcstr);中的两个参数dststr和srcstr,这两个参数的值仍然是c语言在初始化这两个字符串时指向字符串的首地址,这一点可以通过ATX调试时观察寄存器的变化情况来证明。但是为什么地址值没有变化,但却实现了字符串的拷贝了呢?这主要时因为通过汇编程序,虽然没有改变两个指针的位置,但却改变了两个字符串所在内存地址中的内容,这种方式就是c语言中常说的引用方式,即dststr和r0起初指向的是同一内存空间,但是字符串复制时只是利用r0来复制的,而dststr的位置却没有发生变化。因此在c语言中输出字符串时并不需要将dststr减去字符串的个数来实现指向字符串的首地址。

这个程序中第二个需要注意的地方是,汇编程序段中的起到临时存放字符串的r2寄存器,很奇怪的是这个地方的寄存器不能换成r4,如果换成r4的话,输出的结果就会有问题,这一点我现在还没有找到答案,希望将来某一天能遇见高人给我指点一下。

最后需要注意的地方是在汇编程序末尾一定要加上MOV  pc, lr

用ADS编译后,两个文件会被自动的链接,并在工程文件夹下生成一个.o文件,这个文件就是将来要下到开发板上的二进制文件,其中还有一个.axf的镜像文件,这个文件是用来进行ATX调试的,默认的单步调试是在反汇编中进行的,这就会给调试程序带来极大的不便,通过自己的摸索,发现可以通过设置strong source实现在c语言中进行单步调试,两外在单步调试中通过watch来观察c语言中的形参的值和地址的变化情况,便于程序的调试,需要强调的一点时,汇编程序与c程序的文件名不能相同,否则将无法用ATX进行调试。

另外,在汇编程序中访问c程序全局变量的例子。程序中变量globvl是在c程序中声明的全局变量。在汇编程序中首先用IMPORT伪操作声明该变量;再将其内存地址读入到寄存器R1中;再将其值读入到寄存器R0中;修改后再将寄存器R0的值赋于变量globvl。请参看例4

例4

#include

int  globvl;

int main(){

globvl = 0;

    asmsub();

   printf(“globvl = %d”, globvl);

     return 0;

}



AREA  globals, CODE, READONLY

       EXPORT asmsub

       IMPORT globvl

       asmsub

       LDR  r1,  =globvl

       LDR  r0, [r1]

       ADD  r0, r0, #2

       STR  r0, [r1]

       MOV  pc, lr

       END                ;注意!!汇编代码编写时一定要缩进,否则编译将会出错



   

3、汇编调用c

最后我再谈一下如何在汇编中调用c,看一下例5

例5

int g(int a, int b, int c, int d, int e)

{

return a + b + c + d + e;

}



;汇编程序调用c程序g()计算5个整数i, 2*i, 3*i, 4*i, 5*i的和

EXPORT f

AREA  f, CODE, READONLY

IMPORT  g                 ;使用伪操作数IMPORT声明c程序g()

STR  lr, [sp,#-4]!        ;保存返回地址

ADD  r1, r0, r0             ;假设进入程序f时,r0中的值为i,r1值设为2*i

ADD  r2, r1, r0             ;r2的值设为3*i

ADD  r3, r1, r2           ;r3的值设为5*i

STR  r3, [sp, # -4]!     ;第五个参数5*i通过数据栈传递

ADD  r3, r1, r1           ;r4值设为4*i

BL   g          ;调用c程序g()

ADD  sp, sp, #4          ;调整数据栈指针,准备返回

LDR  pc, [sp], #4       ;返回

END                 ;注意!!汇编代码编写时一定要缩进,否则编译将会出错



注意,c语言最终返回的五个数之和放到了r0寄存器中
此帖出自单片机论坛
 
 
 

回复

66

帖子

0

TA的资源

一粒金砂(中级)

4
 

关于在 KEIL C51 中直接嵌入汇编

上网搜索加上看帮助文档,明白了应该进行一些设置。现在的问题是右键单击文件,没有“options for...”选项。再问问有经验的人吧。这里先做个回复。下面这段话来自于google搜索:

1、在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码:
#pragma ASM
; Assembler Code Here
#pragma ENDASM
2、在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRC File”
和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;
3、根据选择的编译模式,把相应的库文件(如 Small 模式时,是 KeilC51LibC51S.Lib)加入工程中, 该文件必须作为工程的最
后文件;
4、编译,即可生成目标代码。
看了许多keil c51中嵌入汇编的帖子,根据自己的经验在keil7.01环境中总结如下:
1、把"xx.c"加入工程中,右击"xx.c"选择“options for file"xx.c" 选择“Generate Assembler SRC File”和“Assemble SRC File”打上黑勾有效;
2、根据选择的编译模式,把相应的库文件象加"xx.c"一样加入工程中并放在"xx.c"下面,如smail模式下选择"keilc51libc51s.lib"加入工程中,如果要进行浮点运算把"keilc51libc51fpl.lib"也加入工程中。
3、在"xx.c"头文件中加入优化:比如#pragma OT(4,speed)
4、在"xx.c"中加入汇编代码#pragma ASM
;Assembler Code Here
#pragma ENDASM
5、编译生成xx.hex
注意:没有做第一步会有如下警告:'asm/endasm' requires src-control to be active
没有做第二步会有如下警告:UNRESOLVED EXTERNAL SYMBOL;
REFERENCE MADE TO UNRESOLVED EXTERNAL等
没有做第三步会有如下警告:UNDEFINED SYMBOL (PASS-2)
此帖出自单片机论坛
 
 
 

回复

6

帖子

0

TA的资源

一粒金砂(中级)

5
 

请教LSJ师傅:附件中KeilC51LibC51S.Lib是从那里来的?

请教LSJ师傅:附件中KeilC51LibC51S.Lib是从那里来的?是否为自己编写的汇编语言源程序文件名?

Snap1.jpg (88.96 KB, 下载次数: 1)

Snap1.jpg
此帖出自单片机论坛
 
 
 

回复

97

帖子

0

TA的资源

五彩晶圆(初级)

6
 

回复 5楼 y_y133 的帖子

恩,很抱歉啊,这个我也不是很懂~~
只是从“C:\SiLabs\MCU\IDEfiles\C51\LIB”路径下找到了C51S.LIB文件,S是Small的意思。
当时查资料,是这样描述的,见上文。
“3、根据选择的编译模式,把相应的库文件(如Small 模式时,是KeilC51LibC51S.Lib)加入工程中, 该文件必须作为工程的最后文件;”
恩,不求甚解的后果~~还是请更明白的人来回答吧。
很抱歉
此帖出自单片机论坛
 
 
 

回复

1583

帖子

0

TA的资源

五彩晶圆(高级)

7
 
调用ASM程序有两种方法:
一是:在程序里直接插入ASM代码:
#pragma asm(以此开始汇编)
在这里输入ASM代码
N行
#pragma endasm(以此结束汇编)

第二种方法是将汇编程序写在一个文件里,然后再从主程序中调用这些使用汇编语言写的子程序.此方法我没用过.没有经验.
此帖出自单片机论坛
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

8
 
学习了!!mark~~~
此帖出自单片机论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表