Skip to content

Commit ca43634

Browse files
committed
Add initial specification for Big Endian
1 parent ee1eefc commit ca43634

File tree

3 files changed

+96
-7
lines changed

3 files changed

+96
-7
lines changed

introduction.adoc

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,29 @@ This specification uses the following terms and abbreviations:
5858
| RV64ILP32Q | Draft
5959
|===
6060

61-
NOTE: ABI for big-endian is *NOT* included in this specification, we intend to
62-
define that in future version of this specification.
61+
=== Big-endian ABI Status
62+
63+
[width=80%]
64+
|===
65+
| ABI Name | Status
66+
67+
| ILP32 (BE) | Draft
68+
| ILP32F (BE) | Draft
69+
| ILP32D (BE) | Draft
70+
| ILP32E (BE) | Draft
71+
| LP64 (BE) | Draft
72+
| LP64F (BE) | Draft
73+
| LP64D (BE) | Draft
74+
| LP64Q (BE) | Draft
75+
| RV64ILP32 (BE) | Draft
76+
| RV64ILP32F (BE) | Draft
77+
| RV64ILP32D (BE) | Draft
78+
| RV64ILP32Q (BE) | Draft
79+
|===
80+
81+
NOTE: This specification now includes preliminary support for big-endian ABIs.
82+
Big-endian support has been implemented in GNU GCC and LLVM/Clang toolchains.
83+
The big-endian variants follow the same calling conventions as their
84+
little-endian counterparts, with only the data byte ordering differing.
6385

6486
:sectnums:

riscv-cc.adoc

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,10 @@ the calling convention are unspecified upon exit, the contents of all
166166
callee-saved registers must be restored to what was set on entry, and the
167167
contents of any fixed registers like `gp` and `tp` never change.
168168

169-
170-
NOTE: Calling convention for big-endian is *NOT* included in this specification
171-
yet, we intend to define that in future version of this specification.
169+
NOTE: Big-endian calling conventions follow the same rules as little-endian
170+
calling conventions. The only difference is in the byte ordering of multi-byte
171+
values in memory and registers. Register usage, argument passing, and return
172+
value conventions remain the same.
172173

173174
[#integer-cc]
174175
=== Integer Calling Convention
@@ -191,14 +192,27 @@ available, the scalar is passed on the stack by value. If exactly one
191192
register is available, the low-order XLEN bits are passed in the register and
192193
the high-order XLEN bits are passed on the stack.
193194

195+
This register-pair ordering is defined in terms of value significance and is
196+
independent of endianness. For example, on RV32BE a 64-bit scalar returned
197+
in a0/a1 places bits [31:0] (the least-significant XLEN bits) in a0 and
198+
bits [63:32] in a1; memory layout remains big-endian.
199+
200+
NOTE: Defining the register-pair ordering independent of endianness allows
201+
RV32_Zdinx and Zilsd paired load/store paths to be used directly for argument
202+
passing and return without extra swaps. Memory layout remains governed by the
203+
target endianness.
204+
194205
Scalars wider than 2×XLEN bits are passed by reference and are replaced in the
195206
argument list with the address.
196207

197208
Aggregates whose total size is no more than XLEN bits are passed in
198209
a register, with the fields laid out as though they were passed in memory. If
199210
no register is available, the aggregate is passed on the stack.
200211
Aggregates whose total size is no more than 2×XLEN bits are passed in a pair
201-
of registers; if only one register is available, the first XLEN bits are passed
212+
of registers with the fields laid out as though they were passed in memory:
213+
the lower-numbered register holds the lower-addressed XLEN-sized chunk of
214+
the aggregate and the higher-numbered register holds the next chunk;
215+
if only one register is available, the first XLEN bits are passed
202216
in a register and the remaining bits are passed on the stack. If no registers are
203217
available, the aggregate is passed on the stack. Bits unused due to
204218
padding, and bits past the end of an aggregate whose size in bits is not
@@ -231,7 +245,10 @@ same manner as named arguments, with one exception. Variadic arguments with
231245
even-numbered), or on the stack by value if none is available. After a
232246
variadic argument has been passed on the stack, all future arguments will also
233247
be passed on the stack (i.e. the last argument register may be left unused due
234-
to the aligned register pair rule).
248+
to the aligned register pair rule). For 2×XLEN scalars placed in an aligned
249+
register pair, the lower-numbered register holds the least-significant XLEN bits
250+
and the higher-numbered register holds the most-significant XLEN bits,
251+
regardless of endianness.
235252

236253
Values are returned in the same manner as a first named argument of the same
237254
type would be passed. If such an argument would have been passed by

riscv-elf.adoc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,56 @@ type-name = identifier-nondigit *identifier-char
236236
identifier-nondigit = ALPHA / "_"
237237
identifier-char = identifier-nondigit / "_"
238238
----
239+
240+
== Data Representation
241+
242+
The data representation for RISC-V follows the conventions of the target endianness.
243+
RISC-V supports both little-endian and big-endian byte ordering.
244+
245+
=== Byte Ordering
246+
247+
RISC-V implementations can support either little-endian or big-endian byte ordering:
248+
249+
* **Little-endian**: The least significant byte is stored at the lowest memory address.
250+
This is the default and most common byte ordering for RISC-V.
251+
* **Big-endian**: The most significant byte is stored at the lowest memory address.
252+
253+
The endianness is fixed at the system level and cannot be changed dynamically.
254+
All data types follow the byte ordering of the target system.
255+
256+
IMPORTANT: RISC-V instructions are always stored in little-endian format,
257+
regardless of the data endianness. This means that in big-endian systems,
258+
data is big-endian but instructions remain little-endian.
259+
260+
=== Relocations and Byte Ordering
261+
262+
When generating big-endian output, the following relocations write their
263+
data values in big-endian byte order:
264+
265+
* `R_RISCV_32`
266+
* `R_RISCV_64`
267+
* `R_RISCV_ADD16`
268+
* `R_RISCV_ADD32`
269+
* `R_RISCV_ADD64`
270+
* `R_RISCV_SUB16`
271+
* `R_RISCV_SUB32`
272+
* `R_RISCV_SUB64`
273+
* `R_RISCV_SET16`
274+
* `R_RISCV_SET32`
275+
* `R_RISCV_SET64`
276+
* `R_RISCV_32_PCREL`
277+
* `R_RISCV_PLT32`
278+
* `R_RISCV_JUMP_SLOT`
279+
* `R_RISCV_TLS_DTPMOD32`
280+
* `R_RISCV_TLS_DTPMOD64`
281+
* `R_RISCV_TLS_DTPREL64`
282+
* `R_RISCV_TLS_DTPREL32`
283+
* `R_RISCV_TLS_TPREL64`
284+
* `R_RISCV_TLS_TPREL32`
285+
286+
All other relocations that modify instruction fields continue to use
287+
little-endian byte order, as RISC-V instructions are always little-endian.
288+
239289
== ELF Object Files
240290

241291
The ELF object file format for RISC-V follows the

0 commit comments

Comments
 (0)