簡體   English   中英

使用 GCC 內聯匯編和取立即值的指令

[英]Using GCC inline assembly with instructions that take immediate values

問題

我正在為 ARM Cortex-M3 處理器開發自定義操作系統。 要與我的 kernel 交互,用戶線程必須生成一個 SuperVisor Call (SVC) 指令(以前稱為 SWI,用於軟件中斷)。 ARM ARM中這條指令的定義是:

在此處輸入圖像描述

這意味着該指令需要立即參數,而不是寄存器值。

這讓我很難以可讀的方式構建我的界面。 它需要如下代碼:

asm volatile( "svc #0");

當我更喜歡類似的東西

svc(SVC_YIELD);

但是,我無法構造這個 function,因為 SVC 指令需要立即參數,而當值通過寄存器傳入時我無法提供。

kernel:

作為背景,svc指令在kernel中解碼如下

#define SVC_YIELD   0
// Other SVC codes

// Called by the SVC interrupt handler (not shown)
void handleSVC(char code)
{
  switch (code) {

    case SVC_YIELD:
      svc_yield();
      break;
    // Other cases follow

這個案例陳述很快就失控了,但我看不出解決這個問題的辦法。 歡迎提出任何建議。

我試過的

帶有寄存器參數的 SVC

我最初考慮過

__attribute__((naked)) svc(char code)
{
    asm volatile ("scv r0"); 
}

但這當然不起作用,因為 SVC 需要一個寄存器參數。

蠻力

解決問題的蠻力嘗試如下所示:

void svc(char code)
  switch (code) {
    case 0:
      asm volatile("svc #0");
      break;
    case 1:
      asm volatile("svc #1");
      break;
    /* 253 cases omitted */
    case 255:
      asm volatile("svc #255");
      break;
  }
}

但那有一股難聞的代碼味道。 這當然可以做得更好。

即時生成指令編碼

最后一次嘗試是在 RAM 中生成指令(代碼的 rest 從只讀閃存運行)然后運行它:

void svc(char code)
{
  asm volatile (
      "orr r0, 0xDF00  \n\t" // Bitwise-OR the code with the SVC encoding
      "push {r1, r0}   \n\t" // Store the instruction to RAM (on the stack)
      "mov r0, sp      \n\t" // Copy the stack pointer to an ordinary register
      "add r0, #1      \n\t" // Add 1 to the address to specify THUMB mode
      "bx r0           \n\t" // Branch to newly created instruction
      "pop {r1, r0}    \n\t" // Restore the stack
      "bx lr           \n\t" // Return to caller
      );
}

但這也感覺不對。 此外,它不起作用 - 我在這里做錯了什么; 也許我的指令沒有正確對齊,或者我沒有設置處理器以允許在此位置從 RAM 運行代碼。

我應該怎么辦?

我必須處理最后一個選項。 但是,感覺我應該能夠做類似的事情:

__attribute__((naked)) svc(char code)
{
    asm volatile ("scv %1"
         : /* No outputs */
         : "i" (code)    // Imaginary directive specifying an immediate argument
                         // as opposed to conventional "r"
          ); 
}

但是我在文檔中沒有找到任何這樣的選項,而且我無法解釋如何實現這樣的功能,所以它可能不存在。 我應該怎么做?

您希望使用約束來強制將操作數分配為8位立即數。 對於ARM,這是約束I 所以你要

#define SVC(code) asm volatile ("svc %0" : : "I" (code) )

有關所有constaints的摘要,請參閱GCC文檔 - 您需要查看特定於處理器的注釋以查看特定平台的約束。 在某些情況下,您可能需要查看gcc源代碼中架構的.md (機器描述)文件以獲取完整信息。

還有一些不錯的特定ARM-GCC文檔在這里 在“輸入和輸出操作數”標題下面幾頁,它提供了所有ARM約束的表格

使用宏怎么樣:

#define SVC(i)  asm volatile("svc #"#i)

正如Chris Dodd在關於宏的評論中所指出的那樣,它並不是很有效,但是這樣做:

#define STRINGIFY0(v) #v
#define STRINGIFY(v) STRINGIFY0(v)
#define SVC(i)  asm volatile("svc #" STRINGIFY(i))

但是請注意,如果您將枚舉值傳遞給它,它只會是#defined。

因此,克里斯上面的答案是最好的,因為它使用立即值,這是所需要的,至少是拇指指令。

我的解決方案(“動態生成指令編碼”):

#define INSTR_CODE_SVC      (0xDF00)
#define INSTR_CODE_BX_LR    (0x4770)

void svc_call(uint32_t svc_num)
{
    uint16_t instrs[2];

    instrs[0] = (uint16_t)(INSTR_CODE_SVC | svc_num);
    instrs[1] = (uint16_t)(INSTR_CODE_BX_LR);

    // PC = instrs (or 1 -> thumb mode)
    ((void(*)(void))((uint32_t)instrs | 1))();
}

它的工作原理和它比switch-case變體要好得多,后者需要大約2kb的ROM才能生成256個svc。 這個func不必放在RAM部分,FLASH就可以了。 如果svc_num應該是運行時變量,則可以使用它。

正如在這個問題中所討論的那樣, SVC的操作數是固定的,即預處理器應該知道它,它與立即數據處理操作數不同。

gcc手冊上寫着

'I'-作為數據處理指令中的立即操作數有效的整數。 也就是說,0到255范圍內的整數旋轉2的倍數。

因此,這里使用宏的答案是首選,並且Chris Dodd的答案不能保證可行,具體取決於gcc版本和優化級別。 請參閱另一個問題的討論。

我最近在 Cortex-M 上為我自己的玩具操作系統編寫了一個處理程序。 如果任務使用 PSP 指針,則工作。

思路:獲取被中斷進程的棧指針,獲取進程的棧PC,就會有SVC之后指令的指令地址,查找指令中的立即數。 它並不像聽起來那么難。

uint8_t __attribute__((naked)) get_svc_code(void){
__asm volatile("MSR R0, PSP"); //Get Process Stack Pointer (We're in SVC ISR, so currently MSP in use)
__asm volatile("ADD R0, #24"); //Pointer to stacked process's PC is in R0
__asm volatile("LDR R1, [R0]"); //Instruction Address after SVC is in R1
__asm volatile("SUB R1, R1, #2"); //Subtract 2 bytes from the address of the current instruction. Now R1 contains address of SVC instruction
__asm volatile("LDRB R0, [R1]"); //Load lower byte of 16-bit instruction into R0. It's immediate value.
//Value is in R0. Function can return
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM