包含内联C代码的程序集如何工作?

MDM*_*313 16 c embedded assembly

我已经看到了Arduino和其他硬件的代码,这些硬件具有与C内联的汇编,类似于以下内容:

asm("movl %ecx %eax"); /* moves the contents of ecx to eax */
__asm__("movb %bh (%eax)"); /*moves the byte from bh to the memory pointed by eax */
Run Code Online (Sandbox Code Playgroud)

这实际上是如何工作的?我意识到每个编译器都不同,但是这样做的常见原因是什么,以及如何利用这个?

Sco*_*man 10

内联汇编程序代码直接进入完整的汇编代码,并且不受影响.你这样做的时候,你真的需要绝对的完全控制你的指令序列,或者也许当你不能让一个优化有它与您的代码的方式.也许你需要每一个时钟滴答.也许您需要代码的每个分支都采用完全相同的时钟周期数,并使用NOP来实现这一点.

在任何情况下,有很多理由可能有人想要这样做,但你真的需要知道你在做什么.这些代码块对于编译器来说是非常不透明的,如果你做的不好,你可能不会得到任何警告.

  • 跟进"你真的需要知道你在做什么".请注意,您打算内联的精确汇编行并不总是由编译器完全遵守.我经历过编译器微妙的变化.在编译之后,请务必仔细查看反汇编,以确保它完全符合预期. (2认同)

Roc*_*net 6

通常编译器只会将汇编程序指令插入其生成的汇编程序输出中.它会这样做而不考虑后果.

例如,在此代码中,优化器正在执行复制传播,从而看到y = x,然后z = y.因此它用z = x替换z = y,希望这将允许它执行进一步的优化.但是,它并没有发现我在平均时间内弄乱了x的值.

char x=6;
char y,z;

y=x;                 // y becomes 6

_asm                    
    rrncf x, 1       // x becomes 3. Optimiser doesn't see this happen!
_endasm  

z=y;                 // z should become 6, but actually gets
                     // the value of x, which is 3
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,您实际上可以告诉优化器不要对此变量执行此优化.

volatile char x=6;   // Tell the compiler that this variable could change
                     // all by itself, and any time, and therefore don't
                     // optimise with it.
char y,z;

y=x;                 // y becomes 6

_asm                    
    rrncf x, 1       // x becomes 3. Optimiser doesn't see this happen!
_endasm  

z=y;                 // z correctly gets the value of y, which is 6
Run Code Online (Sandbox Code Playgroud)

  • 将"挥动char y,z;" 防止优化错误? (4认同)

Gil*_*il' 5

从历史上看,C编译器生成汇编代码,然后由汇编程序将其转换为机器代码.内联汇编作为一个简单的特性出现 - 在中间汇编代码中,在那时,注入一些用户选择的代码.一些编译器直接生成机器代码,在这种情况下,它们包含汇编程序或调用外部汇编程序以生成内联汇编代码段的机器代码.

汇编代码最常见的用途是使用编译器无法生成的专用处理器指令.例如,禁用关键部分的中断,控制处理器功能(缓存,MMU,MPU,电源管理,查询CPU功能......),访问协处理器和硬件外围设备(例如inb/ outbx86上的指令)等.您很少会发现asm("movl %ecx %eax"),因为它影响了它周围的C代码也在使用的通用寄存器,但是有类似的东西asm("mcr p15, 0, 0, c7, c10, 5")(ARM上的数据存储器屏障).该OSDev维基与代码片断几个例子.

汇编代码对于实现破坏C的流控制模型的功能也很有用.一个常见的例子是线程之间的上下文切换(无论是协作还是抢占,无论是否在相同的地址空间中),需要汇编代码来保存和恢复寄存器值.

汇编代码对于手动优化代码的小内存或速度也很有用.随着编译器越来越智能化,这在现在的应用程序层面上很少有用,但它在大多数嵌入式领域仍然具有相关性.

将装配与C组合有两种方式:使用内联装配,或通过将装配模块与C模块链接.链接可以说更清晰但并不总是适用:有时你需要在函数中间使用一条指令(例如,在上下文切换中保存寄存器,函数调用会破坏寄存器),或者你不想支付成本一个函数调用.

大多数C编译器都支持内联汇编,但语法各不相同.它通常由关键字引入asm,_asm,__asm__asm__.除了汇编代码本身之外,内联汇编构造还可以包含允许您在汇编和C之间传递值的其他代码(例如,请求将局部变量的值复制到条目上的寄存器),或者声明汇编代码破坏或保留某些寄存器.