ARM GCC的内联汇编详解 (ARM GCC Inline Assembler Cookbook)

本文详细介绍了如何在 ARM 平台上使用 GCC 的内联汇编,包括 GCC 的 `asm` 语句、C 代码优化、输入输出操作数、常见问题和陷阱。内容涵盖基本和扩展内联汇编的使用,以及与 C 语言表达式的交互。通过实例展示了如何在内联汇编中处理变量和函数,以及如何避免常见问题,适合熟悉 ARM 汇编的开发者参考。
摘要由CSDN通过智能技术生成

 

说明:

 在linux内核源码中,定义了一个__asm__的宏,其定义为:

       #define __asm__ asm

 另外有一个经常和 __asm__一起被用到的宏 __volatile__ 定义如下:

      #define __volatile__ volatile

   下面的文章中是直接用 asm ,但是,我们在linux的源码中看到的大部分都是 __asm__ 。其实他们是等价的。只是视觉上的效果不一样而已。

 

本文前面一大段都是英文,中间有中文注解。对英文不感兴趣的,请直接跳到本文中间部分

 

ARM GCC Inline Assembler Cookbook

About this document

The GNU C compiler for ARM RISC processors offers, to embed assembly language code into C programs. This cool feature may be used for manually optimizing time critical parts of the software or to use specific processor instruction, which are not available in the C language.

It's assumed, that you are familiar with writing ARM assembler programs, because this is not an ARM assembler programming tutorial. It's not a C language tutorial either.

All samples had been tested with GCC version 4, but most of them should work with earlier versions too.

GCC asm statement

Let's start with a simple example. The following statement may be included in your code like any other C statement.

/* NOP example */
asm("mov r0,r0");

It moves the contents of register r0 to register r0. In other words, it doesn't do much more than nothing. It is also known as a NOP (no operation) statement and is typically used for very short delays.

Stop! Before adding this example right away to your C code, keep on reading and learn, why this may not work as expected.

With inline assembly you can use the same assembler instruction mnemonics as you'd use for writing pure ARM assembly code. And you can write more than one assembler instruction in a single inline asm statement. To make it more readable, you can put each instruction on a separate line.

asm(
"mov     r0, r0\n\t"
"mov     r0, r0\n\t"
"mov     r0, r0\n\t"
"mov     r0, r0"
);

The special sequence of linefeed and tab characters will keep the assembler listing looking nice. It may seem a bit odd for the first time, but that's the way the compiler creates its own assembler code while compiling C statements.

So far, the assembler instructions are much the same as they'd appear in pure assembly language programs. However, registers and constants are specified in a different way, if they refer to C expressions. The general form of an inline assembler statement is

asm(code : output operand list : input operand list : clobber list);

The connection between assembly language and C operands is provided by an optional second and third part of theasm statement, the list of output and input operands. We will explain the third optional part, the list of clobbers, later.

The next example of rotating bits passes C variables to assembly language. It takes the value of one integer variable, right rotates the bits by one and stores the result in a second integer variable.

/* Rotating bits example */
asm("mov %[result], %[value], ror #1" : [result] "=r" (y) : [value] "r" (x));

Each asm statement is divided by colons into up to four parts:

  1. The assembler instructions, defined in a single string literal:
    "mov %[result], %[value], ror #1"
  2. An optional list of output operands, separated by commas. Each entry consists of a symbolic name enclosed in square brackets, followed by a constraint string, followed by a C expression enclosed in parentheses. Our example uses just one entry:
    [result] "=r" (y)
  3. A comma separated list of input operands, which uses the same syntax as the list of output operands. Again, this is optional and our example uses one operand only:
    [value] "r" (x)
  4. Optional list of clobbered registers, omitted in our example.

As shown in the initial NOP example, trailing parts of the asm statement may be omitted, if unused. Inline asm statements containing assembler instruction only are also known as basic inline assembly, while statements containing optional parts are called extended inline assembly. If an unused part is followed by one which is used, it must be left empty. The following example sets the current program status register of the ARM CPU. It uses an input, but no output operand.

asm("msr cpsr,%[ps]" : : [ps]"r"(status));

Even the code part may be left empty, though an empty string is required. The next statement creates a special clobber to tell the compiler, that memory contents may have changed. Again, the clobber list will be explained later, when we take a look to code optimization.

asm("":::"memory");

You can insert spaces, newlines and even C comments to increase readability.

asm("mov    %[result], %[value], ror #1"

           : [result]"=r" (y) /* Rotation result. */
           : [value]"r"   (x) /* Rotated value. */
           : /* No clobbers */
    );

In the code section, operands are referenced by a percent sign followed by the related symbolic name enclosed in square brackets. It refers to the entry in one of the operand lists that contains the same symbolic name. From the rotating bits example:

%[result] refers to output operand, the C variable y, and

             %[result]  对应输出操作数,对应C变量 y
%[value] refers to the input operand, the C variable x.

               %[value]  对应输入操作数,对应C变量 x

Symbolic operand names use a separate name space. That means, that there is no relation to any other symbol table. To put it simple: You can choose a name without taking care whether the same name already exists in your C code. However, unique symbols must be used within each asm statement.

符号名(Symbolic operand names)使用一个独立的命名空间(name space.)。这意味着,它与任何其他的符号表(symbol table)没有关系。可以让他更简单:你选择一个名字,而完全不用在意这个名字是否与c代码中的其他名字重名。然而,每个内联汇编段中的名字必须是唯一的。

If you already looked to some working inline assembler statements written by other authors, you may have noticed a significant difference. In fact, the GCC compiler supports symbolic names since version 3.1. For earlier releases the rotating bit example must be written as

如果你已经看到了一些其他作者写的汇编语句,你可能已经注意到 输入输出代号的不同。即 %[result] --> %0   %[value] --> %1 这样的差别。 实际上,gcc 编译器自从3.1版本就开始支持符号名(symbolic names),即%[result]这样的写法。对于早期发布的版本,对于这个移位操作的例子,必须按照如下的方式书写(即使用%0这样的风格):

asm("mov %0, %1, ror #1" : "=r" (result) : "r" (value));

Operands are referenced by a percent sign followed by

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值