项目作者: Mati365

项目描述 :
16bit Intel 8086 / 80186 + X87 emulator written in TypeScript with REPL assembly compiler and tiny C compiler
高级语言: TypeScript
项目地址: git://github.com/Mati365/i8086.js.git
创建时间: 2016-08-27T15:29:21Z
项目社区:https://github.com/Mati365/i8086.js

开源协议:

下载



Banner

ts-c-compiler

License: MIT
GitHub code size in bytes
GitHub issues
PRs Welcome
CI

Multipass portable C lang compiler toolkit with IR code generator including backend, frontend, and optimizer phases. Designed to simple prototyping 16bit toy operating systems and games.

Currently supported architectures:

  1. X86 16bit real mode code emitter with floating point X87 coprocessor support

🚧 Warn! The project is unstable so please do not use it on production!

What does it offer? ⭐

  1. Reasonable assembly code quality in NASM syntax
  2. Simple prototyping boot sector games
  3. Designed especially for old-school 16bit computers with Intel 80286 (and newer) CPU and produces only simple ASM instructions
  4. Backend / Frontend architecture that allows you to add new backends in TypeScript (especially useful for homebrew FPGA CPU)
  5. Peephole optimization of IR code, precompute of constant expressions during compile time and optimizer phase
  6. Slow compile times - feel the vibe of old computing

What works? 🔥

  • Multi-pass branch optimisation (it uses jmp rel8 instructions when offset is smaller than rel16)
  • Local / Global variables
  • float / double operations using X87 stack-based registers
  • Advanced types struct, union, enum
  • Loops and if conditions while, if, do while, for, break, continue
  • Basic preprocessor with #ifdef, #define, #include
  • goto jumps
  • VA lists va_arg, va_end, va_start
  • In expression compound statements
  • Ternary operators a > 1 ? 1 : 2
  • Arithmetic operations a + b, a * b, a / b, etc.
  • Binary operations a | b, a & b etc.
  • Logic operations that are casted to numbers a && 2 || 2 > 1
  • Assign operators a += 1, a <<= b, etc.
  • Designated and C89 initializers
  • Dynamic stack alloc using alloca
  • Type aliasing typedef
  • Variable and function pointers
  • RVO optimization of larger structs
  • Peephole optimization of expensive instruction like a *= 2 -> a <<= 1
  • Constant expressions eval optimizations a = 2 * 4 -> a = 8
  • Constant branch optimization for loops and ifs for (;;) {} -> L1: jmp L1

What does not work? 🚧

  • Bitfields
  • Multiple files support
  • Linker

Online editor

Available at: https://mati365.github.io/ts-c-compiler

REPL

Install

  1. yarn add @ts-cc/cli @ts-cc/machine
  1. Usage: ts-c [options] <source>
  2. Arguments:
  3. source Relative or absolute path to source file
  4. Options:
  5. -b, --binary Emits binary stdout
  6. -o, --output <string> Relative path to your output binary
  7. -d, --debug Print AST tree and assembly output
  8. -ps, --print-assembly Print assembly output
  9. -pjs, --print-jump-assembly Print assembly output with jmps
  10. -bs, --bootsector Generate 512B bootsector output. Remember to
  11. have main entrypoint.
  12. -h, --help display help for command

Usage

Example main.c file:

  1. #include <stdio.h>
  2. #include <kernel/textmode.h>
  3. int main() {
  4. int rows = 8, coef = 1, space, i, j;
  5. kernel_screen_clear();
  6. for (i = 0; i < rows; i++) {
  7. for (space = 1; space <= rows - i; space++) {
  8. printf(" ");
  9. }
  10. for (j = 0; j <= i; j++) {
  11. if (j == 0 || i == 0) {
  12. coef = 1;
  13. } else {
  14. coef = coef * (i - j + 1) / j;
  15. }
  16. printf("%4d", coef);
  17. }
  18. printf("\n");
  19. }
  20. for (;;) {}
  21. return 0;
  22. }

Compile main.c and boot-it in 16bit VM available in web-browser:

  1. npx ts-c main.c --bootsector --binary | APP_PORT=3002 npx run-x86_16-vm

Compile main.c to x86-16 binary:

  1. npx ts-c ./main.c -o ./output.bin

Print assembly output without generate binary file:

  1. npx ts-c ./main.c -ps
  2. 0x000000 55 push bp
  3. 0x000001 89 e5 mov bp, sp
  4. 0x000003 83 ec 02 sub sp, 0x2
  5. 0x000006 c7 46 fe 04 00 mov word [bp-2], 0x4
  6. 0x00000b 89 ec mov sp, bp
  7. 0x00000d 5d pop bp
  8. 0x00000e c3 ret

Examples

Simple macros with constant expressions optimization

  1. #include "file.h"
  2. #define PRINT_SUM 1
  3. #define A 1
  4. #define B 1
  5. #define esum(...) sum(__VA_ARGS__)
  6. #define internal_fn(name) internal_ ## name
  7. #define min(a,b) ((a)<(b)?(a):(b))
  8. #define max(a,b) ((a)>(b)?(a):(b))
  9. #define sum(a,b) (min(a, b) + max(a, b))
  10. enum {
  11. TEN = 10,
  12. FIVE = 5
  13. };
  14. #ifdef PRINT_SUM
  15. #if A + B == 12 || A - B == 0
  16. int main() {
  17. int k = esum(TEN, FIVE + 1);
  18. }
  19. #endif
  20. #elifdef ABC
  21. int s = 2;
  22. #elifndef DBEF
  23. struct Vec2 { int x, y; };
  24. struct Vec2 sum_vec(int k, struct Vec2 vec, int x) {
  25. struct Vec2 result = {
  26. .x = k + vec.x * vec.y - x,
  27. .y = vec.y * 3
  28. };
  29. return result;
  30. }
  31. int main() {
  32. struct Vec2 vec = { .x = 4, .y = 3 };
  33. struct Vec2 k = sum_vec(2, vec, 5);
  34. int d = k.x + k.y;
  35. asm("xchg dx, dx");
  36. }
  37. #else
  38. int internal_fn(main)() {
  39. int k = 2;
  40. }
  41. #endif

IR Output

ruby # --- Block main --- def main(): [ret: int2B] k{0}: int*2B = alloca int2B *(k{0}: int*2B) = store %16: int2B ret end-def


Binary output

asm 0x000000 55 push bp 0x000001 89 e5 mov bp, sp 0x000003 83 ec 02 sub sp, 0x2 0x000006 c7 46 fe 10 00 mov word [bp-2], 0x10 0x00000b 89 ec mov sp, bp 0x00000d 5d pop bp 0x00000e c3 ret

Floating point operations

  1. float calculate_pi(int nbofterms) {
  2. float x = 0.0;
  3. for (int n = 0; n < nbofterms; n++) {
  4. float z = 1.0 / (2 * n + 1);
  5. if (n % 2 == 1) {
  6. z *= -1;
  7. }
  8. x = (x + z);
  9. }
  10. return 4 * x;
  11. }
  12. int main() {
  13. float pi = calculate_pi(500);
  14. int trunc_pi = pi;
  15. asm("xchg bx, bx");
  16. return 0;
  17. }

IR Output

ruby # --- Block calculate_pi --- def calculate_pi(nbofterms{0}: int*2B): [ret: float4B] x{0}: float*2B = alloca float4B *(x{0}: float*2B) = store %0: float4B n{0}: int*2B = alloca int2B *(n{0}: int*2B) = store %0: int2B L1: %t{0}: int2B = load n{0}: int*2B %t{1}: int2B = load nbofterms{0}: int*2B %t{2}: i1:zf = icmp %t{0}: int2B less_than %t{1}: int2B br %t{2}: i1:zf, true: L2, false: L3 L2: z{0}: float*2B = alloca float4B %t{5}: int2B = load n{0}: int*2B %t{6}: int2B = %t{5}: int2B mul %2: char1B %t{7}: int2B = %t{6}: int2B plus %1: char1B %t{8}: float4B = cast %t{7}: int2B %t{9}: float4B = %1: float4B div %t{8}: float4B *(z{0}: float*2B) = store %t{9}: float4B %t{11}: int2B = %t{5}: int2B mod %2: char1B %t{12}: i1:zf = icmp %t{11}: int2B equal %1: char1B br %t{12}: i1:zf, false: L4 L5: %t{14}: float4B = load z{0}: float*2B %t{15}: float4B = %t{14}: float4B mul %-1: char1B *(z{0}: float*2B) = store %t{15}: float4B L4: %t{16}: float4B = load x{0}: float*2B %t{17}: float4B = load z{0}: float*2B %t{18}: float4B = %t{16}: float4B plus %t{17}: float4B *(x{0}: float*2B) = store %t{18}: float4B %t{3}: int2B = load n{0}: int*2B %t{4}: int2B = %t{3}: int2B plus %1: int2B *(n{0}: int*2B) = store %t{4}: int2B jmp L1 L3: %t{19}: float4B = load x{0}: float*2B %t{20}: float4B = %t{19}: float4B mul %4: char1B ret %t{20}: float4B end-def # --- Block main --- def main(): [ret: int2B] pi{0}: float*2B = alloca float4B %t{22}: float4B = call label-offset calculate_pi :: (%500: int2B) *(pi{0}: float*2B) = store %t{22}: float4B trunc_pi{0}: int*2B = alloca int2B %t{23}: float4B = load pi{0}: float*2B %t{24}: int2B = cast %t{23}: float4B *(trunc_pi{0}: int*2B) = store %t{24}: int2B asm "xchg bx, bx" ret %0: char1B end-def


Binary output

asm 0x000000 <──────╮ 55 push bp 0x000001 │ 89 e5 mov bp, sp 0x000003 │ 83 ec 0c sub sp, 0xc 0x000006 │ d9 06 9b 00 fld dword [@@_$lc_0] 0x00000a │ d9 5e fc fstp dword [bp-4] 0x00000d │ c7 46 fa 00 00 mov word [bp-6], 0x0 0x000012 <────╮ │ 8b 46 04 mov ax, word [bp+4] 0x000015 │ │ 39 46 fa cmp word [bp-6], ax 0x000018 ─╮ │ │ 7c 02 jl 0x1c 0x00001a ─┼─╮ │ │ 7d 4b jge 0x67 0x00001c <╯ │ │ │ 8b 46 fa mov ax, word [bp-6] 0x00001f │ │ │ 89 c3 mov bx, ax 0x000021 │ │ │ d1 e0 shl ax, 0x1 0x000023 │ │ │ 05 01 00 add ax, 0x1 0x000026 │ │ │ 89 46 f4 mov word [bp-12], ax 0x000029 │ │ │ df 46 f4 fild word [bp-12] 0x00002c │ │ │ d9 e8 fld1 0x00002e │ │ │ d8 f1 fdiv st0, st1 0x000030 │ │ │ dd c1 ffree st1 0x000032 │ │ │ d9 5e f6 fstp dword [bp-10] 0x000035 │ │ │ 89 d8 mov ax, bx 0x000037 │ │ │ bb 02 00 mov bx, 0x2 0x00003a │ │ │ 66 99 cdq 0x00003c │ │ │ f7 fb idiv bx 0x00003e │ │ │ 83 fa 01 cmp dx, 0x1 0x000041 ─╮ │ │ │ 75 0a jnz 0x4d 0x000043 │ │ │ │ d9 46 f6 fld dword [bp-10] 0x000046 │ │ │ │ d8 0e 9f 00 fmul dword [@@_$lc_1] 0x00004a │ │ │ │ d9 5e f6 fstp dword [bp-10] 0x00004d <╯ │ │ │ d9 46 fc fld dword [bp-4] 0x000050 │ │ │ d9 46 f6 fld dword [bp-10] 0x000053 │ │ │ d9 c9 fxch st1 0x000055 │ │ │ d8 c1 fadd st0, st1 0x000057 │ │ │ dd c1 ffree st1 0x000059 │ │ │ d9 5e fc fstp dword [bp-4] 0x00005c │ │ │ 8b 46 fa mov ax, word [bp-6] 0x00005f │ │ │ 05 01 00 add ax, 0x1 0x000062 │ │ │ 89 46 fa mov word [bp-6], ax 0x000065 ───┼─╯ │ eb ab jmp 0x12 0x000067 <──╯ │ d9 46 fc fld dword [bp-4] 0x00006a │ d8 0e a3 00 fmul dword [@@_$lc_2] 0x00006e │ 89 ec mov sp, bp 0x000070 │ 5d pop bp 0x000071 │ c2 02 00 ret 0x2 0x000074 │ 55 push bp 0x000075 │ 89 e5 mov bp, sp 0x000077 │ 83 ec 0c sub sp, 0xc 0x00007a │ 68 f4 01 push 0x1f4 0x00007d ───────╯ e8 80 ff call 0x0 0x000080 d9 56 f8 fst dword [bp-8] 0x000083 d9 5e fc fstp dword [bp-4] 0x000086 d9 46 fc fld dword [bp-4] 0x000089 df 5e f4 fistp word [bp-12] 0x00008c 8b 46 f4 mov ax, word [bp-12] 0x00008f 89 46 f6 mov word [bp-10], ax 0x000092 87 db xchg bx, bx 0x000094 b8 00 00 mov ax, 0x0 0x000097 89 ec mov sp, bp 0x000099 5d pop bp 0x00009a c3 ret 0x00009b 00 00 00 00 dd 0.0 0x00009f 00 00 80 bf dd -1.0 0x0000a3 00 00 80 40 dd 4.0

### Simple VA lists with primitive types

c #include <stdarg.h> int sum_vector(int total_args, ...) { va_list ap; va_start(ap, total_args); int sum = 0; for (int i = 0; i < total_args; ++i) { sum += va_arg(ap, int); } va_end(ap); return sum; } void main() { int result = sum_vector(3, 5, 8, 10); asm("xchg dx, dx"); }


IR Output

ruby # --- Block sum_vector --- def sum_vector(total_args{0}: int*2B, ...): [ret: int2B] ap{0}: struct __builtin_va_list*2B = alloca struct __builtin_va_list2B %t{1}: struct __builtin_va_list**2B = lea ap{0}: struct __builtin_va_list*2B %t{2}: int**2B = lea total_args{0}: int*2B call label-offset __builtin_va_start :: (%t{1}: struct __builtin_va_list**2B, %t{2}: int**2B) sum{0}: int*2B = alloca int2B *(sum{0}: int*2B) = store %0: int2B i{0}: int*2B = alloca int2B *(i{0}: int*2B) = store %0: int2B L1: %t{3}: int2B = load i{0}: int*2B %t{4}: int2B = load total_args{0}: int*2B %t{5}: i1:zf = icmp %t{3}: int2B less_than %t{4}: int2B br %t{5}: i1:zf, true: L2, false: L3 L2: %t{9}: struct __builtin_va_list**2B = lea ap{0}: struct __builtin_va_list*2B %t{10}: char[2]*2B = alloca char[2]2B %t{11}: char[2]*2B = lea %t{10}: char[2]*2B call label-offset __builtin_va_arg :: (%t{9}: struct __builtin_va_list**2B, %2: int2B, %t{11}: char[2]*2B) %t{12}: int2B = load sum{0}: int*2B %t{13}: int2B = %t{12}: int2B plus %t{10}: char[2]*2B *(sum{0}: int*2B) = store %t{13}: int2B %t{6}: int2B = load i{0}: int*2B %t{7}: int2B = %t{6}: int2B plus %1: int2B *(i{0}: int*2B) = store %t{7}: int2B jmp L1 L3: %t{15}: int2B = load sum{0}: int*2B ret %t{15}: int2B end-def # --- Block main --- def main(): result{0}: int*2B = alloca int2B %t{17}: int2B = call label-offset sum_vector :: (%3: char1B, %5: char1B, %8: char1B, %10: char1B) *(result{0}: int*2B) = store %t{17}: int2B asm "xchg dx, dx" ret end-def


Binary output

asm 0x000000 <──────╮ 55 push bp 0x000001 │ 89 e5 mov bp, sp 0x000003 │ 83 ec 08 sub sp, 0x8 0x000006 │ 8d 5e fe lea bx, word [bp-2] 0x000009 │ 8d 7e 04 lea di, word [bp+4] 0x00000c │ 89 3f mov word [bx], di 0x00000e │ c7 46 fc 00 00 mov word [bp-4], 0x0 0x000013 │ c7 46 fa 00 00 mov word [bp-6], 0x0 0x000018 <────╮ │ 8b 46 04 mov ax, word [bp+4] 0x00001b │ │ 39 46 fa cmp word [bp-6], ax 0x00001e ─╮ │ │ 7c 02 jl 0x22 0x000020 ─┼─╮ │ │ 7d 25 jge 0x47 0x000022 <╯ │ │ │ 8d 5e fe lea bx, word [bp-2] 0x000025 │ │ │ 8d 7e f8 lea di, word [bp-8] 0x000028 │ │ │ 8b 37 mov si, word [bx] 0x00002a │ │ │ 83 c6 02 add si, 0x2 0x00002d │ │ │ 8b 04 mov ax, word [si] 0x00002f │ │ │ 89 05 mov word [di], ax 0x000031 │ │ │ 89 37 mov word [bx], si 0x000033 │ │ │ 8b 46 fc mov ax, word [bp-4] 0x000036 │ │ │ 03 46 f8 add ax, word [bp-8] 0x000039 │ │ │ 89 46 fc mov word [bp-4], ax 0x00003c │ │ │ 8b 5e fa mov bx, word [bp-6] 0x00003f │ │ │ 83 c3 01 add bx, 0x1 0x000042 │ │ │ 89 5e fa mov word [bp-6], bx 0x000045 ───┼─╯ │ eb d1 jmp 0x18 0x000047 <──╯ │ 8b 46 fc mov ax, word [bp-4] 0x00004a │ 89 ec mov sp, bp 0x00004c │ 5d pop bp 0x00004d │ c2 02 00 ret 0x2 0x000050 │ 55 push bp 0x000051 │ 89 e5 mov bp, sp 0x000053 │ 83 ec 02 sub sp, 0x2 0x000056 │ 6a 0a push 0xa 0x000058 │ 6a 08 push 0x8 0x00005a │ 6a 05 push 0x5 0x00005c │ 6a 03 push 0x3 0x00005e ───────╯ e8 9f ff call 0x0 0x000061 83 c4 06 add sp, 0x6 0x000064 89 46 fe mov word [bp-2], ax 0x000067 87 d2 xchg dx, dx 0x000069 89 ec mov sp, bp 0x00006b 5d pop bp 0x00006c c3 ret

Advanced structures with recursive calls

  1. int fibbonacci(int n)
  2. {
  3. if (n == 1)
  4. return 0;
  5. if (n <= 3)
  6. return 1;
  7. return fibbonacci(n-1) + fibbonacci(n-2);
  8. }
  9. struct Vec2 { int x, y; };
  10. struct Vec2 sum_vec(int k, struct Vec2 vec, int x) {
  11. struct Vec2 result = {
  12. .x = k + vec.x * vec.y - x,
  13. .y = vec.y * 3 + (fibbonacci(10) * 2 + fibbonacci(10) * 15)
  14. };
  15. return result;
  16. }
  17. int main() {
  18. struct Vec2 vec = { .x = 4, .y = 3 };
  19. struct Vec2 k = sum_vec(2, vec, 5);
  20. int d = k.x + k.y;
  21. asm("xchg dx, dx");
  22. }

IR Output

ruby # --- Block fibbonacci --- def fibbonacci(n{0}: int*2B): [ret: int2B] %t{0}: int2B = load n{0}: int*2B %t{1}: i1:zf = icmp %t{0}: int2B equal %1: char1B br %t{1}: i1:zf, false: L1 L2: ret %0: char1B L1: %t{2}: int2B = load n{0}: int*2B %t{3}: i1:zf = icmp %t{2}: int2B less_eq_than %3: char1B br %t{3}: i1:zf, false: L3 L4: ret %1: char1B L3: %t{5}: int2B = load n{0}: int*2B %t{6}: int2B = %t{5}: int2B minus %1: char1B %t{7}: int2B = call label-offset fibbonacci :: (%t{6}: int2B) %t{10}: int2B = %t{5}: int2B minus %2: char1B %t{11}: int2B = call label-offset fibbonacci :: (%t{10}: int2B) %t{12}: int2B = %t{7}: int2B plus %t{11}: int2B ret %t{12}: int2B end-def # --- Block sum_vec --- def sum_vec(k{0}: int*2B, vec{0}: struct Vec2*2B, x{0}: int*2B, rvo: %out{0}: struct Vec2*2B): result{0}: struct Vec2*2B = alloca struct Vec24B %t{13}: int2B = load k{0}: int*2B %t{14}: struct Vec2**2B = lea vec{0}: struct Vec2*2B %t{15}: int2B = load %t{14}: struct Vec2**2B %t{17}: struct Vec2**2B = %t{14}: struct Vec2**2B plus %2: int2B %t{18}: int2B = load %t{17}: struct Vec2**2B %t{19}: int2B = %t{15}: int2B mul %t{18}: int2B %t{20}: int2B = %t{13}: int2B plus %t{19}: int2B %t{21}: int2B = load x{0}: int*2B %t{22}: int2B = %t{20}: int2B minus %t{21}: int2B *(result{0}: struct Vec2*2B) = store %t{22}: int2B %t{24}: struct Vec2**2B = %t{14}: struct Vec2**2B plus %2: int2B %t{25}: int2B = load %t{24}: struct Vec2**2B %t{26}: int2B = %t{25}: int2B mul %3: char1B %t{28}: int2B = call label-offset fibbonacci :: (%10: char1B) %t{29}: int2B = %t{28}: int2B mul %2: char1B %t{31}: int2B = call label-offset fibbonacci :: (%10: char1B) %t{32}: int2B = %t{31}: int2B mul %15: char1B %t{33}: int2B = %t{29}: int2B plus %t{32}: int2B %t{34}: int2B = %t{26}: int2B plus %t{33}: int2B *(result{0}: struct Vec2*2B + %2) = store %t{34}: int2B ret result{0}: struct Vec2*2B end-def # --- Block main --- def main(): [ret: int2B] vec{1}: struct Vec2*2B = alloca struct Vec24B *(vec{1}: struct Vec2*2B) = store %4: int2B *(vec{1}: struct Vec2*2B + %2) = store %3: int2B k{1}: struct Vec2*2B = alloca struct Vec24B %t{36}: struct Vec2**2B = lea k{1}: struct Vec2*2B call label-offset sum_vec :: (%2: char1B, vec{1}: struct Vec2*2B, %5: char1B, %t{36}: struct Vec2**2B) d{0}: int*2B = alloca int2B %t{37}: struct Vec2**2B = lea k{1}: struct Vec2*2B %t{38}: int2B = load %t{37}: struct Vec2**2B %t{40}: struct Vec2**2B = %t{37}: struct Vec2**2B plus %2: int2B %t{41}: int2B = load %t{40}: struct Vec2**2B %t{42}: int2B = %t{38}: int2B plus %t{41}: int2B *(d{0}: int*2B) = store %t{42}: int2B asm "xchg dx, dx" ret end-def


Binary output

asm 0x000000 <──╮<╮<╮<╮ 55 push bp 0x000001 │ │ │ │ 89 e5 mov bp, sp 0x000003 │ │ │ │ 83 7e 04 01 cmp word [bp+4], 0x1 0x000007 ─╮ │ │ │ │ 75 09 jnz 0x12 0x000009 │ │ │ │ │ b8 00 00 mov ax, 0x0 0x00000c │ │ │ │ │ 89 ec mov sp, bp 0x00000e │ │ │ │ │ 5d pop bp 0x00000f │ │ │ │ │ c2 02 00 ret 0x2 0x000012 <╯ │ │ │ │ 83 7e 04 03 cmp word [bp+4], 0x3 0x000016 ─╮ │ │ │ │ 7f 09 jg 0x21 0x000018 │ │ │ │ │ b8 01 00 mov ax, 0x1 0x00001b │ │ │ │ │ 89 ec mov sp, bp 0x00001d │ │ │ │ │ 5d pop bp 0x00001e │ │ │ │ │ c2 02 00 ret 0x2 0x000021 <╯ │ │ │ │ 8b 46 04 mov ax, word [bp+4] 0x000024 │ │ │ │ 89 c3 mov bx, ax 0x000026 │ │ │ │ 2d 01 00 sub ax, 0x1 0x000029 │ │ │ │ 53 push bx 0x00002a │ │ │ │ 50 push ax 0x00002b ───╯ │ │ │ e8 d2 ff call 0x0 0x00002e │ │ │ 5b pop bx 0x00002f │ │ │ 83 eb 02 sub bx, 0x2 0x000032 │ │ │ 91 xchg ax, cx 0x000033 │ │ │ 51 push cx 0x000034 │ │ │ 53 push bx 0x000035 ─────╯ │ │ e8 c8 ff call 0x0 0x000038 │ │ 59 pop cx 0x000039 │ │ 01 c1 add cx, ax 0x00003b │ │ 89 c8 mov ax, cx 0x00003d │ │ 89 ec mov sp, bp 0x00003f │ │ 5d pop bp 0x000040 │ │ c2 02 00 ret 0x2 0x000043 <╮ │ │ 55 push bp 0x000044 │ │ │ 89 e5 mov bp, sp 0x000046 │ │ │ 83 ec 04 sub sp, 0x4 0x000049 │ │ │ 8d 5e 06 lea bx, word [bp+6] 0x00004c │ │ │ 8b 07 mov ax, word [bx] 0x00004e │ │ │ 89 d9 mov cx, bx 0x000050 │ │ │ 83 c3 02 add bx, 0x2 0x000053 │ │ │ 8b 17 mov dx, word [bx] 0x000055 │ │ │ 0f af c2 imul ax, dx 0x000058 │ │ │ 8b 7e 04 mov di, word [bp+4] 0x00005b │ │ │ 01 c7 add di, ax 0x00005d │ │ │ 2b 7e 0a sub di, word [bp+10] 0x000060 │ │ │ 89 7e fc mov word [bp-4], di 0x000063 │ │ │ 83 c1 02 add cx, 0x2 0x000066 │ │ │ 89 cb mov bx, cx 0x000068 │ │ │ 8b 07 mov ax, word [bx] 0x00006a │ │ │ 6b c0 03 imul ax, ax, 0x3 0x00006d │ │ │ 93 xchg ax, bx 0x00006e │ │ │ 53 push bx 0x00006f │ │ │ 6a 0a push 0xa 0x000071 ─┼─────╯ │ e8 8c ff call 0x0 0x000074 │ │ 5b pop bx 0x000075 │ │ d1 e0 shl ax, 0x1 0x000077 │ │ 91 xchg ax, cx 0x000078 │ │ 53 push bx 0x000079 │ │ 51 push cx 0x00007a │ │ 6a 0a push 0xa 0x00007c ─┼───────╯ e8 81 ff call 0x0 0x00007f │ 59 pop cx 0x000080 │ 5b pop bx 0x000081 │ 6b c0 0f imul ax, ax, 0xf 0x000084 │ 01 c1 add cx, ax 0x000086 │ 01 cb add bx, cx 0x000088 │ 89 5e fe mov word [bp-2], bx 0x00008b │ 8d 7e fc lea di, word [bp-4] 0x00008e │ 8b 76 0c mov si, word [bp+12] 0x000091 │ 8b 15 mov dx, word [di] 0x000093 │ 89 14 mov word [si], dx 0x000095 │ 8b 55 02 mov dx, word [di+2] 0x000098 │ 89 54 02 mov word [si+2], dx 0x00009b │ 89 ec mov sp, bp 0x00009d │ 5d pop bp 0x00009e │ c2 08 00 ret 0x8 0x0000a1 │ 55 push bp 0x0000a2 │ 89 e5 mov bp, sp 0x0000a4 │ 83 ec 0a sub sp, 0xa 0x0000a7 │ c7 46 fc 04 00 mov word [bp-4], 0x4 0x0000ac │ c7 46 fe 03 00 mov word [bp-2], 0x3 0x0000b1 │ 8d 5e f8 lea bx, word [bp-8] 0x0000b4 │ 53 push bx 0x0000b5 │ 6a 05 push 0x5 0x0000b7 │ ff 76 fe push word [bp-2] 0x0000ba │ ff 76 fc push word [bp-4] 0x0000bd │ 6a 02 push 0x2 0x0000bf ─╯ e8 81 ff call 0x43 0x0000c2 8d 5e f8 lea bx, word [bp-8] 0x0000c5 8b 07 mov ax, word [bx] 0x0000c7 83 c3 02 add bx, 0x2 0x0000ca 8b 0f mov cx, word [bx] 0x0000cc 01 c8 add ax, cx 0x0000ce 89 46 f6 mov word [bp-10], ax 0x0000d1 87 d2 xchg dx, dx 0x0000d3 89 ec mov sp, bp 0x0000d5 5d pop bp 0x0000d6 c3 ret

Compound statements

GCC Docs

  1. void main() {
  2. int dupa = (({
  3. int c = 3, k, d;
  4. k = 16;
  5. d = 20;
  6. c + k + d * 4;
  7. }) *
  8. 2 * ({
  9. int k = 15;
  10. k * 2;
  11. })) *
  12. ({ 5 + 2; });
  13. asm("xchg dx, dx");
  14. }

IR Output

ruby # --- Block main --- def main(): dupa{0}: int*2B = alloca int2B c{0}: int*2B = alloca int2B *(c{0}: int*2B) = store %3: int2B k{0}: int*2B = alloca int2B d{0}: int*2B = alloca int2B *(k{0}: int*2B) = store %16: char1B *(d{0}: int*2B) = store %20: char1B %t{0}: int2B = load c{0}: int*2B %t{1}: int2B = load k{0}: int*2B %t{3}: int2B = load d{0}: int*2B %t{8}: int2B = %t{0}: int2B plus %t{1}: int2B %t{10}: int2B = %t{3}: int2B mul %4: char1B %t{11}: int2B = %t{8}: int2B plus %t{10}: int2B %t{12}: int2B = %t{11}: int2B mul %2: char1B k{1}: int*2B = alloca int2B *(k{1}: int*2B) = store %15: int2B %t{13}: int2B = load k{1}: int*2B %t{16}: int2B = %t{13}: int2B mul %2: char1B %t{17}: int2B = %t{12}: int2B mul %t{16}: int2B %t{20}: int2B = %t{17}: int2B mul %7: char1B *(dupa{0}: int*2B) = store %t{20}: int2B asm "xchg dx, dx" ret end-def


Binary output

asm 0x000000 55 push bp 0x000001 89 e5 mov bp, sp 0x000003 83 ec 0a sub sp, 0xa 0x000006 c7 46 fc 03 00 mov word [bp-4], 0x3 0x00000b c7 46 fa 10 00 mov word [bp-6], 0x10 0x000010 c7 46 f8 14 00 mov word [bp-8], 0x14 0x000015 8b 46 fc mov ax, word [bp-4] 0x000018 03 46 fa add ax, word [bp-6] 0x00001b 8b 5e f8 mov bx, word [bp-8] 0x00001e c1 e3 02 shl bx, 0x2 0x000021 01 d8 add ax, bx 0x000023 d1 e0 shl ax, 0x1 0x000025 c7 46 f6 0f 00 mov word [bp-10], 0xf 0x00002a 8b 4e f6 mov cx, word [bp-10] 0x00002d d1 e1 shl cx, 0x1 0x00002f 0f af c1 imul ax, cx 0x000032 6b c0 07 imul ax, ax, 0x7 0x000035 89 46 fe mov word [bp-2], ax 0x000038 87 d2 xchg dx, dx 0x00003a 89 ec mov sp, bp 0x00003c 5d pop bp 0x00003d c3 ret

Advanced array / pointers / ternary expressions

  1. int strlen(const char* str) {
  2. for (int i = 0;;++i) {
  3. if (*(str + i) == 0) {
  4. return i;
  5. }
  6. }
  7. return -1;
  8. }
  9. typedef struct Box {
  10. int x, y;
  11. const char* str;
  12. } box_t;
  13. int max (int a, int b) {
  14. return a > b ? a : b;
  15. }
  16. void main() {
  17. box_t vec[] = { { .y = 5 }, { .x = 4, .str = "ABC" } };
  18. vec[0].str = "Hello world!";
  19. vec[0].y++;
  20. vec[1].x += 3;
  21. int k = vec[1].x * vec[0].y + strlen(vec[0].str);
  22. int d = max(666, k * 20);
  23. asm("xchg dx, dx");
  24. }

IR Output

ruby # --- Block strlen --- def strlen(str{0}: const char**2B): [ret: int2B] i{0}: int*2B = alloca int2B *(i{0}: int*2B) = store %0: int2B L1: %t{2}: const char*2B = load str{0}: const char**2B %t{3}: int2B = load i{0}: int*2B %t{4}: const char*2B = %t{2}: const char*2B plus %t{3}: int2B %t{5}: const char1B = load %t{4}: const char*2B %t{6}: i1:zf = icmp %t{5}: const char1B equal %0: char1B br %t{6}: i1:zf, false: L4 L5: %t{7}: int2B = load i{0}: int*2B ret %t{7}: int2B L4: %t{0}: int2B = load i{0}: int*2B %t{1}: int2B = %t{0}: int2B plus %1: int2B *(i{0}: int*2B) = store %t{1}: int2B jmp L1 L3: ret %-1: char1B end-def # --- Block max --- def max(a{0}: int*2B, b{0}: int*2B): [ret: int2B] %t{9}: int2B = alloca int2B %t{10}: int2B = load a{0}: int*2B %t{11}: int2B = load b{0}: int*2B %t{12}: i1:zf = icmp %t{10}: int2B greater_than %t{11}: int2B br %t{12}: i1:zf, false: L8 L7: %t{15}: int2B = load a{0}: int*2B %t{13}: int2B = assign:φ %t{15}: int2B jmp L6 L8: %t{16}: int2B = load b{0}: int*2B %t{14}: int2B = assign:φ %t{16}: int2B L6: %t{9}: int2B = φ(%t{13}: int2B, %t{14}: int2B) ret %t{9}: int2B end-def # --- Block main --- def main(): vec{0}: struct Box[3]*2B = alloca struct Box[3]18B *(vec{0}: struct Box[3]*2B + %2) = store %5: int2B *(vec{0}: struct Box[3]*2B + %6) = store %4: int2B *(vec{0}: int*2B + %10) = store %16961: int2B *(vec{0}: int*2B + %12) = store %67: int2B %t{17}: struct Box[3]*2B = lea vec{0}: struct Box[3]*2B %t{20}: const char**2B = label-offset c{0} %t{21}: const char*2B = load %t{20}: const char**2B *(vec{0}: struct Box[3]*2B + %4) = store %t{21}: const char*2B %t{24}: int*2B = %t{17}: struct Box[3]*2B plus %2: int2B %t{25}: int2B = load %t{24}: int*2B %t{26}: int2B = %t{25}: int2B plus %1: int2B *(vec{0}: struct Box[3]*2B + %2) = store %t{26}: int2B %t{28}: struct Box[3]*2B = %t{17}: struct Box[3]*2B plus %6: int2B %t{29}: int2B = load %t{28}: int*2B %t{30}: int2B = %t{29}: int2B plus %3: char1B *(vec{0}: struct Box[3]*2B + %6) = store %t{30}: int2B k{0}: int*2B = alloca int2B %t{32}: struct Box[3]*2B = %t{17}: struct Box[3]*2B plus %6: int2B %t{33}: int2B = load %t{32}: int*2B %t{36}: int*2B = %t{17}: struct Box[3]*2B plus %2: int2B %t{37}: int2B = load %t{36}: int*2B %t{38}: int2B = %t{33}: int2B mul %t{37}: int2B %t{42}: const char**2B = %t{17}: struct Box[3]*2B plus %4: int2B %t{43}: const char*2B = load %t{42}: const char**2B %t{44}: int2B = call label-offset strlen :: (%t{43}: const char*2B) %t{45}: int2B = %t{38}: int2B plus %t{44}: int2B *(k{0}: int*2B) = store %t{45}: int2B d{0}: int*2B = alloca int2B %t{47}: int2B = load k{0}: int*2B %t{48}: int2B = %t{47}: int2B mul %20: char1B %t{49}: int2B = call label-offset max :: (%666: int2B, %t{48}: int2B) *(d{0}: int*2B) = store %t{49}: int2B asm "xchg dx, dx" ret end-def # --- Block Data --- c{0}: const char**2B = const { Hello world! }


Binary output

asm 0x000000 <────╮ 55 push bp 0x000001 │ 89 e5 mov bp, sp 0x000003 │ 83 ec 02 sub sp, 0x2 0x000006 │ c7 46 fe 00 00 mov word [bp-2], 0x0 0x00000b <──╮ │ 8b 5e 04 mov bx, word [bp+4] 0x00000e │ │ 03 5e fe add bx, word [bp-2] 0x000011 │ │ 8a 07 mov al, byte [bx] 0x000013 │ │ 3c 00 cmp al, 0x0 0x000015 ─╮ │ │ 75 09 jnz 0x20 0x000017 │ │ │ 8b 46 fe mov ax, word [bp-2] 0x00001a │ │ │ 89 ec mov sp, bp 0x00001c │ │ │ 5d pop bp 0x00001d │ │ │ c2 02 00 ret 0x2 0x000020 <╯ │ │ 8b 46 fe mov ax, word [bp-2] 0x000023 │ │ 05 01 00 add ax, 0x1 0x000026 │ │ 89 46 fe mov word [bp-2], ax 0x000029 ───╯ │ eb e0 jmp 0xb 0x00002b │ b8 ff ff mov ax, -0x1 0x00002e │ 89 ec mov sp, bp 0x000030 │ 5d pop bp 0x000031 │ c2 02 00 ret 0x2 0x000034 <────┼─╮ 55 push bp 0x000035 │ │ 89 e5 mov bp, sp 0x000037 │ │ 83 ec 02 sub sp, 0x2 0x00003a │ │ 8b 46 06 mov ax, word [bp+6] 0x00003d │ │ 39 46 04 cmp word [bp+4], ax 0x000040 ─╮ │ │ 7e 05 jng 0x47 0x000042 │ │ │ 8b 46 04 mov ax, word [bp+4] 0x000045 ─┼─╮ │ │ eb 03 jmp 0x4a 0x000047 <╯ │ │ │ 8b 46 06 mov ax, word [bp+6] 0x00004a <──╯ │ │ 89 ec mov sp, bp 0x00004c │ │ 5d pop bp 0x00004d │ │ c2 04 00 ret 0x4 0x000050 │ │ 55 push bp 0x000051 │ │ 89 e5 mov bp, sp 0x000053 │ │ 83 ec 16 sub sp, 0x16 0x000056 │ │ c7 46 f0 05 00 mov word [bp-16], 0x5 0x00005b │ │ c7 46 f4 04 00 mov word [bp-12], 0x4 0x000060 │ │ c7 46 f8 41 42 mov word [bp-8], 0x4241 0x000065 │ │ c7 46 fa 43 00 mov word [bp-6], 0x43 0x00006a │ │ 8d 5e ee lea bx, word [bp-18] 0x00006d │ │ a1 cc 00 mov ax, ds:@@_c_0_ 0x000070 │ │ 89 46 f2 mov word [bp-14], ax 0x000073 │ │ 89 d9 mov cx, bx 0x000075 │ │ 83 c3 02 add bx, 0x2 0x000078 │ │ 8b 17 mov dx, word [bx] 0x00007a │ │ 83 c2 01 add dx, 0x1 0x00007d │ │ 89 56 f0 mov word [bp-16], dx 0x000080 │ │ 89 c8 mov ax, cx 0x000082 │ │ 83 c1 06 add cx, 0x6 0x000085 │ │ 89 cf mov di, cx 0x000087 │ │ 8b 1d mov bx, word [di] 0x000089 │ │ 83 c3 03 add bx, 0x3 0x00008c │ │ 89 5e f4 mov word [bp-12], bx 0x00008f │ │ 89 c1 mov cx, ax 0x000091 │ │ 05 06 00 add ax, 0x6 0x000094 │ │ 89 c6 mov si, ax 0x000096 │ │ 8b 14 mov dx, word [si] 0x000098 │ │ 89 c8 mov ax, cx 0x00009a │ │ 83 c1 02 add cx, 0x2 0x00009d │ │ 89 cf mov di, cx 0x00009f │ │ 8b 1d mov bx, word [di] 0x0000a1 │ │ 0f af d3 imul dx, bx 0x0000a4 │ │ 05 04 00 add ax, 0x4 0x0000a7 │ │ 89 c6 mov si, ax 0x0000a9 │ │ 8b 0c mov cx, word [si] 0x0000ab │ │ 52 push dx 0x0000ac │ │ 51 push cx 0x0000ad ─────╯ │ e8 50 ff call 0x0 0x0000b0 │ 5a pop dx 0x0000b1 │ 01 c2 add dx, ax 0x0000b3 │ 89 56 ec mov word [bp-20], dx 0x0000b6 │ 8b 5e ec mov bx, word [bp-20] 0x0000b9 │ 6b db 14 imul bx, bx, 0x14 0x0000bc │ 53 push bx 0x0000bd │ 68 9a 02 push 0x29a 0x0000c0 ───────╯ e8 71 ff call 0x34 0x0000c3 89 46 ea mov word [bp-22], ax 0x0000c6 87 d2 xchg dx, dx 0x0000c8 89 ec mov sp, bp 0x0000ca 5d pop bp 0x0000cb c3 ret 0x0000cc ce 00 dw @@_c_0_@str$0_0 0x0000ce 48 65 6c 6c 6f 20 77 6f db "hello world!", 0x0 72 6c 64 21 00 00

Dynamic alloca

  1. #include <alloca.h>
  2. int main() {
  3. int k = 10;
  4. char* buffer = alloca(k);
  5. return 0;
  6. }

IR Output

ruby # --- Block main --- def main(): [ret: int2B] k{0}: int*2B = alloca int2B *(k{0}: int*2B) = store %10: int2B buffer{0}: char**2B = alloca char*2B %t{1}: int2B = load k{0}: int*2B %t{2}: char*2B = call label-offset __builtin_alloca :: (%t{1}: int2B) *(buffer{0}: char**2B) = store %t{2}: char*2B ret %0: char1B end-def


Binary output

asm 0x000000 55 push bp 0x000001 89 e5 mov bp, sp 0x000003 83 ec 04 sub sp, 0x4 0x000006 c7 46 fe 0a 00 mov word [bp-2], 0xa 0x00000b 2b 66 fe sub sp, word [bp-2] 0x00000e 89 e0 mov ax, sp 0x000010 89 46 fc mov word [bp-4], ax 0x000013 b8 00 00 mov ax, 0x0 0x000016 89 ec mov sp, bp 0x000018 5d pop bp 0x000019 c3 ret

Simple function calls with peephole optimization

  1. #define int16_t int
  2. int16_t sum(int x) {
  3. return x * 2 / 4;
  4. }
  5. int16_t main() {
  6. return sum(3);
  7. }

IR Output

ruby # --- Block sum --- def sum(x{0}: int*2B): [ret: int2B] %t{0}: int2B = load x{0}: int*2B %t{2}: int2B = %t{0}: int2B div %2: char1B ret %t{2}: int2B end-def # --- Block main --- def main(): [ret: int2B] %t{4}: int2B = call label-offset sum :: (%3: char1B) ret %t{4}: int2B end-def


Binary output

asm 0x000000 <╮ 55 push bp 0x000001 │ 89 e5 mov bp, sp 0x000003 │ 8b 46 04 mov ax, word [bp+4] 0x000006 │ d1 e8 shr ax, 0x1 0x000008 │ 89 ec mov sp, bp 0x00000a │ 5d pop bp 0x00000b │ c2 02 00 ret 0x2 0x00000e │ 55 push bp 0x00000f │ 89 e5 mov bp, sp 0x000011 │ 6a 03 push 0x3 0x000013 ─╯ e8 ea ff call 0x0 0x000016 89 ec mov sp, bp 0x000018 5d pop bp 0x000019 c3 ret

Function pointers

  1. int sum(int x, int y) {
  2. return x + y * 2;
  3. }
  4. int addPtr(int (*functionPtr)(int, int)) {
  5. return (*functionPtr)(2, 3);
  6. }
  7. int main() {
  8. int sum = addPtr(sum);
  9. }

IR Output

ruby # --- Block sum --- def sum(x{0}: int*2B, y{0}: int*2B): [ret: int2B] %t{0}: int2B = load x{0}: int*2B %t{1}: int2B = load y{0}: int*2B %t{2}: int2B = %t{1}: int2B mul %2: char1B %t{3}: int2B = %t{0}: int2B plus %t{2}: int2B ret %t{3}: int2B end-def # --- Block addPtr --- def addPtr(functionPtr{0}: int(int, int)**2B): [ret: int2B] %t{4}: int(int, int)*2B = load functionPtr{0}: int(int, int)**2B %t{5}: int2B = call %t{4}: int(int, int)*2B :: (%2: char1B, %3: char1B) ret %t{5}: int2B end-def # --- Block main --- def main(): [ret: int2B] sum{0}: int*2B = alloca int2B %t{7}: int sum(int, int)*2B = label-offset sum %t{8}: int2B = call label-offset addPtr :: (%t{7}: int sum(int, int)*2B) *(sum{0}: int*2B) = store %t{8}: int2B ret end-def


Binary output

asm 0x000000 55 push bp 0x000001 89 e5 mov bp, sp 0x000003 8b 46 06 mov ax, word [bp+6] 0x000006 d1 e0 shl ax, 0x1 0x000008 8b 5e 04 mov bx, word [bp+4] 0x00000b 01 c3 add bx, ax 0x00000d 89 d8 mov ax, bx 0x00000f 89 ec mov sp, bp 0x000011 5d pop bp 0x000012 c2 04 00 ret 0x4 0x000015 <╮ 55 push bp 0x000016 │ 89 e5 mov bp, sp 0x000018 │ 8b 5e 04 mov bx, word [bp+4] 0x00001b │ 6a 03 push 0x3 0x00001d │ 6a 02 push 0x2 0x00001f │ ff d3 call bx 0x000021 │ 89 ec mov sp, bp 0x000023 │ 5d pop bp 0x000024 │ c2 02 00 ret 0x2 0x000027 │ 55 push bp 0x000028 │ 89 e5 mov bp, sp 0x00002a │ 83 ec 02 sub sp, 0x2 0x00002d │ 6a 00 push 0x0 0x00002f ─╯ e8 e3 ff call 0x15 0x000032 89 46 fe mov word [bp-2], ax 0x000035 89 ec mov sp, bp 0x000037 5d pop bp 0x000038 c3 ret

Bubble sort

  1. void bubble_sort(int a[], int n) {
  2. int i = 0, j = 0, tmp;
  3. for (i = 0; i < n; i++) { // loop n times - 1 per element
  4. for (j = 0; j < n - i - 1; j++) { // last i elements are sorted already
  5. if (a[j] > a[j + 1]) { // swop if order is broken
  6. tmp = a[j];
  7. a[j] = a[j + 1];
  8. a[j + 1] = tmp;
  9. }
  10. }
  11. }
  12. }

IR Output

ruby # --- Block bubble_sort --- def bubble_sort(a{0}: int[]*2B, n{0}: int*2B): i{0}: int*2B = alloca int2B *(i{0}: int*2B) = store %0: int2B j{0}: int*2B = alloca int2B *(j{0}: int*2B) = store %0: int2B tmp{0}: int*2B = alloca int2B L1: %t{0}: int2B = load i{0}: int*2B %t{1}: int2B = load n{0}: int*2B %t{2}: i1:zf = icmp %t{0}: int2B less_than %t{1}: int2B br %t{2}: i1:zf, true: L2, false: L3 L2: %t{5}: int2B = load j{0}: int*2B %t{6}: int2B = load n{0}: int*2B %t{7}: int2B = load i{0}: int*2B %t{8}: int2B = %t{6}: int2B minus %t{7}: int2B %t{9}: int2B = %t{8}: int2B minus %1: char1B %t{10}: i1:zf = icmp %t{5}: int2B less_than %t{9}: int2B br %t{10}: i1:zf, true: L5, false: L6 L5: %t{13}: int[]*2B = lea a{0}: int[]*2B %t{14}: int2B = load j{0}: int*2B %t{15}: int[]*2B = %t{14}: int2B mul %2: int2B %t{16}: int[]*2B = %t{13}: int[]*2B plus %t{15}: int[]*2B %t{17}: int2B = load %t{16}: int[]*2B %t{20}: int2B = %t{14}: int2B plus %1: char1B %t{21}: int[]*2B = %t{20}: int2B mul %2: int2B %t{22}: int[]*2B = %t{13}: int[]*2B plus %t{21}: int[]*2B %t{23}: int2B = load %t{22}: int[]*2B %t{24}: i1:zf = icmp %t{17}: int2B greater_than %t{23}: int2B br %t{24}: i1:zf, false: L7 L8: %t{25}: int[]*2B = lea a{0}: int[]*2B %t{26}: int2B = load j{0}: int*2B %t{27}: int[]*2B = %t{26}: int2B mul %2: int2B %t{28}: int[]*2B = %t{25}: int[]*2B plus %t{27}: int[]*2B %t{29}: int2B = load %t{28}: int[]*2B *(tmp{0}: int*2B) = store %t{29}: int2B %t{32}: int[]*2B = %t{26}: int2B mul %2: int2B %t{33}: int[]*2B = %t{25}: int[]*2B plus %t{32}: int[]*2B %t{36}: int2B = %t{26}: int2B plus %1: char1B %t{37}: int[]*2B = %t{36}: int2B mul %2: int2B %t{38}: int[]*2B = %t{25}: int[]*2B plus %t{37}: int[]*2B %t{39}: int2B = load %t{38}: int[]*2B *(%t{33}: int[]*2B) = store %t{39}: int2B %t{42}: int2B = %t{26}: int2B plus %1: char1B %t{43}: int[]*2B = %t{42}: int2B mul %2: int2B %t{44}: int[]*2B = %t{25}: int[]*2B plus %t{43}: int[]*2B %t{45}: int2B = load tmp{0}: int*2B *(%t{44}: int[]*2B) = store %t{45}: int2B L7: %t{11}: int2B = load j{0}: int*2B %t{12}: int2B = %t{11}: int2B plus %1: int2B *(j{0}: int*2B) = store %t{12}: int2B jmp L2 L6: %t{3}: int2B = load i{0}: int*2B %t{4}: int2B = %t{3}: int2B plus %1: int2B *(i{0}: int*2B) = store %t{4}: int2B jmp L1 L3: ret end-def


Binary output

asm 0x000000 55 push bp 0x000001 89 e5 mov bp, sp 0x000003 83 ec 0a sub sp, 0xa 0x000006 c7 46 fe 00 00 mov word [bp-2], 0x0 0x00000b c7 46 fc 00 00 mov word [bp-4], 0x0 0x000010 <────────╮ 8b 46 06 mov ax, word [bp+6] 0x000013 │ 39 46 fe cmp word [bp-2], ax 0x000016 ─╮ │ 7c 04 jl 0x1c 0x000018 ─┼─╮ │ 0f 8d 89 00 jge 0xa5 0x00001c <╯<┼───╮ │ 8b 46 06 mov ax, word [bp+6] 0x00001f │ │ │ 2b 46 fe sub ax, word [bp-2] 0x000022 │ │ │ 2d 01 00 sub ax, 0x1 0x000025 │ │ │ 39 46 fc cmp word [bp-4], ax 0x000028 ─╮ │ │ │ 7c 02 jl 0x2c 0x00002a ─┼─┼─╮ │ │ 7d 6d jge 0x99 0x00002c <╯ │ │ │ │ 8d 5e 04 lea bx, word [bp+4] 0x00002f │ │ │ │ 8b 46 fc mov ax, word [bp-4] 0x000032 │ │ │ │ 89 c1 mov cx, ax 0x000034 │ │ │ │ d1 e0 shl ax, 0x1 0x000036 │ │ │ │ 89 da mov dx, bx 0x000038 │ │ │ │ 01 c3 add bx, ax 0x00003a │ │ │ │ 8b 07 mov ax, word [bx] 0x00003c │ │ │ │ 83 c1 01 add cx, 0x1 0x00003f │ │ │ │ d1 e1 shl cx, 0x1 0x000041 │ │ │ │ 01 ca add dx, cx 0x000043 │ │ │ │ 89 d7 mov di, dx 0x000045 │ │ │ │ 8b 1d mov bx, word [di] 0x000047 │ │ │ │ 39 d8 cmp ax, bx 0x000049 ─╮ │ │ │ │ 7e 43 jng 0x8e 0x00004b │ │ │ │ │ 8d 5e 04 lea bx, word [bp+4] 0x00004e │ │ │ │ │ 8b 46 fc mov ax, word [bp-4] 0x000051 │ │ │ │ │ 89 c1 mov cx, ax 0x000053 │ │ │ │ │ d1 e0 shl ax, 0x1 0x000055 │ │ │ │ │ 89 da mov dx, bx 0x000057 │ │ │ │ │ 01 c3 add bx, ax 0x000059 │ │ │ │ │ 8b 07 mov ax, word [bx] 0x00005b │ │ │ │ │ 89 46 fa mov word [bp-6], ax 0x00005e │ │ │ │ │ 89 c8 mov ax, cx 0x000060 │ │ │ │ │ d1 e1 shl cx, 0x1 0x000062 │ │ │ │ │ 89 d3 mov bx, dx 0x000064 │ │ │ │ │ 01 ca add dx, cx 0x000066 │ │ │ │ │ 89 c1 mov cx, ax 0x000068 │ │ │ │ │ 05 01 00 add ax, 0x1 0x00006b │ │ │ │ │ d1 e0 shl ax, 0x1 0x00006d │ │ │ │ │ 89 46 f8 mov word [bp-8], ax 0x000070 │ │ │ │ │ 89 d8 mov ax, bx 0x000072 │ │ │ │ │ 01 c3 add bx, ax 0x000074 │ │ │ │ │ 89 46 f6 mov word [bp-10], ax 0x000077 │ │ │ │ │ 8b 07 mov ax, word [bx] 0x000079 │ │ │ │ │ 89 d7 mov di, dx 0x00007b │ │ │ │ │ 89 05 mov word [di], ax 0x00007d │ │ │ │ │ 83 c1 01 add cx, 0x1 0x000080 │ │ │ │ │ d1 e1 shl cx, 0x1 0x000082 │ │ │ │ │ 8b 56 f6 mov dx, word [bp-10] 0x000085 │ │ │ │ │ 01 ca add dx, cx 0x000087 │ │ │ │ │ 89 d6 mov si, dx 0x000089 │ │ │ │ │ 8b 56 fa mov dx, word [bp-6] 0x00008c │ │ │ │ │ 89 14 mov word [si], dx 0x00008e <╯ │ │ │ │ 8b 46 fc mov ax, word [bp-4] 0x000091 │ │ │ │ 05 01 00 add ax, 0x1 0x000094 │ │ │ │ 89 46 fc mov word [bp-4], ax 0x000097 ───┼─┼─╯ │ eb 83 jmp 0x1c 0x000099 <──┼─╯ │ 8b 46 fe mov ax, word [bp-2] 0x00009c │ │ 05 01 00 add ax, 0x1 0x00009f │ │ 89 46 fe mov word [bp-2], ax 0x0000a2 ───┼─────╯ e9 6b ff jmp 0x10 0x0000a5 <──╯ 89 ec mov sp, bp 0x0000a7 5d pop bp 0x0000a8 c2 04 00 ret 0x4

Printing BIOS charset

Printing BIOS charset:

  1. const char* VRAM_ADDR = 0xB800;
  2. const char* KERNEL_INIT_MESSAGES[] = {
  3. "Tiny kernel!",
  4. "Charset table:"
  5. };
  6. struct Vec2 {
  7. int x, y;
  8. };
  9. struct Vec2 kernel_screen_cursor = {
  10. .x = 0,
  11. .y = 0,
  12. };
  13. int strlen(const char* str) {
  14. for (int i = 0;;++i) {
  15. if (*(str + i) == 0) {
  16. return i;
  17. }
  18. }
  19. return -1;
  20. }
  21. void kernel_screen_clear() {
  22. asm(
  23. "mov cx, 0x7d0\n"
  24. "mov ax, 0xF00\n"
  25. "mov dx, 0xB800\n"
  26. "mov es, dx\n"
  27. "xor di, di\n"
  28. "rep stosw\n"
  29. );
  30. }
  31. void kernel_print_char_at(int x, int y, char color, char letter) {
  32. const int offset = (y * 80 + x) * 2;
  33. asm(
  34. "mov gs, %[vram]\n"
  35. "mov dl, %[color]\n"
  36. "mov dh, %[letter]\n"
  37. "mov bx, %[offset]\n"
  38. "mov byte [gs:bx + 1], dl\n"
  39. "mov byte [gs:bx], dh\n"
  40. ::
  41. [vram] "r" (VRAM_ADDR),
  42. [offset] "m" (offset),
  43. [letter] "m" (letter),
  44. [color] "m" (color)
  45. : "dx", "bx", "gs"
  46. );
  47. }
  48. void kernel_screen_print_at(int x, int y, char color, const char* str) {
  49. const int len = strlen(str);
  50. for (int i = 0; i < len; ++i) {
  51. kernel_print_char_at(x + i, y, color, str[i]);
  52. }
  53. }
  54. void kernel_screen_newline() {
  55. kernel_screen_cursor.x = 0;
  56. kernel_screen_cursor.y++;
  57. }
  58. void kernel_screen_println(char color, const char* str) {
  59. kernel_screen_print_at(
  60. kernel_screen_cursor.x,
  61. kernel_screen_cursor.y,
  62. color,
  63. str
  64. );
  65. kernel_screen_newline();
  66. }
  67. void main() {
  68. kernel_screen_clear();
  69. for (int i = 0; i < 0x2; ++i) {
  70. kernel_screen_println(0xF, KERNEL_INIT_MESSAGES[i]);
  71. }
  72. kernel_screen_newline();
  73. for (int x = 0; x < 0xFF; ++x) {
  74. kernel_print_char_at(x, kernel_screen_cursor.y, 0xF, 0x1 + x);
  75. }
  76. }

IR Output

ruby # --- Block strlen --- def strlen(str{0}: const char**2B): [ret: int2B] i{0}: int*2B = alloca int2B *(i{0}: int*2B) = store %0: int2B L1: %t{2}: const char*2B = load str{0}: const char**2B %t{3}: int2B = load i{0}: int*2B %t{4}: const char*2B = %t{2}: const char*2B plus %t{3}: int2B %t{5}: const char1B = load %t{4}: const char*2B %t{6}: i1:zf = icmp %t{5}: const char1B equal %0: char1B br %t{6}: i1:zf, false: L4 L5: %t{7}: int2B = load i{0}: int*2B ret %t{7}: int2B L4: %t{0}: int2B = load i{0}: int*2B %t{1}: int2B = %t{0}: int2B plus %1: int2B *(i{0}: int*2B) = store %t{1}: int2B jmp L1 L3: ret %-1: char1B end-def # --- Block kernel_screen_clear --- def kernel_screen_clear(): asm "mov cx, 0x7d0 mov ax, 0xF00 mov dx, 0xB800 mov es, dx xor di, di rep stosw " ret end-def # --- Block kernel_print_char_at --- def kernel_print_char_at(x{0}: int*2B, y{0}: int*2B, color{0}: char*2B, letter{0}: char*2B): offset{0}: const int*2B = alloca const int2B %t{9}: int2B = load y{0}: int*2B %t{10}: int2B = %t{9}: int2B mul %80: char1B %t{11}: int2B = load x{0}: int*2B %t{12}: int2B = %t{10}: int2B plus %t{11}: int2B %t{13}: int2B = %t{12}: int2B mul %2: char1B *(offset{0}: const int*2B) = store %t{13}: int2B %t{14}: const char**2B = label-offset c{0} %t{15}: const char*2B = load %t{14}: const char**2B %t{16}: const int2B = load offset{0}: const int*2B %t{17}: char1B = load letter{0}: char*2B %t{18}: char1B = load color{0}: char*2B asm "mov gs, %[vram] mov dl, %[color] mov dh, %[letter] mov bx, %[offset] mov byte [gs:bx + 1], dl mov byte [gs:bx], dh " ret end-def # --- Block kernel_screen_print_at --- def kernel_screen_print_at(x{1}: int*2B, y{1}: int*2B, color{1}: char*2B, str{1}: const char**2B): len{0}: const int*2B = alloca const int2B %t{20}: const char*2B = load str{1}: const char**2B %t{21}: int2B = call label-offset strlen :: (%t{20}: const char*2B) *(len{0}: const int*2B) = store %t{21}: int2B i{0}: int*2B = alloca int2B *(i{0}: int*2B) = store %0: int2B L6: %t{22}: int2B = load i{0}: int*2B %t{23}: const int2B = load len{0}: const int*2B %t{24}: i1:zf = icmp %t{22}: int2B less_than %t{23}: const int2B br %t{24}: i1:zf, true: L7, false: L8 L7: %t{28}: int2B = load x{1}: int*2B %t{29}: int2B = load i{0}: int*2B %t{30}: int2B = %t{28}: int2B plus %t{29}: int2B %t{31}: int2B = load y{1}: int*2B %t{32}: char1B = load color{1}: char*2B %t{33}: const char*2B = load str{1}: const char**2B %t{35}: const char*2B = %t{29}: int2B mul %1: int2B %t{36}: const char*2B = %t{33}: const char*2B plus %t{35}: const char*2B %t{37}: const char1B = load %t{36}: const char*2B call label-offset kernel_print_char_at :: (%t{30}: int2B, %t{31}: int2B, %t{32}: char1B, %t{37}: const char1B) %t{26}: int2B = %t{29}: int2B plus %1: int2B *(i{0}: int*2B) = store %t{26}: int2B jmp L6 L8: ret end-def # --- Block kernel_screen_newline --- def kernel_screen_newline(): %t{38}: struct Vec2*2B = label-offset c{2} *(%t{38}: int*2B) = store %0: char1B %t{40}: int*2B = %t{38}: struct Vec2*2B plus %2: int2B %t{41}: int2B = load %t{40}: int*2B %t{42}: int2B = %t{41}: int2B plus %1: int2B *(%t{40}: int*2B) = store %t{42}: int2B ret end-def # --- Block kernel_screen_println --- def kernel_screen_println(color{1}: char*2B, str{1}: const char**2B): %t{44}: struct Vec2*2B = label-offset c{2} %t{45}: int2B = load %t{44}: int*2B %t{47}: int*2B = %t{44}: struct Vec2*2B plus %2: int2B %t{48}: int2B = load %t{47}: int*2B %t{49}: char1B = load color{1}: char*2B %t{50}: const char*2B = load str{1}: const char**2B call label-offset kernel_screen_print_at :: (%t{45}: int2B, %t{48}: int2B, %t{49}: char1B, %t{50}: const char*2B) call label-offset kernel_screen_newline :: () ret end-def # --- Block main --- def main(): call label-offset kernel_screen_clear :: () i{0}: int*2B = alloca int2B *(i{0}: int*2B) = store %0: int2B L9: %t{53}: int2B = load i{0}: int*2B %t{54}: i1:zf = icmp %t{53}: int2B less_than %2: char1B br %t{54}: i1:zf, true: L10, false: L11 L10: %t{58}: const char*[2]*2B = label-offset c{1} %t{59}: int2B = load i{0}: int*2B %t{60}: const char*[2]*2B = %t{59}: int2B mul %2: int2B %t{61}: const char*[2]*2B = %t{58}: const char*[2]*2B plus %t{60}: const char*[2]*2B %t{62}: const char*2B = load %t{61}: const char*[2]*2B call label-offset kernel_screen_println :: (%15: char1B, %t{62}: const char*2B) %t{56}: int2B = %t{59}: int2B plus %1: int2B *(i{0}: int*2B) = store %t{56}: int2B jmp L9 L11: call label-offset kernel_screen_newline :: () %1_x{0}: int*2B = alloca int2B *(%1_x{0}: int*2B) = store %0: int2B L12: %t{64}: int2B = load %1_x{0}: int*2B %t{65}: i1:zf = icmp %t{64}: int2B less_than %255: char1B br %t{65}: i1:zf, true: L13, false: L14 L13: %t{69}: int2B = load %1_x{0}: int*2B %t{70}: struct Vec2*2B = label-offset c{2} %t{71}: int*2B = %t{70}: struct Vec2*2B plus %2: int2B %t{72}: int2B = load %t{71}: int*2B %t{74}: int2B = %t{69}: int2B plus %1: char1B call label-offset kernel_print_char_at :: (%t{69}: int2B, %t{72}: int2B, %15: char1B, %t{74}: int2B) %t{67}: int2B = %t{69}: int2B plus %1: int2B *(%1_x{0}: int*2B) = store %t{67}: int2B jmp L12 L14: ret end-def # --- Block Data --- c{0}: const char**2B = const { 47104 } c{1}: const char*[2]*2B = const { Tiny kernel!, Charset table: } c{2}: struct Vec2*2B = const { 0, 0 }


Binary output

asm 0x000000 <────╮ 55 push bp 0x000001 │ 89 e5 mov bp, sp 0x000003 │ 83 ec 02 sub sp, 0x2 0x000006 │ c7 46 fe 00 00 mov word [bp-2], 0x0 0x00000b <──╮ │ 8b 5e 04 mov bx, word [bp+4] 0x00000e │ │ 03 5e fe add bx, word [bp-2] 0x000011 │ │ 8a 07 mov al, byte [bx] 0x000013 │ │ 3c 00 cmp al, 0x0 0x000015 ─╮ │ │ 75 09 jnz 0x20 0x000017 │ │ │ 8b 46 fe mov ax, word [bp-2] 0x00001a │ │ │ 89 ec mov sp, bp 0x00001c │ │ │ 5d pop bp 0x00001d │ │ │ c2 02 00 ret 0x2 0x000020 <╯ │ │ 8b 46 fe mov ax, word [bp-2] 0x000023 │ │ 05 01 00 add ax, 0x1 0x000026 │ │ 89 46 fe mov word [bp-2], ax 0x000029 ───╯ │ eb e0 jmp 0xb 0x00002b │ b8 ff ff mov ax, -0x1 0x00002e │ 89 ec mov sp, bp 0x000030 │ 5d pop bp 0x000031 │ c2 02 00 ret 0x2 0x000034 <────┼─────╮ 55 push bp 0x000035 │ │ 89 e5 mov bp, sp 0x000037 │ │ b9 d0 07 mov cx, 0x7d0 0x00003a │ │ b8 00 0f mov ax, 0xf00 0x00003d │ │ ba 00 b8 mov dx, 0xb800 0x000040 │ │ 8e c2 mov es, dx 0x000042 │ │ 31 ff xor di, di 0x000044 │ │ f3 ab repz stosw 0x000046 │ │ 89 ec mov sp, bp 0x000048 │ │ 5d pop bp 0x000049 │ │ c3 ret 0x00004a <────┼─╮<──┼───╮ 55 push bp 0x00004b │ │ │ │ 89 e5 mov bp, sp 0x00004d │ │ │ │ 83 ec 02 sub sp, 0x2 0x000050 │ │ │ │ 8b 46 06 mov ax, word [bp+6] 0x000053 │ │ │ │ 6b c0 50 imul ax, ax, 0x50 0x000056 │ │ │ │ 03 46 04 add ax, word [bp+4] 0x000059 │ │ │ │ d1 e0 shl ax, 0x1 0x00005b │ │ │ │ 89 46 fe mov word [bp-2], ax 0x00005e │ │ │ │ 8b 1e 7e 01 mov bx, word [@@_c_0_] 0x000062 │ │ │ │ 8e eb mov gs, bx 0x000064 │ │ │ │ 8a 56 08 mov dl, byte [bp+8] 0x000067 │ │ │ │ 8a 76 0a mov dh, byte [bp+10] 0x00006a │ │ │ │ 8b 5e fe mov bx, word [bp-2] 0x00006d │ │ │ │ 65 88 57 01 mov byte [gs:bx+1], dl 0x000071 │ │ │ │ 65 88 37 mov byte [gs:bx], dh 0x000074 │ │ │ │ 89 ec mov sp, bp 0x000076 │ │ │ │ 5d pop bp 0x000077 │ │ │ │ c2 08 00 ret 0x8 0x00007a <────┼─┼─╮ │ │ 55 push bp 0x00007b │ │ │ │ │ 89 e5 mov bp, sp 0x00007d │ │ │ │ │ 83 ec 04 sub sp, 0x4 0x000080 │ │ │ │ │ 8b 5e 0a mov bx, word [bp+10] 0x000083 │ │ │ │ │ 53 push bx 0x000084 ─────╯ │ │ │ │ e8 79 ff call 0x0 0x000087 │ │ │ │ 89 46 fe mov word [bp-2], ax 0x00008a │ │ │ │ c7 46 fc 00 00 mov word [bp-4], 0x0 0x00008f <────╮ │ │ │ │ 8b 46 fe mov ax, word [bp-2] 0x000092 │ │ │ │ │ 39 46 fc cmp word [bp-4], ax 0x000095 ─╮ │ │ │ │ │ 7c 02 jl 0x99 0x000097 ─┼─╮ │ │ │ │ │ 7d 2c jge 0xc5 0x000099 <╯ │ │ │ │ │ │ 8b 46 04 mov ax, word [bp+4] 0x00009c │ │ │ │ │ │ 03 46 fc add ax, word [bp-4] 0x00009f │ │ │ │ │ │ 8b 5e 0a mov bx, word [bp+10] 0x0000a2 │ │ │ │ │ │ 03 5e fc add bx, word [bp-4] 0x0000a5 │ │ │ │ │ │ 8a 0f mov cl, byte [bx] 0x0000a7 │ │ │ │ │ │ 0f b6 d1 movzx dx, cl 0x0000aa │ │ │ │ │ │ 52 push dx 0x0000ab │ │ │ │ │ │ 8b 4e 08 mov cx, word [bp+8] 0x0000ae │ │ │ │ │ │ 81 e1 ff 00 and cx, 0xff 0x0000b2 │ │ │ │ │ │ 51 push cx 0x0000b3 │ │ │ │ │ │ ff 76 06 push word [bp+6] 0x0000b6 │ │ │ │ │ │ 50 push ax 0x0000b7 ───┼─┼─╯ │ │ │ e8 90 ff call 0x4a 0x0000ba │ │ │ │ │ 8b 46 fc mov ax, word [bp-4] 0x0000bd │ │ │ │ │ 05 01 00 add ax, 0x1 0x0000c0 │ │ │ │ │ 89 46 fc mov word [bp-4], ax 0x0000c3 ───┼─╯ │ │ │ eb ca jmp 0x8f 0x0000c5 <──╯ │ │ │ 89 ec mov sp, bp 0x0000c7 │ │ │ 5d pop bp 0x0000c8 │ │ │ c2 08 00 ret 0x8 0x0000cb <╮<──────┼─┼─╮ │ 55 push bp 0x0000cc │ │ │ │ │ 89 e5 mov bp, sp 0x0000ce │ │ │ │ │ c7 06 a2 01 00 00 mov word [@@_c_2_], 0x0 0x0000d4 │ │ │ │ │ b8 a2 01 mov ax, 0x1a2 0x0000d7 │ │ │ │ │ 05 02 00 add ax, 0x2 0x0000da │ │ │ │ │ 89 c7 mov di, ax 0x0000dc │ │ │ │ │ 8b 1d mov bx, word [di] 0x0000de │ │ │ │ │ 83 c3 01 add bx, 0x1 0x0000e1 │ │ │ │ │ 89 1d mov word [di], bx 0x0000e3 │ │ │ │ │ 89 ec mov sp, bp 0x0000e5 │ │ │ │ │ 5d pop bp 0x0000e6 │ │ │ │ │ c3 ret 0x0000e7 <┼───╮ │ │ │ │ 55 push bp 0x0000e8 │ │ │ │ │ │ 89 e5 mov bp, sp 0x0000ea │ │ │ │ │ │ a1 a2 01 mov ax, ds:@@_c_2_ 0x0000ed │ │ │ │ │ │ bb a2 01 mov bx, 0x1a2 0x0000f0 │ │ │ │ │ │ 83 c3 02 add bx, 0x2 0x0000f3 │ │ │ │ │ │ 8b 0f mov cx, word [bx] 0x0000f5 │ │ │ │ │ │ 8b 7e 06 mov di, word [bp+6] 0x0000f8 │ │ │ │ │ │ 57 push di 0x0000f9 │ │ │ │ │ │ 8b 56 04 mov dx, word [bp+4] 0x0000fc │ │ │ │ │ │ 81 e2 ff 00 and dx, 0xff 0x000100 │ │ │ │ │ │ 52 push dx 0x000101 │ │ │ │ │ │ 51 push cx 0x000102 │ │ │ │ │ │ 50 push ax 0x000103 ─┼───┼───╯ │ │ │ e8 74 ff call 0x7a 0x000106 ─╯ │ │ │ │ e8 c2 ff call 0xcb 0x000109 │ │ │ │ 89 ec mov sp, bp 0x00010b │ │ │ │ 5d pop bp 0x00010c │ │ │ │ c2 04 00 ret 0x4 0x00010f │ │ │ │ 55 push bp 0x000110 │ │ │ │ 89 e5 mov bp, sp 0x000112 │ │ │ │ 83 ec 04 sub sp, 0x4 0x000115 ─────┼─────╯ │ │ e8 1c ff call 0x34 0x000118 │ │ │ c7 46 fe 00 00 mov word [bp-2], 0x0 0x00011d <────┼─╮ │ │ 83 7e fe 02 cmp word [bp-2], 0x2 0x000121 ─╮ │ │ │ │ 7c 02 jl 0x125 0x000123 ─┼─╮ │ │ │ │ 7d 20 jge 0x145 0x000125 <╯ │ │ │ │ │ 8b 46 fe mov ax, word [bp-2] 0x000128 │ │ │ │ │ 89 c3 mov bx, ax 0x00012a │ │ │ │ │ d1 e0 shl ax, 0x1 0x00012c │ │ │ │ │ b9 80 01 mov cx, 0x180 0x00012f │ │ │ │ │ 01 c1 add cx, ax 0x000131 │ │ │ │ │ 89 cf mov di, cx 0x000133 │ │ │ │ │ 8b 15 mov dx, word [di] 0x000135 │ │ │ │ │ 53 push bx 0x000136 │ │ │ │ │ 52 push dx 0x000137 │ │ │ │ │ 6a 0f push 0xf 0x000139 ───┼─╯ │ │ │ e8 ab ff call 0xe7 0x00013c │ │ │ │ 5b pop bx 0x00013d │ │ │ │ 83 c3 01 add bx, 0x1 0x000140 │ │ │ │ 89 5e fe mov word [bp-2], bx 0x000143 ───┼───╯ │ │ eb d8 jmp 0x11d 0x000145 <──╯─────────╯ │ e8 83 ff call 0xcb 0x000148 │ c7 46 fc 00 00 mov word [bp-4], 0x0 0x00014d <────╮ │ 81 7e fc ff 00 cmp word [bp-4], 0xff 0x000152 ─╮ │ │ 7c 02 jl 0x156 0x000154 ─┼─╮ │ │ 7d 24 jge 0x17a 0x000156 <╯ │ │ │ b8 a2 01 mov ax, 0x1a2 0x000159 │ │ │ 05 02 00 add ax, 0x2 0x00015c │ │ │ 89 c7 mov di, ax 0x00015e │ │ │ 8b 1d mov bx, word [di] 0x000160 │ │ │ 8b 46 fc mov ax, word [bp-4] 0x000163 │ │ │ 89 c1 mov cx, ax 0x000165 │ │ │ 05 01 00 add ax, 0x1 0x000168 │ │ │ 51 push cx 0x000169 │ │ │ 50 push ax 0x00016a │ │ │ 6a 0f push 0xf 0x00016c │ │ │ 53 push bx 0x00016d │ │ │ 51 push cx 0x00016e ───┼─┼─────────╯ e8 d9 fe call 0x4a 0x000171 │ │ 59 pop cx 0x000172 │ │ 83 c1 01 add cx, 0x1 0x000175 │ │ 89 4e fc mov word [bp-4], cx 0x000178 ───┼─╯ eb d3 jmp 0x14d 0x00017a <──╯ 89 ec mov sp, bp 0x00017c 5d pop bp 0x00017d c3 ret 0x00017e 00 b8 dw 47104 0x000180 84 01 dw @@_c_1_@str$0_0 0x000182 92 01 dw @@_c_1_@str$0_1 0x000184 54 69 6e 79 20 6b 65 72 db "tiny kernel!", 0x0 6e 65 6c 21 00 00 0x000192 43 68 61 72 73 65 74 20 db "charset table:", 0x0 74 61 62 6c 65 3a 00 00 0x0001a2 00 00 00 00 dw 0, 0

ASM syntax

It’s pretty similar to NASM syntax (including preprocessor), examples:

https://github.com/Mati365/i8086.js/tree/master/packages/x86-assembler/tests/asm

Architecture

Multipass steps

X86 Arch support

  • [x] 16bit real mode X86 arch support

    • [x] X86 16bit Multipass Assembler compatible with NASM syntax (source)

      • Preprocessor (source) compatible with NASM that supports:
        • Conditions and definitions: %if, %ifn, %ifdef, %ifndef, %else, %elif, %elifndef, %elifdef, %elifn, %define, %undef
        • Macros: %macro, %define, %imacro
        • Predefined variables: __TIMES__
        • Inline expressions calls: %[__TIMES__]
    • [x] X86 CPU 16bit Intel 8086 virtual machine (source)

      • VGA graphical mode support (source)
      • VGA text mode support (source)

Current progress

  • C compiler
    • Frontend
      • Syntax parser
      • Typechecker
      • IR code generator
    • Backend
      • IR optimizer
      • X86-16 Code generator
        • Register allocator
          • Basic allocation using ownership checking
          • Spilling regs and detection lifetime of IR vars
        • Compile math integer instruction
          • Compile *, +, -, /
          • Compile <<, >>
          • Compile xor / and / or / not
        • Compile if stmts
        • Compile loops while {}, do { } while, for (...) {}
        • Compile typedefs
        • Compile pointers
          • Basic pointer access *k = 5
          • Array access k[4]
        • Compile function calls
        • Compile asm tag
          • Basic asm tag without args
          • asm tag with arguments
        • Unions
        • Preprocessor
        • Stdlib
  • ASM Compiler
    • NASM syntax instruction compiler matcher with expression eval mov ax, byte [ds:label+bx+12+(1/3)]
    • Instruction prefix support rep movsw
    • Compiler bits/org config [bits 16], [org 0x7C00]
    • Labels support jmp_label:
    • Data define support db, dw, dd, dq, dt
    • EQU, times support
    • Floating point numbers support
    • Preprocessor
      • Basic lang keywords support: %if, %ifn, %ifdef, %ifndef, %else, %elif, %elifndef, %elifdef, %elifn, %define, %undef
      • Macros support: %macro, %define, %imacro
      • Predefined macros like __TIMES__
      • Inline expressions calls %[__TIMES__]
    • Output logger
      • Basic logger binary blob serializer helpers
      • Diassembler binary view
      • Branch arrows (for jmp, call, jz etc.)
  • CPU Emulator
    • Magic breakpoint support xchg bx, bx
    • Interrupts handlers support
    • Basic Intel ~80186 instructions set
    • ALU instructions support
    • FPU Support
      • Assembler
      • Emulator
    • Basic PIT/PIC support
      • PIT
      • PIC
      • IDE
      • PS2
    • Graphics mode
      • Basic canvas graphics driver
      • Text Mode
      • Graphics VGA
      • VGA IO ports bindings
    • BIOS
      • Basic bios interrupt handlers
  • App frontend
    • Basic front CSS UI
    • Debugger

Screens

C Compiler Hello World
C Compiler Advanced Expressions
C Compiler Assembly
C Compiler IR
C Compiler IR
Pillman
Space invaders
Prototype
Prototype
Tetris
ASM Preprocessor
ASM Compiler
C Compiler

Docs

https://cs.lmu.edu/~ray/notes/ir

https://www.youtube.com/watch?v=yTXCPGAD3SQ

https://books.google.pl/books?id=Lq4yDwAAQBAJ&pg=PA120&lpg=PA120&dq=chain4+mode&source=bl&ots=Eun_wNFE7b&sig=ACfU3U37tSXE7qOZn0AKGeFwaaNLS4nrKg&hl=pl&sa=X&ved=2ahUKEwjlupT5-u_pAhVNxhoKHVfRA7YQ6AEwAnoECAoQAQ#v=onepage&q=chain4%20mode&f=false

https://bellard.org/otcc/otccn.c

https://bellard.org/otcc

https://gist.github.com/nikAizuddin/0e307cac142792dcdeba

http://www.plantation-productions.com/Webster/www.artofasm.com/Windows/HTML/RealArithmetica3.html

https://gist.github.com/mikesmullin/6259449

http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt

http://ece425web.groups.et.byu.net/stable/labs/8086Assembly.html

http://dsearls.org/courses/C391OrgSys/IntelAL/8086_instruction_set.html

https://pdos.csail.mit.edu/6.828/2008/readings/i386/s17_02.htm

https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol1/o_7281d5ea06a5b67a-194.html

https://johnloomis.org/ece314/notes/fpu/fpu.pdf

https://www.felixcloutier.com/x86/index.html

https://c9x.me/x86/html/file_module_x86_id_87.html

http://www.osdever.net/FreeVGA/vga/graphreg.htm#06

http://www.osdever.net/FreeVGA/vga/vgamem.htm

http://www.osdever.net/FreeVGA/home.htm

License

The MIT License (MIT)
Copyright (c) 2023/2024 Mateusz Bagiński

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.