簡體   English   中英

具有intel x86-32位匯編的gcc:訪問C函數參數

[英]gcc with intel x86-32 bit assembly : accessing C function arguments

我正在執行操作系統實施工作。
下面是代碼:

//generate software interrupt
void generate_interrupt(int n) {

    asm("mov al, byte ptr [n]");
    asm("mov byte ptr [genint+1], al");
    asm("jmp genint");
    asm("genint:");
    asm("int 0"); 
}

我在gcc中使用-masm=intel選項編譯以上代碼。 另外,這不是生成軟件中斷的完整代碼。

我的問題是我收到n undefined錯誤,我該如何解決,請幫忙?

另外它在鏈接時提示錯誤而不是在編譯時提示錯誤,下面是一個圖像 在此處輸入圖片說明

使用GCC時,即使使用Intel匯編語法,也必須使用GCC樣式的擴展asm來訪問用C聲明的變量。 直接將C變量名稱寫入程序集插入的功能是MSVC的一項功能,GCC不會復制該功能。

對於這樣的結構,使用單個裝配體插入件(而不是連續多個插入件)也很重要。 GCC可以並且將相對於周圍的代碼,包括相對於其他程序集插入,重新排列程序集插入,除非您采取特定步驟阻止它。

這種特殊的結構應該寫成

void generate_interrupt(unsigned char n)
{
    asm ("mov byte ptr [1f+1], %0\n\t"
         "jmp 1f\n"
         "1:\n\t"
         "int 0"
         : /* no outputs */ : "r" (n));
}

請注意,我已經刪除了初始mov和所有涉及到A寄存器的要求,而是告訴GCC使用"r"輸入約束將n加載到任何方便的寄存器中。 最好在程序集插入中做的盡可能少,並且將寄存器的選擇留給編譯器。

我還將n的類型更改為unsigned char以匹配INT指令的實際要求,並且我使用的是1f 局部標簽語法,因此,如果將generate_interrupt用作內聯函數,則此語法可以正常工作。

說了這么多,我懇請您找到不涉及自修改代碼的操作系統實現策略。 好吧,除非您打算從自我修改中獲得更多使用 ,否則。

這不是您有關將參數傳遞給內聯匯編的特定問題的答案(請參閱@zwol的答案)。 對於該特定任務,這不必要地使用了自我修改代碼。


如果在編譯時知道中斷號,則使用宏方法

使用自修改代碼的另一種方法是創建一個C宏,該宏生成所需的特定中斷。 一種技巧是您需要一個將數字轉換為字符串的宏。 字符串化宏非常常見,並在GCC文檔中進行了記錄

您可以創建一個看起來像這樣的宏GENERATE_INTERRUPT

#define STRINGIZE_INTERNAL(s) #s
#define STRINGIZE(s) STRINGIZE_INTERNAL(s)

#define GENERATE_INTERRUPT(n) asm ("int " STRINGIZE(n));

STRINGIZE將采用數字值並將其轉換為字符串。 GENERATE_INTERRUPT只是獲取數字,將其轉換為字符串,然后將其附加到INT指令的末尾。

您可以這樣使用它:

GENERATE_INTERRUPT(0);
GENERATE_INTERRUPT(3);
GENERATE_INTERRUPT(255);

生成的指令應類似於:

int    0x0
int3
int    0xff

如果僅在運行時知道中斷號,則使用跳轉表方法

如果您需要調用僅在運行時才知道的中斷,則可以創建一張中斷調用表(使用int指令),然后創建一個ret 然后, generate_interrupt會簡單地從堆棧中檢索中斷號,計算表中可以找到特定int的位置並jmp到該位置。

在下面的代碼中,我得到GNU匯編器以生成256個中斷調用的表,每個中斷調用后都使用.rept指令進行ret 每個代碼片段可容納4個字節。 結果代碼生成和generate_interrupt函數如下所示:

/* We use GNU assembly to create a table of interrupt calls followed by a ret
 * using the .rept directive. 256 entries (0 to 255) are generated.
 * generate_interrupt is a simple function that takes the interrupt number
 * as a parameter, computes the offset in the interrupt table and jumps to it.
 * The specific interrupted needed will be called followed by a RET to return
 * back from the function */

extern void generate_interrupt(unsigned char int_no);
asm (".pushsection .text\n\t"

     /* Generate the table of interrupt calls */
     ".align 4\n"
     "int_jmp_table:\n\t"
     "intno=0\n\t"
     ".rept 256\n\t"
         "\tint intno\n\t"
         "\tret\n\t"
         "\t.align 4\n\t"
         "\tintno=intno+1\n\t"
     ".endr\n\t"

     /* generate_interrupt function */
     ".global generate_interrupt\n"  /* Give this function global visibility */
     "generate_interrupt:\n\t"
#ifdef __x86_64__
     "movzx edi, dil\n\t"              /* Zero extend int_no (in DIL) across RDI */
     "lea rax, int_jmp_table[rip]\n\t" /* Get base of interrupt jmp table */
     "lea rax, [rax+rdi*4]\n\t"        /* Add table base to offset = jmp address */
     "jmp rax\n\t"                     /* Do sepcified interrupt */
#else
     "movzx eax, byte ptr 4[esp]\n\t"    /* Get Zero extend int_no (arg1 on stack) */
     "lea eax, int_jmp_table[eax*4]\n\t" /* Compute jump address */
     "jmp eax\n\t"                       /* Do specified interrupt */
#endif
     ".popsection");

int main()
{
    generate_interrupt (0);
    generate_interrupt (3);
    generate_interrupt (255);
}

如果要查看目標文件中生成的代碼,您會發現中斷調用表( int_jmp_table )類似於以下內容:

00000000 <int_jmp_table>:
   0:   cd 00                   int    0x0
   2:   c3                      ret
   3:   90                      nop
   4:   cd 01                   int    0x1
   6:   c3                      ret
   7:   90                      nop
   8:   cd 02                   int    0x2
   a:   c3                      ret
   b:   90                      nop
   c:   cc                      int3
   d:   c3                      ret
   e:   66 90                   xchg   ax,ax
  10:   cd 04                   int    0x4
  12:   c3                      ret
  13:   90                      nop

  ...
  [snip]

因為我使用.align 4每個條目都被填充為4個字節。 這使jmp的地址計算更加容易。

暫無
暫無

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

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