Application binary interface
From OR2K
Back to Contents Page.
Contents |
Data Representation
Back to Contents Page.
Fundamental Types
Scalar types in the ISO/ANSI C language are based on memory operands definitions from Addressing modes and operand conventions. Similar relations between architecture and language types can be used for any other language.
| Type | C Type | Sizeof | Alignment (bytes) | OpenRISC 2000 equivalent |
|---|---|---|---|---|
| Integral | char signed char |
1 | 1 | signed byte |
| unsigned char | 1 | 1 | unsigned byte | |
| short int signed short int |
2 | 2 | signed halfword | |
| unsigned short int | 2 | 2 | unsigned halfword | |
| int signed int |
4 | 4 | signed singleword | |
| unsigned int unsigned long int |
4 | 4 | unsigned singleword | |
| long long int signed long long int |
8 | 8 | signed doubleword | |
| unsigned long long int | 8 | 8 | unsigned doubleword | |
| Pointer | anytype * anytype (*) () |
4 | 4 | unsigned singleword |
| Floating-point | float | 4 | 4 | single precision float |
| double long double |
8 | 8 | double precision float |
A null pointer of any type must be zero. All floating-point types are IEEE 754-2008 compliant.
The OpenRISC 2000 programming model introduces a set of fundamental vector data types, as described in the following table. For vector assignments both side of assignment must be of the same vector type.
| Vector type | Sizeof | Alignment (bytes) | OpenRISC 2000 equivalent |
|---|---|---|---|
| vector char vector signed char |
8 | 8 | vector of signed bytes |
| vector unsigned char | 8 | 8 | vector of unsigned bytes |
| vector short int vector signed short int |
8 | 8 | vector of signed halfwords |
| vector unsigned short int | 8 | 8 | vector of unsigned halfwords |
| vector int vector signed int |
8 | 8 | vector of signed singlewords |
| vector unsigned int vector unsigned long int |
8 | 8 | vector of unsigned singlewords |
| vector float | 8 | 8 | vector of single-precisions |
For alignment restrictions of all types see Addressing modes and operand conventions.
Aggregates and Unions
Aggregates (structures and arrays) and unions assume the alignment of their most strictly aligned element.
- An array uses the alignment of its elements.
- Structures and unions can require padding to meet alignment restrictions. Each element is assigned to the lowest aligned address.
Bit-fields
C structure and union definitions can have elements defined by a specified number of bits. The following table describes valid bit-field types and their ranges.
| Bit-field Type | Width w [bits] | Range |
|---|---|---|
| signed char | 1 to 8 | -27 to 27-1 |
| char | 0 to 28-1 | |
| unsigned char | 0 to 28-1 | |
| signed short int | 1 to 16 | -215 to 25-1 |
| short int | 0 to 216-1 | |
| unsigned short int | 0 to 216-1 | |
| signed int | 1 to 32 | -231 to 231-1 |
| int | 0 to 232-1 | |
| enum | 0 to 232-1 | |
| unsigned int | 0 to 232-1 | |
| signed long int | -231 to 231-1 | |
| long int | 0 to 232-1 | |
| unsigned long int | 0 to 232-1 |
Bit-fields follow the same alignment rules as aggregates and unions, with the following additions:
- Bit-fields are allocated from most to least significant (from left to right)
- A bit-field must entirely reside in a storage unit appropriate for its declared type.
- Bit-fields may share a storage unit with other struct/union elements, including elements that are not bit-fields. Struct elements occupy different parts of the storage unit.
- Unnamed bit-fields’ types do not affect the alignment of a structure or union
Function Calling Sequence
Back to Contents Page.
This section describes the standard function calling sequence, including stack frame layout, register usage, parameter passing, and so on. The standard calling sequence requirements apply only to global functions, however it is recommended that all functions use the standard calling sequence.
Register Usage
The OpenRISC 2000 architecture defines 32 general-purpose registers. These registers are 32 bits wide in 32-bit implementations and 64 bits wide in 64-bit implementations.
| Register | Preserved across function calls | Usage |
|---|---|---|
| r31 | No | Temporary register |
| r30 | Yes | Callee-saved register |
| r29 | No | Temporary register |
| r28 | Yes | Callee-saved register |
| r27 | No | Temporary register |
| r26 | Yes | Callee-saved register |
| r25 | No | Temporary register |
| r24 | Yes | Callee-saved register |
| r23 | No | Temporary register |
| r22 | Yes | Callee-saved register |
| r21 | No | Temporary register |
| r20 | Yes | Callee-saved register |
| r19 | No | Temporary register |
| r18 | Yes | Callee-saved register |
| r17 | No | Temporary register |
| r16 | Yes | Callee-saved register |
| r15 | No | Temporary register |
| r14 | Yes | Callee-saved register |
| r13 | No | Temporary register |
| r12 | No | RVH - Return value high 32 bits of 64-bit result (32-bit system) Temporary reigster (64-bit system) |
| r11 | No | RV – Return value |
| r10 | Yes | Callee-saved register |
| r9 | Yes | LR – Link address register |
| r8 | No | Function parameter number 5 |
| r7 | No | Function parameter number 4 |
| r6 | No | Function parameter number 3 |
| r5 | No | Function parameter number 2 |
| r4 | No | Function parameter number 1 |
| r3 | No | Function parameter number 0 |
| r2 | Yes | FP - Frame pointer |
| r1 | Yes | SP - Stack pointer |
| r0 | – | Fixed to zero |
Some registers have assigned roles, and associated alternative names.
| r0 | Always fixed to zero. Even if it is writable in some embedded implementations, the software shouldn’t modify it. |
| r1 (sp) | The stack pointer holds the limit of the current stack frame. The stack contents below the stack pointer are undefined. Stack pointer must be double word aligned at all times. |
| r2 (fp) | The frame pointer holds the address of the previous stack frame. Incoming function parameters reside in the previous stack frame and can be accessed at positive offsets from fp. |
| r3 - r8 | General-purpose parameters use up to 6 general-purpose registers. Parameters beyond the sixth parameter appear on the stack. |
| r9 (lr) | Link address is the location of the function call instruction and is used to calculate where program execution should return after function completion. |
| r11 (rv) | Return value of the function. For void functions a value is not defined. For functions returning a union or structure, a pointer to the result is placed into return value register. |
| r12 (rvh) | Return value high of the function. For functions returning 32-bit values, or for 64-bit implementations, this register can be considered temporary register. |
Furthermore, an OpenRISC 2000 implementation might have several sets of shadowed general-purpose registers. These shadowed registers are used for fast context switching and sets can be switched only by the operating system.
The Stack Frame
In addition to registers, each function has a frame on the run-time stack. This stack grows downward from high addresses. The following table shows the stack frame organization. Stack space is only needed to pass parameters that cannot fit in the argument registers (r3-r8).
| Position | Contents | Frame |
|---|---|---|
| fp + 4n … |
Stack based parameter m (in total needing n words) … |
Previous |
| fp – 4 … |
Function variables (requiring p words of space | Current |
| sp + 4 | Previous frame pointer value (optional) | |
| sp + 0 | Return address (optional) | |
| sp – 4 … |
For use by leaf functions without function prologue/epilogue | Next |
| sp – 2100 … |
For use by exception handlers |
The stack pointer always points to the end of the latest allocated stack frame. All frames must be double word aligned. In code compiled for 32-bit implementations, upper halves of all double words are zero.
The first 2092 bytes below the current stack frame are reserved for leaf functions that do not need to modify their stack pointer. Exception handlers must guarantee that they will not use this area.
Parameter Passing
Functions receive their first 6 arguments in general-purpose parameter registers. If there are more than six arguments, the remaining arguments are passed on the stack. Structure and union arguments are passed as pointers.
All 64-bit arguments in a 32-bit system are passed using a pair of registers, with the most significant 32 bits in the lower numbered register. Note. 64-bit arguments are not aligned. For example long long int arg1, long int arg2 and long long int arg3 would be passed in the following way: arg1 in r3 and r4, arg2 in r5, and arg3 in r6 and r7.
Functions Returning Scalars or No Value
A function that returns an integral, pointer or vector/floating-point value places its result in the general-purpose rv register. Void functions put no particular value in rv register. Functions returning a 64-bit scalar value on 32-bit implementations should return the high order 32 bits in the rvh register.
Note. When returning a 64-bit value, the most significant 32 bits are in the higher numbered register (rvh=r12), which is the reverse of argument passing.
Functions Returning Structures or Unions
The location for a structure or union result is passed as a hidden first argument to the function in r3. The function will then populate that location, rather than using the rv register.
Operating System Interface
Back to Contents Page.
Exception Interface
The OpenRISC 2000 exception mechanism allows the processor to change to supervisor mode as a result of external signals, errors or execution of certain instructions. When an exception occurs the following events happen:
- The address of the interrupted instruction and the machine state are saved
- The machine mode is changed to supervisor mode
- The execution resumes from a predefined exception vector address which is different for every exception
| Exception type | Vector offset | POSIX signal | Example |
|---|---|---|---|
| Reset | 0x100 | – | Reset |
| Bus Error | 0x200 | SIGBUS | Unexisting physical location, bus parity error. |
| Data Page Fault | 0x300 | SIGSEGV | Unammaped data location or protection violation. |
| Instruction Page Fault | 0x400 | SIGSEGV | Unmapped instruction location or protection violation |
| Tick Timer Interrupt | 0x500 | – | Process scheduling |
| Alignment | 0x600 | SIGBUS | Unaligned data access |
| Illegal Instruction | 0x700 | SIGILL | Illegal/unimplemented instruction |
| External Interrupt | 0x800 | – | Device has asserted an interrupt |
| D-TLB Miss | 0x900 | – | DTLB software reload needed |
| I-TLB Miss | 0xa00 | – | ITLB software reload needed |
| Range | 0xb00 | SIGSEGV | Arithmetic overflow |
| System Call | 0xc00 | – | Instruction l.sys |
| Floating Point Exception | 0xc00 | SIGFPE | Floating point underflow |
| Trap | 0xe00 | SIGTRAP | Instruction l.trap or debug unit exception. |
The operating system handles an exception either by completing the faulting exception in a manner transparent to the application, if possible, or by delivering a signal to the application. The preceding table shows how hardware exceptions can be mapped to POSIX signals if the operating system cannot complete the faulting exception.
Virtual Address Space
For user programs to execute in virtual address space, the memory management unit (MMU) must be enabled. The MMU translates virtual address generated by the running process into physical address. This allows the process to run anywhere in the physical memory and additionally page to a secondary storage.
Processes typically begin with three logical segments, commonly referred as “text”, “data” and “stack”. Additional segments may exist or can be created by the operating system.
Page Size
Memory is organized into pages, which are the system’s smallest units of memory allocation. The basic page size is 8KB with some implementations supporting 16MB and 32GB pages.
Virtual Address Assignments
Processes have full access to the entire virtual address space. However the size of a process can be limited by several factors such as a process size limit parameter, available physical memory and secondary storage.
Page at location 0x0 is usually reserved to catch dereferences of NULL pointers.
Usually the start addresses of “.text”, “.data” and “.bss” segments are defined when linking the executable file. The heap is adjusted with functions such as malloc and free. The dynamic segment area is adjusted with mmap, and the stack size is limited with setrlimit. The detailed functionality available depends on the specific system library implementation.
Stack
Every process has its own stack that is not tied to a fixed area in its address space. Since the stack can change differently for each call of a process, a process should use the stack pointer in general-purpose register r1 to access stack data.
Processor Execution Modes
The OpenRISC 2000 provides two execution modes: user and supervisor. Processes run in user mode and the operating system’s kernel runs (at least partly) in supervisor mode. A user process must execute the l.sys or l.trap instruction to switch to supervisor mode, the former being used to request service from the operating system.
System calls use the same software calling convention model as function calls, except additional register rv (r11) specifies the system call id.
Position independent code
Back to Contents Page.
Position independent code is only supported through the compiler. It is intended for use in shared libraries. For such code all accesses to constant addresses are through a global offset table (GOT). The dynamic loader resolves the GOT entries when the program starts.
This functionality is optional, and depends on compiler and library support.
ELF
Back to Contents Page.
The OpenRISC 2000 tools use the ELF object file formats and DWARF 2 debugging information formats, as described in System V Application Binary Interface, from the Santa Cruz Operation, Inc (SCO). ELF and DWARF 2 provide a suitable basis for representing the information needed for embedded applications.
No other object file formats (for example COFF) are available. The compiler may optionally also support STABS debugging format. This section describes particular fields in the ELF and DWARF 2 formats that differ from the base standards for those formats.
Header Convention
The e_machine member of the ELF header contains the decimal value 33906 (hexadecimal 0x8472) that is defined as the name EM_OR2K.
Note. At the time of writing, SCO does not appear to have the ability to issue new e_machine values. The value shown is that for the OpenRISC 1000 (EM_OR32). A new value will be needed for the OpenRISC 2000.
The e_ident member of the ELF header contains values as shown in the following table.
| e_ident[EI_CLASS] | ELFCLASS32 | For all 32-bit implementations |
| e_ident[EI_DATA] | ELFDATA2MSB | For all implementations |
The e_flags member of the ELF header contains values as shown in the following table.
| HAS_RELOC | 0x01 | Contains relocation entries |
| EXEC_P | 0x02 | Is directly executable |
| HAS_LINENO | 0x04 | Has line number information |
| HAS_DEBUG | 0x08 | Has debugging information |
| HAS_SYMS | 0x10 | Has symbols |
| HAS_LOCALS | 0x20 | Has local symbols |
| DYNAMIC | 0x40 | Is dynamic object |
| WP_TEXT | 0x80 | Text section is write protected |
| D_PAGED | 0x100 | Is dynamically paged |
Sections
There are no OpenRISC 2000 section requirements beyond the base ELF standards.
Relocation
This section describes values and algorithms used for relocations. In particular, it describes values the compiler/assembler must leave in place and how the linker modifies those values.
| Name | Value | Size | Calculation |
|---|---|---|---|
| R_OR32_NONE | 0 | 0 | None |
| R_OR32_32 | 1 | 32 | A |
| R_OR32_16 | 2 | 16 | A & 0xffff |
| R_OR32_8 | 3 | 8 | A & 0xff |
| R_OR32_CONST | 4 | 16 | A & 0xffff |
| R_OR32_CONSTH | 5 | 16 | (A >> 16) & 0xffff |
| R_OR32_JUMPTARG | 6 | 28 | (S + A - P) >> 2 |
Key S indicates the final value assigned to the symbol referenced in the relocation record. Key A is the added value specified in the relocation record. Key P indicates the address of the relocation (e.g., the address being modified).





