分析简单的ARM汇编代码

Mik*_*ke 2 assembly arm

我开始使用GNU工具链研究ARM汇编语言,并使用以下代码在C中创建一个非常简单的函数示例:

#include <stdint.h>

    uint32_t *a;
    uint32_t *b;
    uint32_t *c;

     __attribute__((naked)) void f() {

             *a += *c;
             *b += *c;
       }
Run Code Online (Sandbox Code Playgroud)

在终端中使用此命令后查看汇编代码:

arm-none-eabi-gcc -O1 -S -std=c99 example.c -o -
Run Code Online (Sandbox Code Playgroud)

这就是结果:

    @ Function supports interworking.
    @ Naked Function: prologue and epilogue provided by programmer.
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    ldr r3, .L2
    ldr r2, .L2+4
    ldr r3, [r3]
    ldr r2, [r2] ; r2 <- &(*c)
    ldr ip, [r3]
    ldr r0, [r2] ; r0 <- *c
    ldr r1, .L2+8
    add r0, ip, r0
    str r0, [r3]
    ldr r3, [r1]
    ldr r2, [r2] ; why make the same thing 
    ldr r1, [r3]
    add r2, r1, r2
    str r2, [r3]
.L3:
    .align  2
.L2:
    .word   a
    .word   c
    .word   b
    .size   f, .-f
    .comm   c,4,4
    .comm   b,4,4
    .comm   a,4,4
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么编译器加载指针c的地址的两倍,如果我很清楚,那就是行

ldr  r2, [r2] 
Run Code Online (Sandbox Code Playgroud)

我找不到编译器复制此代码的充分理由.提前致谢.

Car*_*rum 5

如果您的指针别名,则需要两个解引用.想一想你的算法做了什么a == c.如果他们不能使用别名,则需要添加一些restrict关键字.这是一个优化您期望的方式的示例:

#include <stdint.h>

void f(uint32_t * restrict a, uint32_t * restrict b, uint32_t * restrict c)
{
    *a += *c;
    *b += *c;
}
Run Code Online (Sandbox Code Playgroud)

和汇编输出(评论我的):

00000000 <f>:
   0:   e5922000    ldr r2, [r2]     // r2 = *c
   4:   e5903000    ldr r3, [r0]     // r3 = *a
   8:   e0833002    add r3, r3, r2   // r3 = r3 + r2 = *a + *c
   c:   e5803000    str r3, [r0]     // *a = r3 = *a + *c
  10:   e5910000    ldr r0, [r1]     // r0 = *b
  14:   e0800002    add r0, r0, r2   // r0 = r0 + r2 = *b + *c
  18:   e5810000    str r0, [r1]     // *b = r0 = *b + *c
  1c:   e12fff1e    bx  lr
Run Code Online (Sandbox Code Playgroud)

编辑:这是一个更像原始示例的示例,第一个没有restrict关键字,第二个是GCC的输出格式.

示例一(没有restrict关键字)代码:

#include <stdint.h>

__attribute__((naked))
void f(uint32_t *a, uint32_t *b, uint32_t *c)
{
    *a += *c;
    *b += *c;
}
Run Code Online (Sandbox Code Playgroud)

输出:

f:
    ldr ip, [r0, #0]
    ldr r3, [r2, #0]
    add r3, ip, r3
    str r3, [r0, #0]
    ldr r0, [r1, #0]
    ldr r3, [r2, #0]
    add r3, r0, r3
    str r3, [r1, #0]
Run Code Online (Sandbox Code Playgroud)

示例二(带restrict关键字)代码:

#include <stdint.h>

__attribute__((naked))
void f(uint32_t * restrict a, uint32_t * restrict b, uint32_t * restrict c)
{
    *a += *c;
    *b += *c;
}
Run Code Online (Sandbox Code Playgroud)

输出:

f:
    ldr r3, [r2, #0]
    ldr ip, [r1, #0]
    ldr r2, [r0, #0]
    add r2, r2, r3
    add r3, ip, r3
    str r2, [r0, #0]
    str r3, [r1, #0]
Run Code Online (Sandbox Code Playgroud)

第二个解除引用c不在第二个程序中,用一条指令缩短它.