簡體   English   中英

如何編寫X86_64 _assembler_?

[英]How to write a X86_64 _assembler_?

目標:我想編寫一個X86_64匯編程序。 注意:標記為社區維基

背景:我熟悉C.我以前寫過MIPS匯編。 我寫了一些x86程序集。 但是,我想編寫一個x86_64匯編程序 - 它應該輸出我可以跳轉到並開始執行的機器代碼(就像在JIT中一樣)。

問題是:解決這個問題的最佳方法是什么? 我意識到這個問題看起來有點大。 我想從一個基本的最小集開始:

  • 加載到寄存器
  • 寄存器上的算術運算(只需整數就可以了,不需要亂用FPU)
  • 條件語句

只是一個基本的設置,使圖靈完成。 有人做過嗎? 建議/資源?

像任何其他“編譯器”一樣,匯編程序最好寫成一個詞法分析器,輸入語言語法處理器。

匯編語言通常比常規編譯語言更容易,因為您不需要擔心跨越行邊界的構造,並且格式通常是固定的。

兩年前我為一個(虛構的)CPU編寫了一個匯編程序用於教育目的,它基本上將每一行視為:

  • 可選標簽(例如:loop )。
  • 操作(例如, mov )。
  • 操作數(例如, ax,$1 )。

最簡單的方法是確保令牌易於區分。

這就是為什么我制定了標簽必須開始的規則: - 它使得對線的分析變得更加容易。 處理生產線的過程是:

  • 剝離注釋(第一個;在字符串外面到行尾)。
  • 提取標簽(如果存在)
  • 第一個字就是操作。
  • 休息是操作數。

您可以輕松地堅持不同的操作數也有特殊的標記,讓您的生活更輕松。 所有這一切都假設您可以控制輸入格式。 如果您需要使用英特爾或AT&T格式,那就更難了。

我接近它的方式是有一個簡單的每個操作函數被調用(例如, doJmpdoCalldoRet ),並且該函數決定了操作數中允許的內容。

例如, doCall只允許數字或標簽, doRet不允許任何內容。

例如,這是來自encInstr函數的代碼段:

private static MultiRet encInstr(
    boolean ignoreVars,
    String opcode,
    String operands)
{
    if (opcode.length() == 0) return hlprNone(ignoreVars);
    if (opcode.equals("defb"))  return hlprByte(ignoreVars,operands);
    if (opcode.equals("defbr")) return hlprByteR(ignoreVars,operands);
    if (opcode.equals("defs"))  return hlprString(ignoreVars,operands);
    if (opcode.equals("defw"))  return hlprWord(ignoreVars,operands);
    if (opcode.equals("defwr")) return hlprWordR(ignoreVars,operands);
    if (opcode.equals("equ"))   return hlprNone(ignoreVars);
    if (opcode.equals("org"))   return hlprNone(ignoreVars);

    if (opcode.equals("adc"))   return hlprTwoReg(ignoreVars,0x0a,operands);
    if (opcode.equals("add"))   return hlprTwoReg(ignoreVars,0x09,operands);
    if (opcode.equals("and"))   return hlprTwoReg(ignoreVars,0x0d,operands);

hlpr...函數只是獲取操作數並返回包含指令的字節數組。 當許多操作具有類似的操作數要求時,它們很有用,例如adc , add and `在上述情況下都需要兩個寄存器操作數(第二個參數控制了為指令返回的操作碼)。

通過使操作數的類型易於區分,您可以檢查提供的操作數,它們是否合法以及要生成哪些字節序列。 將操作分離為它們自己的函數提供了一個很好的邏輯結構。

此外,大多數CPU遵循從操作碼到操作的合理邏輯轉換(以使芯片設計者更容易生活),因此在所有允許例如索引尋址的操作碼上將進行非常類似的計算。

為了在允許可變長度指令的CPU中正確創建代碼,您最好在兩次通過中執行此操作。

在第一遍中,不生成代碼,只生成指令長度。 這允許您在遇到所有標簽時為其分配值。 第二遍將生成代碼,並且可以填充對這些標簽的引用,因為它們的值已知。 上面代碼段中的ignoreVars用於此目的(返回代碼的字節序列,因此我們可以知道長度,但是對剛剛使用的符號的任何引用都是0)。

不要勸阻你,但已經有很多裝配工具有各種各樣的花里胡哨。 請考慮為像elftoolchain這樣的現有開源項目做出貢獻。

暫無
暫無

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

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