1.简介
本文介绍在c代码中嵌入汇编语言的方法,所有的方法仅对gcc(Gnu C Compiler)有效。由于作者是在一台pc上进行的实验,所以例子中如果未加说明,所有的汇编代码均为x86汇编。本文的唯一参考资料就是gcc Manual,其中的5.36小节介绍了在c中嵌入汇编的办法。
2.如何在c中嵌入汇编代码
2.1.最简单的情形
在gcc里有一个asm表达式,用于实现嵌入汇编。就像这样
asm("xor %%eax, %%eax");
这个汇编指令的作用是吧eax寄存器清零,你也许注意到这些代码和我们常见的x86汇编代码有些不同,的确,gcc使用的汇编格式是AT&T格式而不是DOS下常见的Intel格式,它们之间主要区别有:AT&T格式的寄存器使用%标志开头,例如Intel格式中的EAX在这里写作%eax;AT&T格式的目的操作数是后一个而不像Intel格式那样是前一个,比如:
asm("movl %%eax, %%ebx");
是将eax寄存器的值移到ebx。另外还有一些区别,比如内存地址的表示方法等等,详情可以参考DJGPP FAQ里的Coverting between Intel ASM syntax and AT&T syntax。
另外还要注意%号在asm表达式里是特殊字符,所以%eax前面要再加一个%号进行转义,这样就成了"%%eax"这样的寄存器表示方法,如果你用的是Sparc之类的cpu,寄存器使用"r1""r5"之类的表达式,就不需要累赘的%号了。
为了比较易读,多行的汇编代码可以写成这样
asm("xor %%eax, %%eax
movl -20(%%ebp), %%ebx
sub %%ebx, %%eax");
不过在最新的gcc-3系列里一个字符串写了一行以上是会引发一个warning的,让人看了不舒服,这样写就不会了:
asm("xor %%eax, %%eax \n\t"
"movl -20(%%ebp), %%ebx \n\t"
"sub %%ebx, %%eax");
\n就是换行,\t是tab对齐,这下明白了吧 :)
2.2.使用c中定义的变量
先给出一个例子:
int foo;
asm("movl %%eax, %0"
: "=g" (foo));
在asm()中,在冒号分隔符后面声明你的变量,括号中是变量名(foo),"=g"表示这是一个作为输出的整型变量,如果变量是作为输入的话,就要放在第二个括号分隔符后面,象这样:
int foo1,foo2;
asm("movl %1, %%eax \n\t"
"movl %%eax, %0"
: "=g" (foo1)
: "g" (foo2));
程序是把foo2的内容赋给foo1。从这个例子可以看到,变量在汇编语言里被引用的时候表示符是该变量在asm()里被声明的位置,foo1在asm()里首先声明,所以是%0,foo2紧接着所以是%1。"g"表示是一个整型,前面有"="号说明这是一个作为输出的变量(也就是被写的),没有"="号就说明是作为输入的变量。别的被支持的类型还有"r"(寄存器变量),"m"(内存变量),"f"(浮点变量)等等,更多的表示可以参考gcc manual 20.7.1 。
2.3.避免寄存器冲突
如果你在汇编中显式的使用寄存器,编译器会注意不会在上下文中造成冲突,但是有一些指令是不会显式的使用寄存器的,例如cpuid这条指令,它运行以后会改变%eax,%ebx,%ecx,%edx的值,但是这些寄存器不会在代码里出现,因此编译器不会为你避开这个冲突,如果你直接调用这个指令,可能就会造成你的代码core dump!一个笨笨的办法是自己保护寄存器,调用cpuid之前先将四个寄存器push到栈里,运行了cpuid之后将值保存,再pop这四个寄存器。当然这样很影响代码的效率。其实解决的办法很简单,在asm()的第三个冒号后面声明那些需要保护的寄存器就可以了,像这样:
asm("cpuid"
:
:
:"%eax","%ebx","%ecx","%edx");
注意在这里一个"%"号就好了,这样编译器就会小心的避开这些寄存器的冲突
分享到:
相关推荐
首先,要在C语言中嵌入汇编代码,可以在C文件中使用特定的编译指令#pragma。具体来说,当需要插入汇编代码时,可以使用#pragma ASM来标识开始,紧接着插入汇编代码段,然后再用#pragma ENDASM来结束汇编代码段。例如...
这部分代码定义了一个函数`shiftR1`,该函数的功能是在C语言中调用汇编代码实现。通过预处理指令`#ifdef`检查是否定义了`ASM`宏,如果定义了,则声明`shiftR1`为内部函数;如果没有定义,则声明为外部函数。这种做法...
这时候,我们可以在C语言中嵌入汇编代码,从而发挥出汇编语言的优势。 在keil中嵌入汇编的方法是使用#pragma asm和#pragma endasm指令来分隔C语言代码和汇编代码。这样,keil编译器就会将汇编代码识别出来,并对其...
然而,有时为了实现特定的硬件操作或者提高性能,我们可能需要在C程序中嵌入汇编语言。本文将深入探讨如何在C程序中嵌入汇编语言,以及这种技术在实际应用中的重要性。 首先,我们需要理解C语言与汇编语言的区别。...
1. **C 语言与汇编语言的结合**:在C语言程序中嵌入汇编代码可以充分利用汇编语言在控制硬件方面的能力,同时保持C语言的高级特性和可读性。 2. **中断服务程序(ISR)的设计**:关键功能实现在外部中断0的中断服务...
| **缺点** | - 在大型应用中效率低 - 代码难以理解 - 难以维护 - 不可移植 | - 对资源使用的控制有限 - 在小型应用中代码体积大且执行速度慢 | #### C语言与汇编代码之间的变量传递 当使用IAR C编译器...
在深入探讨C语言中嵌入ASM汇编代码的示例之前,我们首先应当理解何为C语言与汇编语言,以及两者如何交互。C语言是一种高级编程语言,它提供了丰富的数据类型、控制结构和库函数,使程序员能够高效地编写各种复杂的...
确保在汇编代码中正确设置调用约定,否则可能会导致堆栈错误。 5. **汇编优化** 对于性能敏感的代码段,汇编语言可以提供显著的优化机会。例如,可以直接操作内存和寄存器,避免不必要的函数调用开销,或者利用...
混合编程的方法在 C 语言中嵌入汇编语言有两种:在 C 程序中嵌入汇编指令和在 C 程序中调用汇编子程序模块。在 C 程序中嵌入汇编指令主要用于当 C 语言无法实现对硬件的控制功能时,如修改某个寄存器的值、修改中断...
在C语言中嵌入汇编代码是一种常见的技术手段,用于实现高性能或特定硬件操作。然而,格式上的细微差别可能导致编译错误。本案例展示了如何通过正确处理引号与汇编语句之间的空格来避免编译错误。这对于初学者尤其...
另一种是通过gcc的内嵌汇编语法asm,将汇编代码嵌入到C语言程序中。后者是本文介绍的重点。 内嵌汇编的语法格式基于Intel的汇编语言风格,但也有一些显著的区别。在AT&T格式的汇编语言中,立即操作数前需要加上'$'...
### 如何在KEIL中C语言里嵌入汇编语言 ...通过上述步骤,我们不仅了解了如何在C语言中嵌入汇编代码,还掌握了如何在C程序中调用汇编函数的具体方法。这对于深入理解嵌入式系统的底层操作具有重要意义。
本案例中,我们将会探讨如何在C语言中利用`#pragma`预处理指令来嵌入汇编代码,实现C与汇编的无缝结合。 `#pragma`是C语言中的一个预处理指令,它允许程序员向编译器传递自定义的命令或信息。在某些编译器中,`#...
通过在汇编代码前使用`asm`关键字来指示编译器这部分是汇编代码。例如,下面的C函数`exchange`使用内联汇编交换两个整数`a`和`b`的值: ```c void exchange(int a, int b) { asm("mov ax, a"); asm("mov bx, b"); ...
C语言嵌入汇编介绍。有详细例子以及说明。初学者必备。
- **宏和预处理**:C预处理器的宏在汇编中也可以使用,但需要谨慎处理,避免混淆和错误。 7. **KEIL段重定位** Keil编译器在生成可执行文件时,会根据代码和数据的分布对段进行重定位,确保程序在目标硬件上的...
嵌入汇编允许我们直接在C代码中插入汇编指令,以实现C语言无法直接完成的功能。以下是C语言中嵌入汇编的7种方式的详细解释: 1. **嵌入汇编方式1(宏指令方式)**: 这种方式通常用于定义宏,例如`...
在这个主题中,我们将探讨如何在C语言函数中嵌入ARM汇编代码,以实现字符串的拷贝。 首先,我们要了解ARM汇编的基本语法。ARM汇编是一种低级编程语言,用于编写针对ARM架构处理器的指令。在我们的例子中,`strCopy....
在汇编指令中,逗号(,)用作分隔符。因此如果指令中的C/C++表达式中包含有逗号(,),则该表达式应该被包含在括号中。例如: 其中,(f(),Z)为C/C++表达式 如果在指令中使用物理寄存器,则应该保证...
C语言中嵌入汇编语言[收集].pdf