自作言語でお絵描き

>100 Views

January 03, 21

スライド概要

自作言語OpeLaでSDLを使い絵を描く方法を説明します。SDLはC言語で作られており、OpeLaから簡単に使えます。後半は可変長引数の対応方針を紹介します。

profile-image

サイボウズ・ラボ株式会社で教育向けのOSやCPU、コンパイラなどの研究開発をしています。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

自作言語でお絵描き 2021年1月3日 第24回自作OSもくもく会 @uchan_nos

2.

自己紹介 名前:内田公太 Twitter:@uchan_nos  東京工業大学 情報工学系 特任助教(週2)  サイボウズ・ラボ株式会社(週3) 活動  osdev-jpの運営  OS、言語処理系の開発 『30日でできる! OS自作入門』 の校正を担当(2006年) 『自作エミュレータで学ぶ x86アーキテクチャ』著(2015年)

3.

OpeLaプロジェクトとは OpeLa: Operating and Language processing system OSと言語処理系を全部自作するプロジェクト  OS  アセンブラ  コンパイラ  リンカ  ライブラリ 特徴:完全なセルフホスト

4.

OpeLaで書き初め

5.

OpeLaで書き初めの仕組み OpeLaでSDLを使う SDLでウィンドウ、背景、線を表示 SDL: Simple DirectMedia Layer マルチメディアを扱うライブラリ シンプルなライブラリ故に対応機種 が幅広い C言語用インタフェースなのでいろ んな言語から簡単に使える! ロゴが明滅する様子

6.
[beta]
SDLの関数を呼び出す
func main() int {
if SDL_Init(0x20) < 0 { // SDL_INIT_VIDEO
printf("Failed to initialize SDL: %s\n", SDL_GetError());
return 1;
}
printf("Creating a window\n");
window := SDL_CreateWindow("SDL by OpeLa", 0x1fff0000, 0x1fff0000, 300, 200, 0);

extern "C" SDL_Init func(flag uint) int;
extern "C" SDL_GetError func() *byte;
extern "C" SDL_CreateWindow func(title *byte, x, y, w, h int, flags uint) *int;

SDLの関数をextern宣言し、呼び出す
ヘッダファイルは読み込めないのでマクロは使えない
SDL_Window*の代わりにint*

7.

イベントポーリング var event [16]uint32; for { for SDL_PollEvent(&event[0]) != 0 { if event[0] == uint32(256) { // SDL_QUIT SDL_DestroyWindow(window); SDL_Quit(); return 0; } } SDL_Eventの代わりに[16]uint32

8.

グラデーション背景 color += dir; if color == 255 { dir = -1; } else if color == 0 { dir = 1; } SDL_SetRenderDrawColor(renderer, 0, color, color, 255); SDL_RenderClear(renderer); Colorを1ずつ変化させ、黒→青緑に徐々に変化させる SDL_SetRenderDrawColorで描画色を設定し SDL_RenderClearで背景を塗りつぶす

9.

ロゴ SDL_SetRenderDrawColor(renderer, 0, // O DrawRect(renderer, 30, 60, logo_x + // p DrawRect(renderer, 30, 30, logo_x SDL_RenderDrawLine(renderer, logo_x logo_x 0, 0, 255); 40*0, logo_y); + 40*1, logo_y + 30); + 40*1, logo_y + 60, + 40*1, logo_y + 90); func DrawRect(ren *int, w, h, x, y int) { var r [4]int32; r[0] = x; r[1] = y; r[2] = w; r[3] = h; SDL_RenderDrawRect(ren, &r[0]); } 長方形と直線の描画を駆使してロゴを描く

10.
[beta]
SDLの関数を呼び出すときの注意
SDLに限らないが、関数を呼び出す際はスタックのアライメント

に注意が必要
 参考「x86-64 モードのプログラミングではスタックのアライメントに気を付けよう」
 https://uchan.hateblo.jp/entry/2018/02/16/232029

関数を呼び出す直前でRSPが16の倍数でなければならない
void Call(std::ostream& os, Register addr) override {
os << "
push rbx\n";
os << "
mov rbx, rsp\n";
and rsp, -16
os << "
and rsp, -16\n";
=
os << "
call " << RegName(addr) << "\n";
and rsp, 0xf…f0
os << "
mov rsp, rbx\n";
os << "
pop rbx\n";
}

RBXは関数呼び出し前後で保存されている必要があるから、スタックに保存してから使う

11.

SDLを使うサンプルのビルド cat sdl.opl | ../../opelac > sdl.s cc sdl.s -lSDL2 sdl.oplをコンパイルしてsdl.sを得て libSDL2.soとリンクする

12.

可変長引数の対応

13.

OpeLaで可変長引数 可変長引数:int printf(const char* format, ...);の... C言語で可変個の引数を渡す仕組み 呼び出し側 x86-64(SystemV AMD64 ABI)  普通の引数と同様に、レジスタ渡し  RDI, RSI, RDX, RCX, R8, R9 RDI RSI RDX RCX format 1 2 3 X0 AArch64(EABI)  可変長引数だけスタック渡し format 1 2 3 SP

14.
[beta]
OpeLaの仕組みと可変長引数
OpeLaはスタックマシン
SP

式はスタックに値を積む
「1 + 2」は右図

SP
1

2

1

SP
3

SP

printf("%d:%d", 1, 2)
x86-64:いったんスタック

に引数を積み、最後にレジス
タへ転写すれば良い
普通の関数呼び出しと同じ!

文字列へのアドレス
1
2

for (int i = 0; i < num_args; ++i) {
asmgen->Pop64(os, kArgRegs[i]);
}

15.

AArch64で可変長引数 printf("%d:%d", 1, 2) AArch64では、途中までレジ スタへ転写すればいいので は? SP 1 スタックに残す 2 →ダメだった SP AArch64ではスタックに式の 文字列へのアドレス 値を8バイト飛ばしで積んで いるから 空き 1 空き AppleのABIではこうなっているが、Armの世界で一般 的なEABIでは可変長引数もレジスタ渡しらしい。 https://developer.apple.com/documentation/xcode/ writing_arm64_code_for_apple_platforms レジスタへ 文字列へのアドレス 2 空き AArch64だと 実はこうなってる

16.

なぜAArch64だと8バイト飛ばしなの? 16の倍数でないSPがベースアドレスとして使われると例外発生 str x0, [sp, #-16]! Spから16を引き、そのアドレスにx0の値を書く だから、opelacは8バイト飛ばしでスタックに値を積む →そのままでは可変長引数として使えない!

17.

私の今日の目標 AArch64で可変長引数をサポートする 引数省略記号「...」にパーサを対応させ、 可変長引数の部分はスタックに残し、 スタックの8バイトの隙間を詰め、 最後に関数を呼び出す とうまく行くかなあ…? SP 可変長引数1 コピー 空き 可変長引数2 コピー コピー 空き 可変長引数3 空き 可変長引数4

18.

OpeLaに興味ある人を募集してます 開発の様子は Twitterの@uchan_nos osdev-jp Slackの#opelaチャンネル に書いてます 今は言語設計とコンパイラ実装を並走中  「配列リテラルを実装するかどうか」  「sizeof(uint2)は何を返すべきか」  などなど… Wanted ・言語設計の話し相手 ・OpeLaロゴ制作 ・アプリ製作 ・実装のお手伝い 設計すべき部分がたくさんある 一緒にお話ししながらアイデアを練っていきたいです