【问题标题】:This assembly code makes nothing这个汇编代码什么也没做
【发布时间】:2014-04-01 09:59:19
【问题描述】:

我正在处理一个 C 文件,它是这样的:

    #define v2      0x560000a0
    int main(void)
    {
        long int v1;
        v1 = ioread32(v2);
        return 0;
    }

我已经提取了这部分以将其写在汇编中:

int main ()
{
    extern v1,v2;
    v1=ioread32(v2);
    return 0;
}

我正在尝试使用 armv4 的汇编代码在 v1 中写入 v2 的值。使用

arm-linux-gnueabi-gcc -S -march=armv4 assembly_file.c

我得到这个代码:

.arch armv4
.eabi_attribute 27, 3
.fpu vfpv3-d16
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 34, 0
.eabi_attribute 18, 4
.file   "txind-rsi.c"
.text
.align  2
.global main
.type   main, %function

main:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
stmfd   sp!, {fp, lr}
add fp, sp, #4
ldr r3, .L2
ldr r3, [r3, #0]
mov r0, r3
bl  ioread32
mov r2, r0
ldr r3, .L2+4
str r2, [r3, #0]
mov r3, #0
mov r0, r3
sub sp, fp, #4
ldmfd   sp!, {fp, lr}
bx  lr

.L3:
.align  2

.L2:
.word   v1
.word   v2
.size   main, .-main
.ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section    .note.GNU-stack,"",%progbits

我使用该代码以这种方式将其放回 C 文件中:

asm volatile(
    "stmfd  sp!, {fp, lr}\n"
    "add    fp, sp, #4\n"
    "ldr    r3, =v1\n"
    "ldr    r3, [r3, #0]\n"
    "mov    r0, r2\n"
    "ldr    r3, =v2\n"
    "str    r2, [r3, #0]\n"
    "sub    sp, fp, #4\n"
    "ldmfd  sp!, {fp, lr}\n"
    "bx lr"
);

代码不做任何事情。

事实上,它会停止目标的工作。 有谁知道为什么?

编辑: 看完你的回答我还有一个问题: 我如何将常量值放入寄存器中? C 中的代码是这样的:

#define v2      0x560000a0
int main(void)
{
    long int value = 0x0000ffff;
    long int v1;
    v1 = ioread32(v2);
    iowrite32(v2,value);
    return 0;
}

我试过了:

asm volatile("mov r3, #value");

我收到一条汇编消息:“值符号在不同的部分”; 我也试过了

asm volatile("mov r3, #0x0000ffff);

并且汇编程序消息是: “修复后的无效常量(ffff)”。读完后:Invalid constant after fixup? 我不知道如何将这个值放入 r3,因为我似乎无法用 mov 来做到这一点。我使用的是 armv4,而不是 armv7。而链接中提出的这个解决方案对我不起作用:

asm volatile("ldr   r3, =#0000ffff\n");

【问题讨论】:

  • 缺少了真正有趣的部分:你开始使用的 C 源代码 (assembly_file.c)...
  • 我已经编辑了我的问题。谢谢
  • ...您仍然缺少最终 C 文件的可编译版本。或者您是否真的将 asm volatile 行单独放入一个 .c 文件中并期望它做任何事情?
  • ...但它不起作用,并且由于缺少信息,我们无法重现您看到的结果。缩短你的代码,直到你有一个最小的例子仍然表现出观察到的行为,然后发布。这是调试 101,真的。 (正如我所说,我不了解 ARM 汇编。但与反汇编相比,您的内联汇编缺少几行是否重要?)
  • asm volatile 语句之前和之后显示 10 行。

标签: c assembly arm


【解决方案1】:

您的代码没有问题,bx lr 是终止 main 的正确方法,那里没有问题。您的代码很可能由于您正在访问的地址而崩溃,它可能不是您被允许访问的地址...

#define v2      0x560000a0
    int main(void)
    {
        long int v1;
        v1 = ioread32(v2);
        return 0;
    }

如果您在 C 编译步骤上进行优化,您会看到一个更干净、更简单的版本

00000000 <main>:
   0:   e92d4008    push    {r3, lr}
   4:   e59f0008    ldr r0, [pc, #8]    ; 14 <main+0x14>
   8:   ebfffffe    bl  0 <ioread32>
   c:   e3a00000    mov r0, #0
  10:   e8bd8008    pop {r3, pc}
  14:   560000a0    strpl   r0, [r0], -r0, lsr #1

这在 asm 中并不难实现。

.globl main
main:
    push {r3,lr}
    ldr r0,=0x560000A0
    bl ioread32
    mov r0,#0
    pop {r3,pc}

组装和拆卸

00000000 <main>:
   0:   e92d4008    push    {r3, lr}
   4:   e59f0008    ldr r0, [pc, #8]    ; 14 <main+0x14>
   8:   ebfffffe    bl  0 <ioread32>
   c:   e3a00000    mov r0, #0
  10:   e8bd8008    pop {r3, pc}
  14:   560000a0    strpl   r0, [r0], -r0, lsr #1

您已经将代码简化到 v1 成为死代码,但函数调用无法优化,所以返回被丢弃。

如果你不使用 main 而是创建一个单独的返回函数

#define v2      0x560000a0
    long int fun(void)
    {
        long int v1;
        v1 = ioread32(v2);
        return v1;
    }

...该死...尾部优化:

00000000 <fun>:
   0:   e59f0000    ldr r0, [pc]    ; 8 <fun+0x8>
   4:   eafffffe    b   0 <ioread32>
   8:   560000a0    strpl   r0, [r0], -r0, lsr #1

哦,好吧。您走在正确的道路上,请查看 C 编译器生成的内容,然后对其进行模仿或修改。我怀疑是你的 ioread 是问题而不是外部结构(为什么你用 32 位读取做一个 64 位的事情,也许这就是问题很长时间它很可能会被实现为 64 位)。

【讨论】:

  • “32 位读取的 64 位事物”是 ioread32(v2),v2 是长整数?事实上,它在主程序中并不是一个长整数。它被定义为一个 u32 变量。很抱歉的改变。我不知道如何进行优化(是 -On 修饰符?)以及组装和反汇编。无论如何,我的新问题是我无法使用 iowrite32 指令写入诸如 0x0000ffff 之类的值。我不能使用 ldr 并且 mov 也不起作用。我已经编辑了消息
  • 你从哪里得到这个硬编码的地址?如果它在操作系统之上运行,你很可能会崩溃......如果不在操作系统上,这变得非常简单,只是一个 ldr,如果 ldr 不适合你,那么问题就不是 ldr。 .
  • 虽然bx lr 是结束函数的正确方法,但它只有在你清理完你在序言中所做的一切后才能正常工作。鉴于在这种情况下编译器会生成序言,您必须将其留作清理工作。您自己的示例说明编译器生成了push {r3, lr}。现在想象一下,如果函数体包含一个包含 bx lr 的 asm 块,则不会从堆栈中清除此推送。
【解决方案2】:

最后的bx lr 会尝试从当前函数返回。你可能不想要那个。我想这也是导致崩溃的原因,因为您不要让编译器撤消它在函数序言中所做的任何设置。

另外,在您的 asm 块中,您不使用任何本地变量,因此您不需要调整堆栈指针,也不需要新的堆栈帧。 mov r0, r2 也被破坏,因为您已将值加载到 r3。如果您只是直接加载到您想要的任何寄存器中,您可以删除mov。此外,在 gcc 内联汇编中,您应该告诉编译器您修改了哪些寄存器。不这样做也可能导致崩溃,因为您可能会覆盖编译器所依赖的值。

不确定在汇编中这样做有什么意义。如果您坚持这样做,以下应该会更好:

asm volatile(
    "ldr    r3, =v1\n"
    "ldr    r2, [r3, #0]\n"
    "ldr    r3, =v2\n"
    "str    r2, [r3, #0]\n" ::: "r2", "r3"
);

【讨论】:

  • 我的 C 代码必须对几个内存位置使用 iowrite32 和 ioread32。我只发布了其中一条说明以简化汇编代码的长度。我猜bx lr指令是为了在我用arm-linux-gnueabi-gcc编译的文件末尾返回0。所以,如果我想从v2指示的内存位置读取一个值并将其存储在v1中,我应该做你写的,不是吗?如果我想在内存位置写入一个值,我只需要将值加载到寄存器中,然后将其写入正确的位置?我在 C 中找不到内联 arm4 asm 代码的好来源
  • 但是你为什么要使用 asm 呢?为什么不只是简单的 C?
  • 因为有人告诉过我。我必须学习在 C 中包含 armv4 汇编代码。我找到的所有信息来源都不是很清楚,也没有可以从中学习的示例。你能推荐一些我可以学习的书或网站吗?
猜你喜欢
  • 1970-01-01
  • 2015-01-14
  • 2022-01-20
  • 2019-02-27
  • 2019-11-01
  • 2013-08-13
  • 1970-01-01
  • 2012-06-29
  • 2016-04-02
相关资源
最近更新 更多