簡體   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