【问题标题】:How can I generate following arm assembler output using ARM gcc 7.3?如何使用 ARM gcc 7.3 生成以下 arm 汇编器输出?
【发布时间】:2018-12-06 21:50:23
【问题描述】:
myfunction:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
mul r3, r0, r0
mov r0, r3
mla r0, r1, r0, r2
bx  lr

我可以使用以下 C 函数生成除 mov 指令之外的所有内容。

int myfunction(int r0, int r1, int r2, int r3)
{
  r3 = r0*r0;
  r0 = r3;
  r3 = r0;
  return (r1*r3)+r2;
}

如何在汇编代码中指示 r3 设置为 r0 的地址?

【问题讨论】:

  • 当您说您“能够生成除 mov 指令之外的所有内容”时,您是在使用 gcc 工具生成汇编程序吗?
  • 你的代码没有意义。 r0=r3 没用,编译器明白这一点。您的汇编代码可以在mla 源代码中只使用r3 而不是r0,从而完全避免mov
  • 获得所需结果的最简单方法是使用内联汇编。通常,编译器的输出无法预测到所选择的确切寄存器和指令。强制编译器发出某些指令的最有效方法是使用内联汇编,其他方法通常是徒劳的。
  • 呼应其他人 - 给定的程序集不是最佳的,因此编译器正在帮您一个忙。如果您不想要编译器的帮助,那么您需要自己完成这项工作。轻松做到这一点的最佳方法是使用内联汇编程序,尽管偶尔内部调用就足够了。
  • @MichaelDorgan: 没有人会打电话给gcc's inline assembler 好用吗?

标签: c assembly arm


【解决方案1】:
unsigned int myfunction(unsigned int a, unsigned int  b, unsigned int c)
{
  return (a*a*b)+c;
}

你的选择会是这样的

00000000 <myfunction>:
   0:   e52db004    push    {r11}       ; (str r11, [sp, #-4]!)
   4:   e28db000    add r11, sp, #0
   8:   e24dd014    sub sp, sp, #20
   c:   e50b0008    str r0, [r11, #-8]
  10:   e50b100c    str r1, [r11, #-12]
  14:   e50b2010    str r2, [r11, #-16]
  18:   e51b3008    ldr r3, [r11, #-8]
  1c:   e51b2008    ldr r2, [r11, #-8]
  20:   e0010392    mul r1, r2, r3
  24:   e51b200c    ldr r2, [r11, #-12]
  28:   e0000291    mul r0, r1, r2
  2c:   e51b3010    ldr r3, [r11, #-16]
  30:   e0803003    add r3, r0, r3
  34:   e1a00003    mov r0, r3
  38:   e28bd000    add sp, r11, #0
  3c:   e49db004    pop {r11}       ; (ldr r11, [sp], #4)
  40:   e12fff1e    bx  lr

或者这个

00000000 <myfunction>:
   0:   e0030090    mul r3, r0, r0
   4:   e0202391    mla r0, r1, r3, r2
   8:   e12fff1e    bx  lr

你可能已经猜到了。

编译器后端永远不应考虑 mov,因为它只会浪费一条指令。 r3 进入 mla 无需将其放入 r0 然后执行 mla。不太确定如何让编译器做更多事情。即使这样也不鼓励它

unsigned int fun ( unsigned int a )
{
    return(a*a);
}
unsigned int myfunction(unsigned int a, unsigned int  b, unsigned int c)
{
  return (fun(a)*b)+c;
}

给予

00000000 <fun>:
   0:   e1a03000    mov r3, r0
   4:   e0000093    mul r0, r3, r0
   8:   e12fff1e    bx  lr

0000000c <myfunction>:
   c:   e0030090    mul r3, r0, r0
  10:   e0202391    mla r0, r1, r3, r2
  14:   e12fff1e    bx  lr

基本上,如果您不进行优化,您将无法达到您所追求的目标。如果你优化那个 mov 不应该在那里,应该很容易优化出来。

虽然编写高级代码以鼓励编译器输出低级代码的某种程度的操作是可能的,但您不应该期望获得这种精确的输出。

除非你使用内联汇编

asm
(
   "mul r3, r0, r0\n"
   "mov r0, r3\n"
   "mla r0, r1, r0, r2\n"
   "bx lr\n"
);

给出你的结果

Disassembly of section .text:

00000000 <.text>:
   0:   e0030090    mul r3, r0, r0
   4:   e1a00003    mov r0, r3
   8:   e0202091    mla r0, r1, r0, r2
   c:   e12fff1e    bx  lr

或真正的asm

mul r3, r0, r0
mov r0, r3
mla r0, r1, r0, r2
bx lr

并将其输入 gcc 而不是 (arm-whatever-gcc so.s -o so.o)

Disassembly of section .text:

00000000 <.text>:
   0:   e0030090    mul r3, r0, r0
   4:   e1a00003    mov r0, r3
   8:   e0202091    mla r0, r1, r0, r2
   c:   e12fff1e    bx  lr

所以从技术上讲,您在命令行上使用 gcc,但 gcc 会进行一些预处理,然后将其提供给 as。

除非您找到一个核心或者 Rd 和 Rs 必须是同一个寄存器,然后可以在 gcc 命令行上指定该核心/错误/任何内容,否则我看不到 mov 发生,也许,只是也许, clang/llvm 将 fun 和 myfunction 分别编译为字节码,然后将它们组合起来,然后优化,然后输出到目标,然后检查它。我希望在优化或输出中 mov 会被优化,但你可能会很幸运。

编辑

我犯了一个错误:

unsigned int myfunction(unsigned int a, unsigned int  b, unsigned int c)
{
  return (a*a*b)+c;
}

arm-linux-gnueabi-gcc --version
arm-linux-gnueabi-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Disassembly of section .text:

00000000 <myfunction>:
   0:   e0030090    mul r3, r0, r0
   4:   e1a00003    mov r0, r3
   8:   e0202091    mla r0, r1, r0, r2
   c:   e12fff1e    bx  lr

但是这个

arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

arm-none-eabi-gcc -O2 -c so.c -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <myfunction>:
   0:   e0030090    mul r3, r0, r0
   4:   e0202391    mla r0, r1, r3, r2
   8:   e12fff1e    bx  lr

我将不得不构建一个 7.3 或去找一个。在 5.x.x 和 8.x.x 之间的某个地方,后端发生了变化或......

请注意,根据编译器内置的默认目标 (cpu/arch),您可能需要在命令行上使用 -mcpu=arm7tdmi 或 -mcpu=arm9tdmi 或 -march=armv4t 或 -march=armv5t。或者你可能会得到这样的东西

Disassembly of section .text:

00000000 <myfunction>:
   0:   fb00 f000   mul.w   r0, r0, r0
   4:   fb01 2000   mla r0, r1, r0, r2
   8:   4770        bx  lr
   a:   bf00        nop

这个

arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

生产

Disassembly of section .text:

00000000 <myfunction>:
   0:   e0030090    mul r3, r0, r0
   4:   e0202391    mla r0, r1, r3, r2
   8:   e12fff1e    bx  lr

因此,您可能必须向后查找它更改的版本,将源代码更改为导致它的 gcc 并修改 7.3.0,使其不是真正的 7.3.0 但报告为 7.3.0 并输出您的想要的代码。

【讨论】:

  • 非常感谢您的快速回复。这真的很有帮助,谢谢!当我使用您通过 -mcpu=arm6 设置提供的功能时,它起作用了。与此同时,我发现了一个不错的编译器资源管理器,它也让我的生活更轻松——仅适用于未来面临这个问题的人——访问godbolt.org
  • 很多人使用 godbolt.org 是的,我没有,这就是为什么我忘记它在那里进行快速测试的原因。再次永远不要假设编译器会做什么,您可以迭代特定的编译器并鼓励它做事,但不要依赖这些事情的发生,不要依赖编译器来生成上述代码的任何一个版本,他们甚至可能不会使用 mla,可能会将其分解为多个指令……您是对的,尽管 Godbolt 是此练习的一个很好的资源。
  • 这对一个简单的问题有很大帮助。干得好。
  • @MichaelDorgan 没有那么多工作,而且很有趣。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 2014-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多