6

我正在尝试用 C 和 ARM 编写一些自我修改的代码。我之前问过一个关于 MIPS 的类似问题,现在正试图将项目移植到 ARM。
我的系统 := 树莓派、ARMv6、GCC 上的 Raspbian

有几件事我不确定:

  • ARM 是否需要 D 缓存回写/I 缓存无效(缓存刷新)?如果是这样,我们该怎么做?

我也尝试了一个例子

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int inc(int x){ //increments x
    uint16_t *ret = malloc(2 * sizeof(uint16_t));

    *(ret + 0) = 0x3001; //add r0 1 := r0 += 1
    *(ret + 1) = 0x4770; //bx lr    := jump back to inc()

    int(*f)(int) = (int (*)(int)) ret;
    return (*f)(x);
}

int main(){
    printf("%d",inc(6)); //expect '7' to be printed
exit(0);}

但我不断收到分段错误。我正在使用 aapcs 调用约定,我已经明白这是所有 ARM 的默认设置

如果有人指出我正确的方向,我将不胜感激

额外的问题(意思是,它实际上不需要回答,但知道会很酷) - 我“来自 MIPS 背景”,ARM 程序员在没有 0 寄存器的情况下怎么做?(例如,硬编码为值 0 的寄存器)

4

3 回答 3

2

阅读上的缓存和自修改代码blogs.arm.com文章还包括一个示例,它可以满足您的描述。

从文章中回答您的问题

... ARM 架构通常被认为是修改后的哈佛架构。...

纯哈佛架构的典型缺点是指令存储器不能从与数据存储器相同的地址空间直接访问,尽管此限制不适用于 ARM。在 ARM 上,您可以将指令写入内存,但由于 D-cache 和 I-cache 不一致,新写入的指令可能会被 I-cache 的现有内容屏蔽,导致处理器执行旧的(或可能无效)说明。

有关如何使缓存无效的信息,请参见__clear_cache 。

如果您打算将指令推送到内存中,我希望您也了解 ARM/Thumb 指令集。

于 2013-04-05T07:13:17.043 回答
2

好的,所以这适用于我的树莓派。

#include <stdio.h>
#include <sys/mman.h>
#include <stdint.h>
#include <stdlib.h>

int inc(int x){ //increments x

    uint32_t *ret = mmap(NULL,
            2 * sizeof(uint32_t),  // Space for 16 instructions. (More than enough.)
            PROT_READ | PROT_WRITE | PROT_EXEC,
            MAP_PRIVATE | MAP_ANONYMOUS,
            -1,0);
    if (ret == MAP_FAILED) {
        printf("Could not mmap a memory buffer with the proper permissions.\n");
        return -1;
    }

    *(ret + 0) = 0xE2800001; //add r0 r0 #1 := r0 += 1
    *(ret + 1) = 0xE12FFF1E; //bx lr        := jump back to inc()

    __clear_cache((char*) ret, (char*) (ret+2));

    int(*f)(int) = (int (*)(int)) ret;
    return (*f)(x);
}

int main(){
    printf("%d\n",inc(6)); //expect '7' to be printed
exit(0);}
于 2013-04-08T17:04:35.203 回答
1

有几个问题。

  1. 您不会刷新 D-Cache 和 I-Cache,因此大多数时候 I-Cache 会从 L2 获取陈旧数据。在 linux 下有一个 libc/sys-call 可以为你做这件事。使用 __clear_cache(begin, end) 或 _ builtin _clear_cache(begin, end)。
  2. 您输出 Thumb-Code,但您不关心如何调用您的代码。解决这个问题的最简单方法是使用一些 asm 代码来执行实际的 blx 调用并将地址与 1 进行或运算,因为该位设置处理器运行的模式。因为你的 malloc 地址将始终与单词边界,让你在 arm 模式下调用 thumb-code。
于 2013-04-04T21:29:11.770 回答