iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0

要將這麼龐大且跨領域的系統從零建構起來。這不單單只是一個物理模擬器,本質上它是一個編譯器後端與高效能運算(HPC)架構的結合。 在正式讓粒子跑起來、讓數值模擬產生結果之前,要先把軟體寫出來。因此,在正式讓粒子跑起來、讓數值模擬產出炫砲的結果之前,我們得先面對骨感的現實——把底層的軟體架構寫出來。

無論多複雜的系統,先來個 LLVM - hello.ll吧。

1. Installation

最簡單無腦的方法,就是直接去 GitHub 的 llvm-project Releases 頁面,拖一個預先編譯好的 Binary 版本回來用。 因為版本變動的速度實在太快了,今年六月還在 LLVM 22.1.8 ,現在就更新到 LLVM 23.1.0-rc3。不用糾結最新版AI懂不懂, 反正 AI 總是趕不上更新的速度。

2. Hello Woeld!

; Define the main function --> int main ( )
define i32 @main() {

    ; Get a pointer to the first element of our string array
    %mystr = getelementptr [14 x i8], [14 x i8]* @.str, i64 0, i64 0
    
    ; Call the 'puts' function with the string pointer
    call i32 @puts(i8* %mystr)
    
    ; Return 0 from main
    ret i32 0
}

2.1 定義函數

define i32 @main()
  • define:這告訴 LLVM 在此定義了一個函數(相對於 declare,後者僅用來引用在其他地方定義的外部函數)。

  • i32:一個 32 位元的有號整數(signed integer)。

  • @main:函數的名稱。

  • @:代表這是一個全域識別碼(global identifier)。在 LLVM IR 中,所有函數與全域變數皆以 @ 開頭。

  • ():參數列表(parameter list)。

結果:define i32 @main():定義了一個名為 main 的全域函數,不接受任何參數,並回傳一個 32 位元的有號整數。

2.2. getelementptr (GEP) 指令

%mystr = getelementptr [14 x i8], [14 x i8]* @.str, i64 0, i64 0
  • %mystr:一個區域識別碼(由 '%' 表示),用來存放計算後位址的暫存器。

  • getelementptr:此指令用於取得複合結構型別(如陣列或結構體)中子元素的記憶體位址。

  • [14 x i8]:指定被逐步走訪的基礎型別([14 x i8],即由 14 個 8 位元整數/字元所組成的陣列)。

  • [14 x i8]*:此參數提供了全域字串變數(@.str)的型別與位址。

  • 第一個索引值 (i64 0):用於指標本身的位移。因為 @.str 是一個指向該陣列的指標,索引值 0 代表停留在 @.str 所指向的記憶體區塊起始處。

  • 第二個索引值 (i64 0):用於深入陣列結構內部。索引值 0 代表取得該 14 位元組陣列中第一個元素(索引 0)的位址。

結果:%mystr 現在儲存了一個簡單的 i8*(指向字元的指標,相當於 C 語言中的 char*),它直接指向該字串的第一個字母。

const char .str[14] = "Hello, World!\0"; // The global array
const char* mystr = &.str[0];

2.3. 呼叫外部函數

call i32 @puts(i8* %mystr)
  • call: 執行一個函數。
  • i32: 表示被呼叫的函數會回傳一個 32 位元的整數。
  • puts 來自標準 C 函式庫(libc)。
  • (i8* %mystr): 傳遞給該函數的參數。

2.4. 從 Main 回傳

ret i32 0
  • ret: 回傳(return)指令。
  • i32 0: 回傳值。表示程式執行成功,沒有發生錯誤。

等效的 C 語言程式碼

如果用 C 語言來寫,對應的程式碼會長得像這樣:

const char .str[14] = "Hello, World!\0"; // The global array

int main() {
    // This is what the GEP instruction does:
    const char* mystr = &.str[0]; 
    
    puts(mystr);
    return 0;
}

編譯並執行

# Compile using the clang binary in the neighboring folder
../llvm-binary/bin/clang hello.ll -o hello

# Run the finished executable
./hello

沒錯,不是組合語言,但是很像組合語言,算比較像人話的組合語言吧。

Reference

[1] Getting Started with the LLVM System
[2] mrjameshamilton/llvm-helloworld

同步備份於 https://github.com/botszhuang/digital_garden/blob/main/ithome_30_2026/day2.md


上一篇
Day#1: 我只是想練習一下 LLVM
系列文
自製核融合反應爐模擬器:基於 LLVM IR 動態生成 PARTICLE-IN-CELL2
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言