繁体   English   中英

编写ARM机器指令并从C执行它们(在Raspberry pi上)

[英]Writing ARM machine instructions and executing them from C (On the Raspberry pi)

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

有一些我不确定的事情:

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

我也试了一个例子

#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的寄存器)

blogs.arm.com上阅读缓存和自我修改代码 文章也包含了一个例子,它描述了你所描述的内容。

从文章中回答你的问题

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

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

有关如何使缓存无效,请参阅__clear_cache

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

有几个问题。

  1. 您不会刷新D-Cache和I-Cache,因此大多数时候I-Cache将从L2获取过时数据。 在linux下有一个libc / sys-call为你做这件事。 使用__clear_cache(开始,结束)或_ builtin _clear_cache(开始,结束)。
  2. 您输出Thumb-Code,但是您没有注意如何调用代码。 解决这个问题的最简单方法是使用一些asm-code来执行实际的blx调用,并使用1来设置地址,因为这个位设置处理器运行的模式。因为你的malloc地址总是与一个对齐单词边界,让你在arm模式下调用thumb-code。

好的,所以这适用于我的覆盆子Pi。

#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);}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM