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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
xStormy16 ABI
************
!!!!! NOTE !!!!!
This document is a draft and is subject to change.
!!!!! NOTE !!!!!
This part of the file describes the conventions required to write
ELF object files that are link-compatible with the ones produced
by the GNU toolchains.
Bit and Byte Ordering
=====================
This implementation is little-endian. Bits are numbered starting
from 0 being the LSB.
In this document, 'word' means 16 bits.
Calling Sequence
================
The registers are allocated as follows:
Register Purpose
-------------------------------------------------------------------
r0, r1 Call-volatile. May be changed during the execution
of a call instruction.
r2 through r7 Argument passing; call-clobbered.
r8, r9 Call-volatile. May be changed during the execution
of a call instruction.
r10 through r13 Call-saved.
r14 Program status word.
r15 Stack pointer.
Scalar values are returned in register r2-r7 if the value fits.
Otherwise, a pointer is passed as a 'hidden' first argument and
the return value is placed there.
Arguments are passed in registers starting in r2, then on the stack.
Arguments of size not a multiple of a word are padded to whole words.
If an argument would otherwise be passed partially in registers, and
partially on the stack, the whole of it is passed on the stack. The
last argument is pushed on the stack first.
After a procedure's arguments are pushed on the stack,
the return address is pushed on the stack, as if by the call
instruction. The return address is on the top of the stack when
a procedure is called.
Objects whose size is a multiple of 16 bits are aligned to a 16-bit
boundary.
Pointers are 16 bits, referencing addresses between 0 and 0xFFFF.
Procedure pointers are also implemented as 16-bit pointers.
Variable Argument Functions
===========================
The C type 'va_list' is implemented as a structure, as follows:
struct {
char *base;
unsigned count;
}
Both fields are 16 bits. An argument of size N bytes
(N will be even) is accessed as if by the following code:
char *result;
/* count = #bytes non-variable arguments */
/* 12 = #bytes for register arguments */
if (count + N > 12)
{
if (count < 12)
count = 12;
result = base - (count + N - 12 + 4);
}
else
{
result = base + count;
}
count += N;
/* The argument is at `*result'. */
One implementation of this is if a variadic function first
pushes registers 2 through 7 in sequence at entry, and
sets 'base' to the address of the first word pushed,
producing a stack that appears like:
SP ->
[other data]
r7
r6
r5
r4
r3
count-> r2
Return address (two words)
7th procedure parameter word
8th procedure parameter word
...
last procedure parameter word
and initializes 'count' to be the number of bytes of non-variable
arguments to the function.
ELF File Format
===============
ELF file header
---------------
xStormy16 ELF files are distinguished by the value EM_XSTORMY16 in
the e_machine field of the ELF file header:
#define EM_XSTORMY16 0xad45
DWARF Register Number Mapping
-----------------------------
Registers r0 through r15 are mapped to numbers 0 through 15.
Relocations
-----------
RELA relocs are used exclusively. The relocation types defined are:
Name Value Field Calculation Overflow
----------------------------------------------------------------
R_XSTORMY16_NONE 0 none none none
R_XSTORMY16_32 1 32 S + A none
R_XSTORMY16_16 2 16 S + A either
R_XSTORMY16_8 3 8 S + A unsigned
R_XSTORMY16_PC32 4 32 S + A - P none
R_XSTORMY16_PC16 5 16 S + A - P signed
R_XSTORMY16_PC8 6 8 S + A - P signed
R_XSTORMY16_REL_12 7 16:12:0 S + A - P signed
R_XSTORMY16_24 8 32:23:1 (S + A) >> 1 unsigned
R_XSTORMY16_FPTR16 9 16 S + A either
R_XSTORMY16_LO16 10 16 S + A none
R_XSTORMY16_HI16 11 32:16:16 S + A none
R_XSTORMY16_12 12 16:12:0 S + A signed
R_XSTORMY16_GNU_VTINHERIT 128 n/a n/a n/a
R_XSTORMY16_GNU_VTENTRY 129 n/a n/a n/a
In the 'Field' column, the first number indicates whether the
relocation refers to a byte, word or doubleword. The second number,
if any, indicates the size of the bit-field into which the relocation
is to occur (and also the size for overflow checking). The third
number indicates the first bit of the bit-field in the word or
doubleword, counting the LSB as bit 0.
In the 'Calculation' column, 'S' is the value of the symbol to which
the reloc refers, 'A' is the addend, and 'P' represents the place of
the storage unit being relocated.
In the 'Overflow' column, 'none' means that any overflow of the
computation performed in the 'Calculation' column is ignored.
'signed' means that the overflow is only reported if it happens when
the values are treated as signed quantities. 'unsigned' is the same,
except that the values are treated as unsigned quantities. 'either'
means that overflow is reported for either signed or unsigned
overflow.
|