1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
asm.sh
======
asm.sh is an assembler embedded into POSIX shell. It defines functions for
all (supported) i386 instructions.
It generally follows AT&T syntax, modified in many places to avoid characters
reserved by the shell. Arguments are separated by spaces, no comma allowed
(as usual in shell). Width suffixes are generally mandatory.
Labels
------
There are two kinds of label: Global and local labels.
Global labels are defined with the `label' function, e.g.:
label _start
They must be globally unique. Global labels are referred to by their name,
e.g. `_start'.
They can also be relative; the following defines a label `offset' whose value
is the difference between the current location and the value of the label
`base':
label offset base
Local labels are defined with the `L' function, e.g.:
L loop
There can be several definitions of a local label. There are two ways to
refer to a local label:
- `loop^' refers to the previous declaration of the label
- `loop.' refers to the next declaration of the label
Operands
--------
Immediates: Either a label, or an integer literal in decimal, octal
(preceded by 0) or hexadecimal (preceded by 0x).
Registers: Preceded by `%' as in AT&T, e.g. `%eax'.
Memory operands: Start with `@', followed by a sum expression. Examples:
AT&T | asm.sh
-------------------|-------------------
0x100 | @0x100
label | @label
4(%eax) | @%eax+4
4(,%eax) | @1%eax+4
14(,%eax,2) | @14+2%eax
(%eax,%ebx) | @%eax+%ebx
(%ebx,%eax) | @%ebx+%eax
(%ebx,%eax) | @1%eax+%ebx
12(%ebx,%eax,8) | @%ebx+8%eax+12
The order of the summands is generally irrelevant, except that if there are
two unscaled registers, the first is taken to be the base and the second
the index. Displacement can be a label, scale must be one of the literal
characters 1, 2, 4, or 8 (or omitted, implicitly 1).
Calling convention
==================
The first three arguments are passed in %eax, %ecx and %edx. Remaining
arguments are passed on the stack in right-to-left order (last argument is
pushed first), and cleaned up by the callee.
The return value currently always fits in three registers; it is placed in
%eax, %ecx, and %edx. Some functions also modify EFLAGS, e.g. streq sets
ZF iff the strings are equal.
Functions may clobber %eax, %ecx and %edx. Stack must be 4-byte aligned.
Porting
=======
To port to other operating systems, it should be sufficient to modify asm.sh
(for the ELF header) and start.asm (for system calls etc).
|