manとgrepの備忘録

manでコマンドのオプションを探すとき、求めている部分だけ目で探すのは不毛。
そんなときは、
man コマンド | grep キーワード -C3 --line-number
でmanの内容をgrepに渡すと楽。
grepのオプションの意味は、

-C*: ヒットした部分から前後*行文も出力する
--line-number: 行数も表示

-Eオプションで、正規表現も使えるらしい。

LLVMのお勉強2

今日は、前回作成したHelloWorld.llの中身を見ていく。 HelloWorld.llはこんなだった。

; ModuleID = 'HelloWorld.c'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@.str = private unnamed_addr constant [12 x i8] c"HelloWorld\0A\00", align 1

; Function Attrs: nounwind uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  %2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0))
  ret i32 0
}

declare i32 @printf(i8*, ...) #1

attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = !{!"clang version 3.8.1-12ubuntu1 (tags/RELEASE_381/final)"}

ここLLVM Language Reference Manual — LLVM 5 documentationを参考にした。

; ModuleID = 'HelloWorld.c'

; で始まる行はコメント文。記述からして、ソースファイル名
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

メモリ上でデータがどういう風に配置されるかを規定する。-区切りで記述していく。
e リトルエンディアン
m:<mangling> パラメータの指定によって、llvm namesがmangledされる。mangledの意味がいまいち分からない。
m:e ELFmangling/プライベートシンボルは、.Lが接頭辞につく
i<size>:<abi>:<pref> サイズ<size>の整数型のabiインターフェース<abi>,アライメント<pref>を規定する
ここでは、abiインターフェースのbitアライメントを指定している?
f<size>:<abi>:<pref> サイズ<size>の浮動小数点型とabiインターフェース<abi>,アライメント<pref>を規定する
sizeはfloat(32),double(64)、80とか128(long double)の場合もある
n<size1>:<size2>:<size3>... cpuがサポートする整数型のサイズ。n8:16:32:64はX86-64アーキテクチャ
S<size> スタックのアライメントを規定する。8の倍数に限る
指定されなかったサイズの型については、デフォルトが適用される

abiってなにさ。
調べてみると、ApplicationBinaryInterfaceの略のようだ。

target triple = "x86_64-pc-linux-gnu"

ターゲットのアーキテクチャの情報
ARCHITECTURE-VENDOR-OPERATING_SYSTEM-ENVIRONMENT
@.str = private unnamed_addr constant [12 x i8] c"HelloWorld\0A\00", align 1

グローバル変数は@.***で定義される。ほぼ、読んだままのことが書いてあるっぽい。
; Function Attrs: nounwind uwtable
define i32 @main() #0 {

defineで関数定義。i32は返り値の型。@mainが関数名,()の中に何もないので、引数をとらない。
  %1 = alloca i32, align 4

  %数字は無名変数扱い。alloca命令は、関数終了時に自動で開放されるスタックを確保する
  store i32 0, i32* %1, align 4

  store a b でaの値をbに保存する
  %2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0))

  call命令は関数呼び出しを示す。@printfだから、printf関数を呼び出している
  ret i32 0

  return。0を返している
}
declare i32 @printf(i8*, ...) #1

declare文は関数宣言。printfをよそから読み込んでいるから(定義は別にあるから)declareでやっている?
attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }

引数属性をグループ(#0,#1)ごとに定義。
関数名の後ろについてた#0とかは、これを指している。別に排他ではなく、#0と#1を同時に指定することもできる
!llvm.ident = !{!0}
!0 = !{!"clang version 3.8.1-12ubuntu1 (tags/RELEASE_381/final)"}

!で始まるのはmetadata型。metadataは書き方が少し特殊らしい

今日はこれでお終い。

LLVMのお勉強1

資料

きつねさんでもわかるLLVM-1.0.0

環境

OS:Lubuntu
clang:version 3.8.1

勉強内容

資料を参考に、CファイルをLLVM-IRへ

#include <stdio.h>

int main (){
  printf("HelloWorld\n");
  return 0;
}

コマンドは次のを使った。

clang -emit-llvm -S -o HelloWorld.ll HelloWorld.c

…何やってるかわからないので、調べる。 man clangを叩く。

-o ***: 出力ファイルを***に指定
-S: LLVMアセンブリファイルの生成
-emit-llvm: -Sオプションと一緒に指定すると、出力ファイルがLLVM中間言語アセンブリになる

というわけで、LLVM中間言語アセンブリを出力していることが分かった。

で、出力された内容(HelloWorld.ll)が次。

; ModuleID = 'HelloWorld.c'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@.str = private unnamed_addr constant [12 x i8] c"HelloWorld\0A\00", align 1

; Function Attrs: nounwind uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  %2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0))
  ret i32 0
}

declare i32 @printf(i8*, ...) #1

attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = !{!"clang version 3.8.1-12ubuntu1 (tags/RELEASE_381/final)"}

あれ、資料にのってるのと違う…
資料では、clang3.2系をベースに解説しているので、多少違いがあっても仕方ない。
次回は、HelloWorld.llの中身を紐解いていこうと思う。

勉強内容を残してみようと思った

動機

  • 勉強した内容を振替りやすい形で残したい
  • どこからでも見れると便利?

はてなブログを選んだ理由

とりあえずこんなテンションで書く