Started work on x86 AHOT
This commit is contained in:
parent
fde87a9aa7
commit
7626f83e90
16
.gitignore
vendored
16
.gitignore
vendored
|
@ -4,11 +4,19 @@ htmldocs
|
|||
acdump
|
||||
src/arctic/handle_syscalls.nim
|
||||
syscalls.json
|
||||
obj/
|
||||
|
||||
# Documentation artefacts
|
||||
doc/documentation.html
|
||||
doc/documentation.tex
|
||||
doc/documentation.pdf
|
||||
# Generated sources
|
||||
src/arch/x86_64.h
|
||||
|
||||
# Documentation artifacts
|
||||
documentation.html
|
||||
documentation.tex
|
||||
documentation.pdf
|
||||
overview.html
|
||||
overview.tex
|
||||
overview.pdf
|
||||
cheatsheet.pdf
|
||||
|
||||
# LaTeX garbage
|
||||
*.log
|
||||
|
|
83
Makefile
83
Makefile
|
@ -1,22 +1,91 @@
|
|||
.PHONY: default
|
||||
.SUFFIXES:
|
||||
MAKEFLAGS+=--no-builtin-rules
|
||||
|
||||
default: docs
|
||||
NODEPS=clean
|
||||
|
||||
OBJECT_DIR=obj
|
||||
SOURCE_DIR=src
|
||||
|
||||
EMPTY:=
|
||||
SPACE:=$(EMPTY) $(EMPTY)
|
||||
COMMA:=,
|
||||
|
||||
default: all
|
||||
all: docs arctic
|
||||
|
||||
DOCUMENTS=$(shell find doc/ -name '*.md')
|
||||
|
||||
HTMLDOCS=$(patsubst %.md,%.html,$(DOCUMENTS))
|
||||
PDFDOCS=$(patsubst %.md,%.pdf,$(DOCUMENTS))
|
||||
HTMLDOCS=$(patsubst doc/%.md,%.html,$(DOCUMENTS))
|
||||
PDFDOCS=$(patsubst doc/%.md,%.pdf,$(DOCUMENTS)) cheatsheet.pdf
|
||||
|
||||
docs: $(HTMLDOCS) $(PDFDOCS)
|
||||
|
||||
%.html: %.md
|
||||
%.html: doc/%.md
|
||||
multimarkdown -t html $^ -o $@
|
||||
|
||||
%.tex: %.md
|
||||
multimarkdown -t latex $^ -o $@
|
||||
multimarkdown -t latex $^ | sed 's/^\[/{[}/g' > $@
|
||||
|
||||
%.pdf: %.tex doc/arctic-leader.tex doc/arctic-begin.tex doc/arctic-footer.tex
|
||||
cd $$(dirname $<) && xelatex -interaction=batchmode $<
|
||||
%.pdf: doc/%.tex doc/arctic-leader.tex doc/arctic-begin.tex doc/arctic-footer.tex
|
||||
# cd doc && latexmk -pdf -xelatex -use-make $*.tex && mv $*.pdf ../
|
||||
cd $$(dirname $<) && xelatex -interaction=batchmode $*.tex && mv $*.pdf ../
|
||||
|
||||
GENERATED_M4=$(shell find $(SOURCE_DIR)/ -name '*.m4')
|
||||
GENERATED_FS=$(patsubst %.m4,%,$(GENERATED_M4))
|
||||
|
||||
%: %.m4 misc/utils.m4
|
||||
m4 $< > $@
|
||||
|
||||
# TODO: fix the structure so this is easier. the JIT libs should become ASM
|
||||
# libs, while the actual JIT sources only get included on whatever the native
|
||||
# arch is (tunable with ARCH=... in make)
|
||||
MAIN_SOURCES=$(shell find $(SOURCE_DIR)/ -name '*.c' -not -path '$(SOURCE_DIR)/jit/*')
|
||||
MAIN_OBJECTS=$(patsubst $(SOURCE_DIR)/%.c,$(OBJECT_DIR)/%.o,$(MAIN_SOURCES))
|
||||
MAIN_DEPENDS=$(patsubst $(SOURCE_DIR)/%.c,$(OBJECT_DIR)/%.d,$(MAIN_SOURCES))
|
||||
|
||||
ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
|
||||
ifeq (,$(findstring print-,$(MAKECMDGOALS)))
|
||||
$(info Including depends files: $(MAIN_DEPENDS))
|
||||
include $(MAIN_DEPENDS)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(OBJECT_DIR):
|
||||
mkdir $@
|
||||
|
||||
$(OBJECT_DIR)/%.d: $(SOURCE_DIR)/%.c | $(OBJECT_DIR) $(GENERATED_FS)
|
||||
$(CC) $(CFLAGS) -MM -MT '$(patsubst $(SOURCE_DIR)/%.c,$(OBJECT_DIR)/%.o,$<)' $< -MF $@
|
||||
|
||||
$(OBJECT_DIR)/%.o: $(SOURCE_DIR)/%.c | $(OBJECT_DIR)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
arctic: $(MAIN_OBJECTS)
|
||||
$(CC) $(LDFLAGS) $^ -o $@
|
||||
|
||||
X86_64_BIT_REGISTERS=RAX RBX RCX RDX RSI RDI RBP RSP R8 R9 R10 R11 R12 R13 R14 R15
|
||||
src/jit/x86_64_mov_opcodes.h:
|
||||
echo '#ifndef X86_64_MOV_OPCODES_H' > $@
|
||||
echo '#define X86_64_MOV_OPCODES_H' >> $@
|
||||
echo >> $@
|
||||
for dstreg in {$(subst $(SPACE),$(COMMA),$(X86_64_BIT_REGISTERS))}; do \
|
||||
for srcreg in {$(subst $(SPACE),$(COMMA),$(X86_64_BIT_REGISTERS))}; do \
|
||||
echo "mov $$srcreg,$$dstreg" | ./tools/x86_64dump | \
|
||||
sed 's/../ X(0x&)/g' | \
|
||||
sed "s/.*/#define MOV_$${srcreg}_$${dstreg}&/" >> $@; \
|
||||
done; \
|
||||
done
|
||||
echo >> $@
|
||||
echo '#endif /* X86_64_MOV_OPCODES_H */' >> $@
|
||||
|
||||
|
||||
clean:
|
||||
-rm $(patsubst doc/%.md,doc/%.aux,$(DOCUMENTS))
|
||||
-rm $(patsubst doc/%.md,doc/%.xdv,$(DOCUMENTS))
|
||||
-rm $(patsubst doc/%.md,doc/%.out,$(DOCUMENTS))
|
||||
-rm $(MAIN_OBJECTS)
|
||||
-rm $(MAIN_DEPENDS)
|
||||
-rm arctic
|
||||
|
||||
print-%:
|
||||
@echo '$*=$($*)'
|
||||
|
|
116
doc/cheatsheet.tex
Normal file
116
doc/cheatsheet.tex
Normal file
|
@ -0,0 +1,116 @@
|
|||
\documentclass{article}
|
||||
|
||||
\usepackage[letterpaper, landscape, margin=1cm]{geometry}
|
||||
|
||||
\usepackage{tabularx}
|
||||
\usepackage{tabulary}
|
||||
\usepackage{booktabs}
|
||||
\usepackage{tikz}
|
||||
|
||||
\usetikzlibrary{shapes.multipart,positioning}
|
||||
|
||||
\tikzstyle{stack}=[rectangle split, rectangle split parts=#1,draw,anchor=center]
|
||||
|
||||
\newenvironment{opsummary}[2]{%
|
||||
\begin{tikzpicture}
|
||||
\newcommand{\opsummaryshort}{#1}
|
||||
\newcommand{\opsummarylong}{#2}
|
||||
}{%
|
||||
\draw[->, double distance=1pt] (before) -- node[above] {\texttt{\opsummaryshort}} node[below] {\texttt{\opsummarylong}} (after);
|
||||
\end{tikzpicture}
|
||||
}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\begin{tabulary}{\textwidth}{@{}cccccccccccccccc@{}} \toprule
|
||||
\begin{opsummary}{0}{BNEZ}
|
||||
\node[stack=2] (before) {%
|
||||
\nodepart{one}$x$
|
||||
\nodepart{two}\ldots
|
||||
};
|
||||
\node[stack=1,right=of before] (after) {%
|
||||
\nodepart{one}\ldots
|
||||
};
|
||||
\end{opsummary}
|
||||
&
|
||||
|
||||
\begin{opsummary}{1}{LDAB}
|
||||
\node[stack=2] (before) {%
|
||||
\nodepart{one}$p$
|
||||
\nodepart{two}…
|
||||
};
|
||||
\node[stack=2,right=of before] (after) {%
|
||||
\nodepart{one}$x$
|
||||
\nodepart{two}…
|
||||
};
|
||||
\end{opsummary}
|
||||
&
|
||||
|
||||
\begin{opsummary}{2}{LDAS}
|
||||
\node[stack=2] (before) {%
|
||||
\nodepart{one}$p$
|
||||
\nodepart{two}…
|
||||
};
|
||||
\node[stack=2,right=of before] (after) {%
|
||||
\nodepart{one}$x$
|
||||
\nodepart{two}…
|
||||
};
|
||||
\end{opsummary}
|
||||
&
|
||||
|
||||
\begin{opsummary}{3}{LDAI}
|
||||
\node[stack=2] (before) {%
|
||||
\nodepart{one}$p$
|
||||
\nodepart{two}…
|
||||
};
|
||||
\node[stack=2,right=of before] (after) {%
|
||||
\nodepart{one}$x$
|
||||
\nodepart{two}…
|
||||
};
|
||||
\end{opsummary}
|
||||
&
|
||||
|
||||
\begin{opsummary}{4}{LDAW}
|
||||
\node[stack=2] (before) {%
|
||||
\nodepart{one}$p$
|
||||
\nodepart{two}…
|
||||
};
|
||||
\node[stack=2,right=of before] (after) {%
|
||||
\nodepart{one}$x$
|
||||
\nodepart{two}…
|
||||
};
|
||||
\end{opsummary}
|
||||
&
|
||||
|
||||
5 &
|
||||
6 &
|
||||
7 &
|
||||
8 &
|
||||
9 &
|
||||
A &
|
||||
B &
|
||||
C &
|
||||
D &
|
||||
E &
|
||||
F \\
|
||||
|
||||
G &
|
||||
H &
|
||||
I &
|
||||
J &
|
||||
K &
|
||||
L &
|
||||
M &
|
||||
N &
|
||||
O &
|
||||
P &
|
||||
Q &
|
||||
R &
|
||||
S &
|
||||
T &
|
||||
U &
|
||||
V \\
|
||||
|
||||
\end{tabulary}
|
||||
|
||||
\end{document}
|
|
@ -2,7 +2,7 @@
|
|||
Title: ARCTIC Documentation
|
||||
Author: Louis A. Burke
|
||||
Language: en
|
||||
CSS: documentation.css
|
||||
CSS: doc/documentation.css
|
||||
LaTeX Leader: arctic-leader.tex
|
||||
LaTeX Begin: arctic-begin.tex
|
||||
LaTeX Footer: arctic-footer.tex
|
||||
|
@ -15,10 +15,25 @@ LaTeX Header Level: 3
|
|||
|
||||
Like the JVM, but the "binaries" consist of printable ASCII characters and the
|
||||
result can be more easily precompiled for native execution. Also far less safety
|
||||
and verification, feel free to shoot yourself in the foot!
|
||||
and verification, feel free to shoot yourself in the foot.
|
||||
|
||||
## Behaviour
|
||||
|
||||
The behaviour of ARCTIC code is described by how a theoretical virtual machine
|
||||
would interpret it. Any compiler or interpreter that produces the same series of
|
||||
exernal syscalls with the same values and returns the same result as the
|
||||
theoretical virtual machine is considered a compliant ARCTIC implementation.
|
||||
|
||||
This documentation describes the input as a "file", but it actually may consist
|
||||
of multiple files or may be processed from standard input. How an ARCTIC
|
||||
implementation consumes its input is up to each specific implementation, but
|
||||
should be well documented.
|
||||
|
||||
## Structure
|
||||
|
||||
ARCTIC code is divided into sections. In each section, each character represents
|
||||
a different operation.
|
||||
|
||||
### Data Types
|
||||
|
||||
### The Stack
|
||||
|
@ -33,9 +48,10 @@ CODE is BE / LDAx
|
|||
|
||||
Specifically:
|
||||
|
||||
.* is shared file load (" libc.so")
|
||||
A.* is BE atomic data
|
||||
a.* is LE atomic data
|
||||
[bB].* is BSS data
|
||||
[bB].* is BSS data (uninitialized, but allocated)
|
||||
C.* is BE code
|
||||
c.* is LE code
|
||||
D.* is BE data
|
||||
|
@ -46,14 +62,33 @@ e.* is LE externals
|
|||
[gG].* is embedded resource ("get X")
|
||||
[hH].* is embedded resource ("http...")
|
||||
[iI].* is embedded code ("include X")
|
||||
[jJ].* is embedded java ("jvm X")
|
||||
[kK].* is ???
|
||||
[lL].* is embedded arctic file ("load X")
|
||||
M.* is BE macros
|
||||
m.* is LE macros
|
||||
[nN].* is ???
|
||||
O.* is BE register-based code ("OPTIMIZED")
|
||||
o.* is LE register-based code ("optimized")
|
||||
P.* is BE per-thread data (POOL)
|
||||
p.* is LE per-thread data (pool)
|
||||
Q.* is BE quantum code ("QUANTUM")
|
||||
q.* is LE quantum code ("quantum")
|
||||
R.* is BE read-only data
|
||||
r.* is LE read-only data
|
||||
[sS].* is ???
|
||||
[tT].* is ???
|
||||
[uU].* is ???
|
||||
[vV].* is ???
|
||||
[wW].* is load module ("with X")
|
||||
[xX].* is ???
|
||||
[yY].* is ???
|
||||
[zZ].* is ???
|
||||
|
||||
Need better description of data '' format. See QBE's data for inspiration?
|
||||
Consider having each op-code mean something different in different sections?
|
||||
Only consistency would be labels... those could be more universally parsed?
|
||||
Alternatively remove sections altogether and use only dynamic memory?
|
||||
```
|
||||
|
||||
## File Format
|
||||
|
@ -123,12 +158,12 @@ Q |LDOW| … p| ⇒ | … x | load word at p plus immediate o
|
|||
6 |STAS| … p x| → | … | store short x to p
|
||||
7 |STAI| … p x| → | … | store int x to p
|
||||
8 |STAW| … p x| → | … | store word x to p
|
||||
D |MCLR| … p x| → | … | memclear x bytes from p
|
||||
d |MSET| … p x| ⇒ | … | set x bytes of memory to immediate value at p
|
||||
K |MCPY| … p q x| → | … | copy x bytes of memory from p to q
|
||||
D†|MCLR| … p x| → | … | memclear x bytes from p
|
||||
d†|MSET| … p x| ⇒ | … | set x bytes of memory to immediate value at p
|
||||
K†|MCPY| … p q x| → | … | copy x bytes of memory from p to q
|
||||
J |MOFF| … p x| → | … q | set q to memory pointer p shifted by x bytes
|
||||
M |MALL| … p| ⇒ | … p | (re)allocate/free memory for immediate bytes at p
|
||||
R |REAL| … p x| → | … p | (re)allocate/free memory for x bytes at p
|
||||
M†|MALL| … p| ⇒ | … p | (re)allocate/free memory for immediate bytes at p
|
||||
R†|REAL| … p x| → | … p | (re)allocate/free memory for x bytes at p
|
||||
9 |CASS| … p x y| → | … z | compare and swap x and y at p, return success
|
||||
|
||||
#### LDAx
|
||||
|
|
26
doc/overview.md
Normal file
26
doc/overview.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
Title: ARCTIC Documentation
|
||||
Author: Louis A. Burke
|
||||
Language: en
|
||||
CSS: documentation.css
|
||||
LaTeX Leader: arctic-leader.tex
|
||||
LaTeX Begin: arctic-begin.tex
|
||||
LaTeX Footer: arctic-footer.tex
|
||||
LaTeX Header Level: 3
|
||||
---
|
||||
|
||||
# ARCTIC Code
|
||||
|
||||
ASCII Rendered, Cross-Target Invocation Character Codes
|
||||
|
||||
An executable "binary" format consisting of only ASCII characters.
|
||||
|
||||
## Goals
|
||||
|
||||
The priorities of this project are:
|
||||
|
||||
- Reasonable performance
|
||||
- Easy to compile to
|
||||
- Reasonable to hand-write
|
||||
- Reasonable to debug
|
||||
- Possible to interface to native environments
|
50
misc/utils.m4
Normal file
50
misc/utils.m4
Normal file
|
@ -0,0 +1,50 @@
|
|||
divert(`-1')dnl
|
||||
#changequote(`[', `]')dnl
|
||||
|
||||
define(`TICK', changequote([,])[changequote([,])'changequote(`,')]changequote(`,'))
|
||||
|
||||
# forloop(var, from, to, stmt) - improved version:
|
||||
# works even if VAR is not a strict macro name
|
||||
# performs sanity check that FROM is larger than TO
|
||||
# allows complex numerical expressions in TO and FROM
|
||||
define(`forloop', `ifelse(eval(`($2) <= ($3)'), `1',
|
||||
`pushdef(`$1')_$0(`$1', eval(`$2'),
|
||||
eval(`$3'), `$4')popdef(`$1')')')
|
||||
define(`_forloop',
|
||||
`define(`$1', `$2')$4`'ifelse(`$2', `$3', `',
|
||||
`$0(`$1', incr(`$2'), `$3', `$4')')')
|
||||
|
||||
# foreachq(x, `item_1, item_2, ..., item_n', stmt)
|
||||
# quoted list, version based on forloop
|
||||
define(`foreachq',
|
||||
`ifelse(`$2', `', `', `_$0(`$1', `$3', $2)')')
|
||||
define(`_foreachq',
|
||||
`pushdef(`$1', forloop(`$1', `3', `$#',
|
||||
`$0_(`1', `2', indir(`$1'))')`popdef(
|
||||
`$1')')indir(`$1', $@)')
|
||||
define(`_foreachq_',
|
||||
``define(`$$1', `$$3')$$2`''')
|
||||
|
||||
# foreach(x, (item_1, item_2, ..., item_n), stmt)
|
||||
# parenthesized list, improved version
|
||||
define(`foreach', `pushdef(`$1')_$0(`$1',
|
||||
(dquote(dquote_elt$2)), `$3')popdef(`$1')')
|
||||
define(`_arg1', `$1')
|
||||
define(`_foreach', `ifelse(`$2', `(`')', `',
|
||||
`define(`$1', _arg1$2)$3`'$0(`$1', (dquote(shift$2)), `$3')')')
|
||||
|
||||
# hextox(x)
|
||||
# hexadecimal number to series of X(0xZZ)X(0xZZ)...
|
||||
define(`hextox', `patsubst(`$1', `..', `X(0x\&)')')
|
||||
|
||||
# hashtag(x)
|
||||
# expands to #x
|
||||
define(`hashtag', `changecom()dnl
|
||||
#$1`'dnl
|
||||
changecom(`#')')
|
||||
|
||||
# rtrimn(x, n)
|
||||
# expands to all but the last n characters of x
|
||||
define(`rtrimn', `substr($1, 0, eval(len($1)-$2))')
|
||||
|
||||
divert(`0')dnl
|
11
samples/asm.arx
Normal file
11
samples/asm.arx
Normal file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env arctic
|
||||
|
||||
# This is a basic ARCTIC assembler, written in ARCTIC.
|
||||
|
||||
@main
|
||||
|
||||
"data" # read-only memory
|
||||
:opcodes '"BNEZLDABLDASLDAILDAWSTABSTASSTAISTAWCASSPUTAPUTBPUTCMCLRFTOIBMISLDOILDOSPUTIMOFFMCPYROLLMALLPUTNITOCPICKLDOWREALITOSPUSHCMPUBIORITOWPUTXPUTYPUTZGETAGETBGETCMSETSROTFMODFINVOVERGETIFNEGSPOPBITCFSUBGETNLDOBFMULFDIVFREMFADDSWAPUSHRFABSSDUPGETXGETYGETZINEGITOFIADDISUBIMULIDIVIMODIREMIABSVALUCALLBLTZBLEZBEQZBGEZBGTZJUMPRETNBANDBXORBNOTROTRBSHRCMPICMPFLABLDPTHPACKDATASECTBIFCNOOPBEAT"'
|
||||
|
||||
"state" # initialized read-write memory
|
||||
|
5
share/vim/ftdetect/arctic.vim
Normal file
5
share/vim/ftdetect/arctic.vim
Normal file
|
@ -0,0 +1,5 @@
|
|||
" Description: ARCTIC ftdetect file
|
||||
" Language: ARCTIC (2024)
|
||||
" Maintainer: Louis Burke
|
||||
|
||||
autocmd BufRead,BufNewFile *.arx set filetype=arctic
|
33
share/vim/syntax/arctic.vim
Normal file
33
share/vim/syntax/arctic.vim
Normal file
|
@ -0,0 +1,33 @@
|
|||
" Description: ARCTIC syntax file
|
||||
" Language: ARCTIC (2024)
|
||||
" Maintainer: Louis Burke
|
||||
|
||||
if exists("b:current_syntax") || version < 700
|
||||
finish
|
||||
endif
|
||||
|
||||
let b:current_syntax = "arctic"
|
||||
|
||||
syntax match arcticComment "\v#.*$"
|
||||
highlight link arcticComment Comment
|
||||
|
||||
syntax region arcticData start=/'/ end=/'/
|
||||
highlight link arcticData Character
|
||||
|
||||
syntax region arcticSection start=/"/ end=/"/
|
||||
highlight link arcticSection PreProc
|
||||
|
||||
syntax match arcticLabel "\v:[^ ]*"
|
||||
highlight link arcticLabel Label
|
||||
|
||||
syntax match arcticCall "\v\@[^ ]*"
|
||||
highlight link arcticCall Function
|
||||
|
||||
syntax match arcticConstant "\v\$[^ ]*"
|
||||
highlight link arcticConstant Constant
|
||||
|
||||
syntax match arcticImmediate "\v[][0EFGHLMPQTdou$@<{=}>,`][^ ]*"
|
||||
highlight link arcticImmediate Statement
|
||||
|
||||
syntax match arcticOperator "\v[-123456789ABCDIJKNORSUVWXYZabcefghijklmnpqrstvwxyz_.+*/%\|;&^!?()]"
|
||||
highlight link arcticOperator Operator
|
68
src/arch/x86_64.h.m4
Normal file
68
src/arch/x86_64.h.m4
Normal file
|
@ -0,0 +1,68 @@
|
|||
#ifndef X86_64_H
|
||||
#define X86_64_H
|
||||
|
||||
#include "../utils.h"
|
||||
|
||||
/*******************************************************************************
|
||||
include(`misc/utils.m4')dnl
|
||||
divert(`-1')dnl
|
||||
|
||||
define(`registers', `RAX, RCX, RDX, RBX, R8, R9, R10, R11, R12, R13, R14, R15')
|
||||
|
||||
define(`x86_encoding_of', `translit(esyscmd(`echo 'TICK`$1'TICK` | ./tools/x86_64dump'),`
|
||||
')')
|
||||
define(`assemble', `hextox(x86_encoding_of($1)) Y("$1")')
|
||||
|
||||
divert(`0')dnl
|
||||
|
||||
Types:
|
||||
|
||||
R: registers
|
||||
V: BYTE(X), WORD(X)
|
||||
Q: QWORD(X)
|
||||
|
||||
To use these macros, either define X(x) as (x), to make lists of bytes, or
|
||||
define Y(s) as whatever you want to do with a string literal. Keep the other
|
||||
defined as an empty expansion.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#define PUSH(A_RV) PUSH_ ## A_RV
|
||||
#define POP(A_R) POP_ ## A_R
|
||||
#define MOV(DST_R,SRC_RV) MOV_ ## DST_R ## _ ## SRC_RV
|
||||
#define ADD(DST_R,SRC_RV) ADD_ ## DST_R ## _ ## SRC_RV
|
||||
#define SUB(DST_R,SRC_RV) SUB_ ## DST_R ## _ ## SRC_RV
|
||||
|
||||
/*******************************************************************************
|
||||
Implementations (auto generated):
|
||||
*******************************************************************************/
|
||||
|
||||
#define XX(x) X(BYTE_0xFF(x)) X(BYTE_0xFF00(x))
|
||||
#define XXX(x) X(BYTE_0xFF(x)) X(BYTE_0xFF00(x)) X(BYTE_0xFF0000(x))
|
||||
#define XXXX(x) X(BYTE_0xFF(x)) X(BYTE_0xFF00(x)) X(BYTE_0xFF0000(x)) X(BYTE_0xFF000000(x))
|
||||
foreachq(register, `registers', `hashtag(define) PUSH_`'register`' assemble(`push register')
|
||||
')
|
||||
#define PUSH_BYTE(x) X(0x6a) X(x) Y("push " #x)
|
||||
#define PUSH_WORD(x) X(0x86) XXXX(x) Y("push " #x)
|
||||
|
||||
foreachq(register, `registers', `hashtag(define) POP_`'register`' assemble(`pop register')
|
||||
')
|
||||
foreachq(registera, `registers', `
|
||||
foreachq(registerb, `registers', `ifelse(registera,registerb,,hashtag(define) MOV_`'registera`'_`'registerb`' assemble(`mov registera`,'registerb')
|
||||
)')')
|
||||
foreachq(register, `registers', `hashtag(define) MOV_`'register`'_WORD(x) hextox(rtrimn(x86_encoding_of(`mov 'register`, 0'), 8)) XXXX(x) Y("mov register," hashtag(x))
|
||||
')
|
||||
|
||||
foreachq(registera, `registers', `
|
||||
foreachq(registerb, `registers', `ifelse(registera,registerb,,hashtag(define) ADD_`'registera`'_`'registerb`' assemble(`add registera`,'registerb')
|
||||
)')')
|
||||
foreachq(register, `registers', `hashtag(define) ADD_`'register`'_WORD(x) hextox(rtrimn(x86_encoding_of(`add 'register`, 0x12345678'), 8)) XXXX(x) Y("add register," hashtag(x))
|
||||
')
|
||||
|
||||
foreachq(registera, `registers', `
|
||||
foreachq(registerb, `registers', `ifelse(registera,registerb,,hashtag(define) SUB_`'registera`'_`'registerb`' assemble(`sub registera`,'registerb')
|
||||
)')')
|
||||
foreachq(register, `registers', `hashtag(define) SUB_`'register`'_WORD(x) hextox(rtrimn(x86_encoding_of(`sub 'register`, 0x12345678'), 8)) XXXX(x) Y("sub register," hashtag(x))
|
||||
')
|
||||
|
||||
#endif /* X86_64_H */
|
3
src/architectures.c
Normal file
3
src/architectures.c
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include "architectures.h"
|
||||
|
||||
#include "arch/x86_64.h"
|
8
src/architectures.h
Normal file
8
src/architectures.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef ARCHITECTURES_H
|
||||
#define ARCHITECTURES_H
|
||||
|
||||
enum Architecture {
|
||||
ARCH_NATIVE
|
||||
};
|
||||
|
||||
#endif /* ARCHITECTURES_H */
|
25
src/args.c
Normal file
25
src/args.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "args.h"
|
||||
|
||||
#include <argp.h>
|
||||
|
||||
static int parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
switch (key) {
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_arguments(struct Arguments *args, int argc, char *argv[]) {
|
||||
struct argp_option options[] = {
|
||||
{ "interpret", 'i', 0, 0, "Interpret the executable, instead of jitting it", 0 },
|
||||
{ "jit", 'j', "ARCH", OPTION_ARG_OPTIONAL, "JIT the executable with instructions for ARCH [default: native]", 0 },
|
||||
{ "asm", 'a', "ARCH", OPTION_ARG_OPTIONAL, "Assemble the executable with instructions for ARCH [default: native]", 0},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
const char *args_doc = "PROGRAM";
|
||||
|
||||
struct argp argp = { options, parse_opt, args_doc, 0, 0, 0 };
|
||||
return argp_parse(&argp, argc, argv, 0, 0, args);
|
||||
}
|
32
src/args.h
Normal file
32
src/args.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef ARGS_H
|
||||
#define ARGS_H
|
||||
|
||||
#include "architectures.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
enum Behaviour {
|
||||
BEHAVIOUR_INTERPRET,
|
||||
BEHAVIOUR_JIT,
|
||||
BEHAVIOUR_ASM
|
||||
};
|
||||
|
||||
struct Arguments {
|
||||
enum Behaviour behaviour;
|
||||
FILE *program;
|
||||
union {
|
||||
struct {
|
||||
} interpret;
|
||||
|
||||
struct {
|
||||
} jit;
|
||||
|
||||
struct {
|
||||
enum Architecture arch;
|
||||
} assemble;
|
||||
};
|
||||
};
|
||||
|
||||
int parse_arguments(struct Arguments *args, int argc, char *argv[]);
|
||||
|
||||
#endif /* ARGS_H */
|
7
src/jit.c
Normal file
7
src/jit.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "jit.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
#include "jit/x86_64.c"
|
||||
#else
|
||||
#include "jit/interpret.c"
|
||||
#endif /* architecture */
|
7
src/jit.h
Normal file
7
src/jit.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef JIT_H
|
||||
#define JIT_H
|
||||
|
||||
/* the implementations must implement this function */
|
||||
int (*jit(const char *src))(int, char**);
|
||||
|
||||
#endif /* JIT_H */
|
12
src/jit/interpret.c
Normal file
12
src/jit/interpret.c
Normal file
|
@ -0,0 +1,12 @@
|
|||
static const char *arctic_src;
|
||||
static int arctic_main(int argc, char **argv) {
|
||||
// TODO: interpret the code in arctic_src
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int (*jit(const char *src))(int, char**) {
|
||||
arctic_src = src; // TODO: instead of interpreting straight from src,
|
||||
// compile structure first and compile from that.
|
||||
return arctic_main;
|
||||
}
|
27
src/jit/x86_64.c
Normal file
27
src/jit/x86_64.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "x86_64.h"
|
||||
|
||||
/*
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 16
|
||||
mov DWORD PTR [rbp-4], edi
|
||||
mov QWORD PTR [rbp-16], rsi
|
||||
mov rdx, QWORD PTR [rbp-16]
|
||||
mov eax, DWORD PTR [rbp-4]
|
||||
mov rsi, rdx
|
||||
mov edi, eax
|
||||
call foo
|
||||
leave
|
||||
ret
|
||||
*/
|
||||
const uint8_t prelude[] = {
|
||||
// PUSH(RBP)
|
||||
// MOV(RBP,RSP)
|
||||
};
|
||||
|
||||
int (*jit(const char *src))(int, char**) {
|
||||
// TODO: see https://github.com/spencertipping/jit-tutorial
|
||||
}
|
||||
|
19
src/jit/x86_64.h
Normal file
19
src/jit/x86_64.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef X86_64_H
|
||||
#define X86_64_H
|
||||
|
||||
/*******************************************************************************
|
||||
Types:
|
||||
|
||||
R: RAX, RCX, RDX, RBX, R8, R9, R10, R11, R12, R13, R14, R15
|
||||
V: BYTE(X), WORD(X)
|
||||
Q: QWORD(X)
|
||||
*******************************************************************************/
|
||||
|
||||
#define PUSH(RV) PUSH_ ## RV
|
||||
#define POP(R) POP_ ## R
|
||||
#define MOV(SRC,DST) MOV_ ## SRC ## _ ## DST
|
||||
/* TODO: sub(R, RV) */
|
||||
|
||||
// #include "x86_64_opcodes.h"
|
||||
|
||||
#endif /* X86_64_H */
|
44
src/jit/x86_64_opcodes.h
Normal file
44
src/jit/x86_64_opcodes.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef X86_64_OPCODES_H
|
||||
#define X86_64_OPCODES_H
|
||||
|
||||
#include "../utils.h"
|
||||
|
||||
/* for list creation, other uses can override X() */
|
||||
#define X(x) (x),
|
||||
|
||||
#define XX(x) X(BYTE_0xFF(x)) X(BYTE_0xFF00(x))
|
||||
#define XXX(x) X(BYTE_0xFF(x)) X(BYTE_0xFF00(x)) X(BYTE_0xFF0000(x))
|
||||
#define XXXX(x) X(BYTE_0xFF(x)) X(BYTE_0xFF00(x)) X(BYTE_0xFF0000(x)) X(BYTE_0xFF000000(x))
|
||||
|
||||
#define PUSH_RAX X(0x50)
|
||||
#define PUSH_RCX X(0x51)
|
||||
#define PUSH_RDX X(0x52)
|
||||
#define PUSH_RBX X(0x53)
|
||||
#define PUSH_RBP X(0x55)
|
||||
#define PUSH_R8 XX(0x4150)
|
||||
#define PUSH_R9 XX(0x4151)
|
||||
#define PUSH_R10 XX(0x4152)
|
||||
#define PUSH_R11 XX(0x4153)
|
||||
#define PUSH_R12 XX(0x4154)
|
||||
#define PUSH_R13 XX(0x4155)
|
||||
#define PUSH_R14 XX(0x4156)
|
||||
#define PUSH_R15 XX(0x4157)
|
||||
#define PUSH_BYTE(x) X(0x6a) X(x)
|
||||
#define PUSH_WORD(x) X(0x68) XXXX(x)
|
||||
|
||||
#define POP_RAX X(0x58)
|
||||
#define POP_RCX X(0x59)
|
||||
#define POP_RDX X(0x5a)
|
||||
#define POP_RBX X(0x5b)
|
||||
#define POP_R8 XX(0x4158)
|
||||
#define POP_R9 XX(0x4159)
|
||||
#define POP_R10 XX(0x415a)
|
||||
#define POP_R11 XX(0x415b)
|
||||
#define POP_R12 XX(0x415c)
|
||||
#define POP_R13 XX(0x415d)
|
||||
#define POP_R14 XX(0x415e)
|
||||
#define POP_R15 XX(0x415f)
|
||||
|
||||
#include "./x86_64_mov_opcodes.h"
|
||||
|
||||
#endif /* X86_64_OPCODES_H */
|
14
src/main.c
Normal file
14
src/main.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <stdio.h>
|
||||
#include <argp.h>
|
||||
|
||||
#include "jit.h"
|
||||
#include "args.h"
|
||||
#include "architectures.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct Arguments args;
|
||||
int rc = parse_arguments(&args, argc, argv);
|
||||
|
||||
printf("%d\n", rc);
|
||||
return 0;
|
||||
}
|
9
src/utils.h
Normal file
9
src/utils.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#define BYTE_0xFF(x) ((x) & 0xFF)
|
||||
#define BYTE_0xFF00(x) BYTE_0xFF((x) >> 8)
|
||||
#define BYTE_0xFF0000(x) BYTE_0xFF((x) >> 16)
|
||||
#define BYTE_0xFF000000(x) BYTE_0xFF((x) >> 24)
|
||||
|
||||
#endif /* UTILS_H */
|
10
tools/x86_64dump
Executable file
10
tools/x86_64dump
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
tmp="$(mktemp)"
|
||||
echo '[bits 64]' >"$tmp"
|
||||
cat >>"$tmp"
|
||||
if ! nasm "$@" "$tmp" -o /dev/stdout | xxd -p; then
|
||||
>&2 echo "Failed to assemble: $(cat "$tmp")"
|
||||
fi
|
||||
rm "$tmp"
|
||||
|
6
tools/x86dump
Executable file
6
tools/x86dump
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
tmp="$(mktemp)"
|
||||
cat >"$tmp"
|
||||
nasm "$@" "$tmp" -o /dev/stdout | xxd -p
|
||||
rm "$tmp"
|
Loading…
Reference in a new issue