diff options
| author | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
|---|---|---|
| committer | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
| commit | 065da3509019b15dd0e678072e6be629e5330bef (patch) | |
| tree | 69c934c9e786ac048b4fbe8f4c4c5571661521f4 /include | |
| parent | d130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff) | |
| download | libmcpu-0.4.0.tar.xz | |
Version 0.4.00.4.0
Diffstat (limited to 'include')
| -rw-r--r-- | include/libmcpu.h | 729 | ||||
| -rw-r--r-- | include/mcpu-elf.h | 3120 |
2 files changed, 3849 insertions, 0 deletions
diff --git a/include/libmcpu.h b/include/libmcpu.h new file mode 100644 index 0000000..178f872 --- /dev/null +++ b/include/libmcpu.h @@ -0,0 +1,729 @@ + +/*************************************************************** + LIBMCPU.H + + This file contains public MCPU operation functions & data + declarations. + + PART OF : MCPU - library . + + Copyright (C) 2026 by Andrew V.Kosteltsev. + All Rights Reserved. + ***************************************************************/ + +#ifndef __LIB_MCPU_H +#define __LIB_MCPU_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmpu.h> + +#define CPU_REGISTERS_MEM_SIZE_IN_UNITS 524288 +#define CPU_REGISTER_ADDRESS_MAX 0x0007ffffU +#define CPU_REGISTER_MIN_BITS 8U +#define CPU_REGISTER_MAX_BITS 65536U + +/* LibCPU CALL ABI return-value area at the top of the register file. */ +#define CPU_RETURN_AREA_SIZE 0x00002000U +#define CPU_RETURN_AREA_BEGIN 0x0007e000U +#define CPU_RETURN_AREA_END 0x00080000U + +/* MCPU SYSCALL register ABI. */ +#define CPU_SYSCALL_NARGS_ADDR 0x0007fff8U +#define CPU_SYSCALL_SYSNO_ADDR 0x0007fffcU +#define CPU_SYSCALL_RET_ADDR 0x0007fff8U +#define CPU_SYSCALL_ARG0_ADDR 0x0007fff0U +#define CPU_SYSCALL_ARG1_ADDR 0x0007ffe8U +#define CPU_SYSCALL_ARG2_ADDR 0x0007ffe0U +#define CPU_SYSCALL_ARG3_ADDR 0x0007ffd8U +#define CPU_SYSCALL_ARG4_ADDR 0x0007ffd0U +#define CPU_SYSCALL_ARG5_ADDR 0x0007ffc8U +#define CPU_SYSCALL_MAX_ARGS 6U + + +/* Machine encoding sizes. */ +#define CPU_OPCODE_SIZE 2U +#define CPU_REG24_SIZE 3U +#define CPU_IMM64_SIZE 8U +#define CPU_ADDR64_SIZE 8U +#define CPU_CODE64_SIZE 8U +#define CPU_OFF64_SIZE 8U +#define CPU_CONST8_SIZE 1U +#define CPU_PSWBIT8_SIZE 1U +#define CPU_PTR64_SIZE 8U + +/* + * Byte-order domains. + * + * PROGRAM multi-byte machine fields are always canonical MSB-first. + * Architectural data objects (register file, DATA, STACK and future data + * segments) use the target data representation selected by LibMPU. + * CPU_DATA_* aliases make this ABI dependency explicit to LibCPU tools. + */ +#define CPU_CODE_BYTE_ORDER_MSB_FIRST 1 +#define CPU_DATA_BYTE_ORDER MPU_BYTE_ORDER +#define CPU_DATA_BYTE_ORDER_BIG_ENDIAN MPU_BYTE_ORDER_BIG_ENDIAN +#define CPU_DATA_BYTE_ORDER_LITTLE_ENDIAN MPU_BYTE_ORDER_LITTLE_ENDIAN +#define CPU_DATA_WORD_ORDER MPU_WORD_ORDER +#define CPU_DATA_WORD_ORDER_BIG_ENDIAN MPU_WORD_ORDER_BIG_ENDIAN +#define CPU_DATA_WORD_ORDER_LITTLE_ENDIAN MPU_WORD_ORDER_LITTLE_ENDIAN + +extern __mpu_uint16_t __cpu_data_get_u16( const __mpu_UNIT_t *p ); +extern __mpu_uint32_t __cpu_data_get_u32( const __mpu_UNIT_t *p ); +extern __mpu_uint64_t __cpu_data_get_u64( const __mpu_UNIT_t *p ); +extern void __cpu_data_put_u16( __mpu_UNIT_t *p, __mpu_uint16_t v ); +extern void __cpu_data_put_u32( __mpu_UNIT_t *p, __mpu_uint32_t v ); +extern void __cpu_data_put_u64( __mpu_UNIT_t *p, __mpu_uint64_t v ); + +extern __mpu_uint16_t __cpu_code_get_u16( const __mpu_UNIT_t *p ); +extern __mpu_uint32_t __cpu_code_get_u32( const __mpu_UNIT_t *p ); +extern __mpu_uint64_t __cpu_code_get_u64( const __mpu_UNIT_t *p ); +extern void __cpu_code_put_u16( __mpu_UNIT_t *p, __mpu_uint16_t v ); +extern void __cpu_code_put_u32( __mpu_UNIT_t *p, __mpu_uint32_t v ); +extern void __cpu_code_put_u64( __mpu_UNIT_t *p, __mpu_uint64_t v ); + +/* Fixed CALL ABI bases. Individual argument offsets are computed inside + the aligned argument block and are therefore not generally fixed. */ +#define CPU_CALL_RETURN_PC_SIZE CPU_CODE64_SIZE +#define CPU_ABI_CALLEE_ARGUMENT_BLOCK_OFFSET 8U +#define CPU_ABI_FP_ARGUMENT_BLOCK_OFFSET 16U +#define CPU_ABI_HIDDEN_RESULT_BLOCK_OFFSET 0U + +/* LibCPU C-like ABI/data-layout conventions used by assembler/linker code. */ +#define CPU_ABI_MAX_ALIGN 16U +#define CPU_ABI_STACK_ALIGN 16U +#define CPU_ABI_STACK_RED_ZONE_SIZE 0U +#define CPU_ABI_ARGUMENT_BLOCK_ALIGN 16U +#define CPU_DATA_NULL_GUARD_SIZE 16U +#define CPU_HEAP_GUARD_SIZE 16U +#define CPU_HEAP_BEGIN CPU_HEAP_GUARD_SIZE +#define CPU_NULL_PTR __mpu_UINT64_C( 0x0000000000000000 ) + + +/*************************************************************** + PTR64 - segmented virtual pointer. + + bits 63..60 : 4-bit segment selector + bits 59..0 : byte offset inside the selected segment + + A PTR64 is an architectural value, never a host pointer. The + 60-bit offset gives each segment a 2^60-byte (1 EiB) virtual + address span. Segment identifiers 0x3..0x7 are assigned to model/runtime data + address spaces. Selectors 0x8..0xf remain reserved. + ***************************************************************/ +#define CPU_PTR_SEG_SHIFT 60U +#define CPU_PTR_SEG_MASK __mpu_UINT64_C( 0xf000000000000000 ) +#define CPU_PTR_OFFSET_MASK __mpu_UINT64_C( 0x0fffffffffffffff ) + +typedef enum __cpu_ptr_segment +{ + CPU_PTR_SEG_DATA = 0x0, + CPU_PTR_SEG_STACK = 0x1, + CPU_PTR_SEG_PROGRAM = 0x2, + CPU_PTR_SEG_CONTROL = 0x3, + CPU_PTR_SEG_INPUT = 0x4, + CPU_PTR_SEG_OUTPUT = 0x5, + CPU_PTR_SEG_TRACE = 0x6, + CPU_PTR_SEG_HEAP = 0x7 +} cpu_ptr_segment; + +#define CPU_PTR_SEG_FIRST_RESERVED 0x8U +#define CPU_PTR_SEG_MAX 0x0fU + +/* CONTROL and INPUT are guest read-only. OUTPUT, TRACE and HEAP are guest + read/write. PROGRAM is guest read-only. DATA and STACK remain guest + read/write. Reserved PTR64 selectors remain structurally valid pointer + values; non-dereferencing pointer arithmetic may preserve them, but any + operation requiring address-space meaning faults until a selector is + architecturally assigned. */ + +extern int __cpu_ptr_make ( __mpu_uint64_t *ptr, + unsigned int segment, + __mpu_uint64_t offset ); +extern unsigned int __cpu_ptr_segment( __mpu_uint64_t ptr ); +extern __mpu_uint64_t __cpu_ptr_offset ( __mpu_uint64_t ptr ); + +/*************************************************************** + PROGRAM STATUS WORD. + ***************************************************************/ +#define PSW_AF_MASK __mpu_UINT32_C( 0x00000001 ) +#define PSW_CF_MASK __mpu_UINT32_C( 0x00000002 ) +#define PSW_OF_MASK __mpu_UINT32_C( 0x00000004 ) +#define PSW_SF_MASK __mpu_UINT32_C( 0x00000008 ) +#define PSW_PF_MASK __mpu_UINT32_C( 0x00000010 ) +#define PSW_ZF_MASK __mpu_UINT32_C( 0x00000020 ) +#define PSW_RF_MASK __mpu_UINT32_C( 0x00000040 ) +#define PSW_VF_MASK __mpu_UINT32_C( 0x00000080 ) +#define PSW_DOMF_MASK __mpu_UINT32_C( 0x00000100 ) +#define PSW_SNGF_MASK __mpu_UINT32_C( 0x00000200 ) +#define PSW_OVFF_MASK __mpu_UINT32_C( 0x00000400 ) +#define PSW_UDFF_MASK __mpu_UINT32_C( 0x00000800 ) +#define PSW_TLSF_MASK __mpu_UINT32_C( 0x00001000 ) +#define PSW_PLSF_MASK __mpu_UINT32_C( 0x00002000 ) +#define PSW_INDF_MASK __mpu_UINT32_C( 0x00004000 ) +#define PSW_INXF_MASK __mpu_UINT32_C( 0x00008000 ) +#define PSW_HF_MASK __mpu_UINT32_C( 0x00010000 ) +#define PSW_TF_MASK __mpu_UINT32_C( 0x00020000 ) +#define PSW_IF_MASK __mpu_UINT32_C( 0x00040000 ) +#define PSW_MODE_MASK __mpu_UINT32_C( 0x00180000 ) +/* Architectural arithmetic/status partition. The lower byte is the CPU + flag domain and the upper byte is the MPU mathematical flag domain. The + implementation-level PSW_MPU_MASK name is retained for the full LibMPU-backed + PSW[15:0] facade used by existing arithmetic primitives. */ +#define PSW_CPUF_MASK __mpu_UINT32_C( 0x000000ff ) +#define PSW_MPUF_MASK __mpu_UINT32_C( 0x0000ff00 ) +#define PSW_MPU_MASK __mpu_UINT32_C( 0x0000ffff ) +#define PSW_CPU_MASK __mpu_UINT32_C( 0x001f0000 ) +#define PSW_USED_MASK __mpu_UINT32_C( 0x001fffff ) +#define PSW_HF_SHIFT 16 +#define PSW_TF_SHIFT 17 +#define PSW_IF_SHIFT 18 +#define PSW_MODE_SHIFT 19 + +/* + * Normal-function PSW calling convention. + * + * CALL/CALLP/RET themselves are PSW-neutral: they do not save, restore or + * modify PSW. The masks below describe the ABI contract across a normal + * function call. + * + * PSW[15:0] is the arithmetic/status domain and is caller-clobbered. + * PSW[7:0] is the CPU flag byte; PSW[15:8] is the MPU mathematical flag byte. + * TF, IF and MODE are persistent control state; a callee that changes any of + * them must restore the incoming value before an ordinary RET. + * HF is execution state, not a caller/callee-saved function value: HALT ends + * normal control flow, while CALL/CALLP/RET themselves leave HF unchanged. + */ +#define CPU_PSW_ABI_VOLATILE_STATUS_MASK PSW_MPU_MASK +#define CPU_PSW_ABI_PERSISTENT_CONTROL_MASK \ + (PSW_TF_MASK | PSW_IF_MASK | PSW_MODE_MASK) +#define CPU_PSW_ABI_EXECUTION_STATE_MASK PSW_HF_MASK + +extern void __cpu_init( void ); +extern void __cpu_free_context( void ); + +extern __mpu_uint64_t *__ptr_cpu_pc( void ); +extern __mpu_uint64_t *__ptr_cpu_sp( void ); +extern __mpu_uint64_t *__ptr_cpu_fp( void ); +extern __mpu_UNIT_t *__ptr_cpu_registers( void ); +#define __cpu_pc (*__ptr_cpu_pc()) +#define __cpu_sp (*__ptr_cpu_sp()) +#define __cpu_fp (*__ptr_cpu_fp()) +#define __cpu_registers (__ptr_cpu_registers()) + +/*************************************************************** + PHYSICAL REGISTER VIEWS. + + REG24 machine encoding: + + bits 23..20 : WIDTH code, 0..13 => 8..65536 bits + bits 19..0 : byte address; bit 19 is MBZ for the current + 512 KiB register file. + + Source assembler uses r<bits>@addr for integer/real views and + c<bits>@addr for complex views. In both forms <bits> is the + PHYSICAL register width. A c64 view therefore contains two + real32 components and has exactly the same REG24 encoding as + r64 at the same address. + ***************************************************************/ +typedef struct __cpu_register cpu_register; +struct __cpu_register +{ + unsigned int bits; + __mpu_uint32_t address; +}; + +extern __mpu_size_t __cpu_reg_size ( unsigned int bits ); +extern int __cpu_reg_valid( unsigned int bits, __mpu_uint32_t address ); +extern __mpu_UNIT_t *__cpu_reg_ptr ( unsigned int bits, __mpu_uint32_t address ); + +/* Canonical ABI return register: addr = 0x80000 - physical_size. */ +extern int __cpu_return_reg ( cpu_register *reg, unsigned int bits ); + +extern int __cpu_encode_reg24( __mpu_UNIT_t out[CPU_REG24_SIZE], + const cpu_register *reg ); +extern int __cpu_decode_reg24( cpu_register *reg, + const __mpu_UNIT_t in[CPU_REG24_SIZE] ); + +/*************************************************************** + PSW access. + ***************************************************************/ +extern __mpu_uint32_t __cpu_get_psw ( void ); +extern void __cpu_set_psw ( __mpu_uint32_t psw ); +extern void __cpu_clear_psw ( void ); +extern int __cpu_gth ( void ); +extern int __cpu_gtt ( void ); +extern int __cpu_gti ( void ); +extern void __cpu_sth ( void ); +extern void __cpu_stt ( void ); +extern void __cpu_sti ( void ); +extern void __cpu_clh ( void ); +extern void __cpu_clt ( void ); +extern void __cpu_cli ( void ); +extern void __cpu_cmh ( void ); +extern void __cpu_cmt ( void ); +extern void __cpu_cmi ( void ); +extern int __cpu_gtmode ( void ); +extern int __cpu_stmode ( unsigned int mode ); + +/*************************************************************** + ARCHITECTURAL MEMORY SPACES. + + PROGRAM, DATA, STACK, CONTROL, INPUT, OUTPUT, TRACE and HEAP are + independent byte-addressable guest spaces backed by anonymous + mmap() mappings. Architectural bounds always use segment size, + never host page-rounded capacity. No guest segment is file-backed. + + PROGRAM is host-protected read-only after loading. CONTROL and + INPUT remain host-writable so a runtime/supervisor can update them, + but guest STOREP/BMOV destinations to those spaces fault. OUTPUT, + TRACE and HEAP are guest read/write. + + STACK grows toward lower addresses; an empty allocated stack has + SP == FP == stack_size. + + HEAP is zero-filled runtime storage and has no assembler payload. + Offsets [0,CPU_HEAP_BEGIN) are reserved. The current API records + initial architectural size and a maximum limit. malloc/free are + library concerns; dynamic heap growth is intentionally reserved for + a future runtime/system-call ABI. + ***************************************************************/ +extern int __cpu_program_alloc ( __mpu_uint64_t size ); +extern void __cpu_program_free ( void ); +extern int __cpu_program_protect ( void ); +extern __mpu_UNIT_t *__cpu_program_ptr ( void ); +extern __mpu_uint64_t __cpu_program_size ( void ); +extern int __cpu_program_set ( const __mpu_UNIT_t *data, + __mpu_uint64_t size ); +extern int __cpu_data_alloc ( __mpu_uint64_t size ); +extern void __cpu_data_free ( void ); +extern __mpu_UNIT_t *__cpu_data_ptr ( void ); +extern __mpu_uint64_t __cpu_data_size ( void ); +extern int __cpu_data_set ( const __mpu_UNIT_t *data, + __mpu_uint64_t size ); +extern int __cpu_stack_alloc ( __mpu_uint64_t size ); +extern void __cpu_stack_free ( void ); +extern __mpu_UNIT_t *__cpu_stack_ptr ( void ); +extern __mpu_uint64_t __cpu_stack_size ( void ); +extern int __cpu_control_alloc ( __mpu_uint64_t size ); +extern void __cpu_control_free ( void ); +extern __mpu_UNIT_t *__cpu_control_ptr ( void ); +extern __mpu_uint64_t __cpu_control_size ( void ); +extern int __cpu_control_set ( const __mpu_UNIT_t *data, __mpu_uint64_t size ); +extern int __cpu_input_alloc ( __mpu_uint64_t size ); +extern void __cpu_input_free ( void ); +extern __mpu_UNIT_t *__cpu_input_ptr ( void ); +extern __mpu_uint64_t __cpu_input_size ( void ); +extern int __cpu_input_set ( const __mpu_UNIT_t *data, __mpu_uint64_t size ); +extern int __cpu_output_alloc ( __mpu_uint64_t size ); +extern void __cpu_output_free ( void ); +extern __mpu_UNIT_t *__cpu_output_ptr ( void ); +extern __mpu_uint64_t __cpu_output_size ( void ); +extern int __cpu_output_set ( const __mpu_UNIT_t *data, __mpu_uint64_t size ); +extern int __cpu_trace_alloc ( __mpu_uint64_t size ); +extern void __cpu_trace_free ( void ); +extern __mpu_UNIT_t *__cpu_trace_ptr ( void ); +extern __mpu_uint64_t __cpu_trace_size ( void ); +extern int __cpu_trace_set ( const __mpu_UNIT_t *data, __mpu_uint64_t size ); +extern int __cpu_heap_alloc ( __mpu_uint64_t initial_size, __mpu_uint64_t maximum_size ); +extern void __cpu_heap_free ( void ); +extern __mpu_UNIT_t *__cpu_heap_ptr ( void ); +extern __mpu_uint64_t __cpu_heap_size ( void ); +extern __mpu_uint64_t __cpu_heap_limit ( void ); + +/*************************************************************** + MACHINE OPCODES. + + The opcode completely determines the number and kind of all + following operands. Multi-byte machine fields use canonical + MSB-first byte order. + ***************************************************************/ +typedef enum __cpu_opcode +{ + CPU_OP_NOP = 0x0000, + CPU_OP_HALT = 0x0001, + CPU_OP_END = 0x0002, /* end current externally managed execution phase */ + CPU_OP_EXIT = 0x0003, /* r32 signed program/model exit status */ + CPU_OP_SYSCALL = 0x0004, /* system call through fixed register ABI */ + + CPU_OP_SETF = 0x0010, /* set one writable PSW[15:0] flag */ + CPU_OP_CLRF = 0x0011, /* clear one writable PSW[15:0] flag */ + CPU_OP_CLRCPUF = 0x0012, /* clear CPU flag byte PSW[7:0] */ + CPU_OP_CLRMPUF = 0x0013, /* clear MPU flag byte PSW[15:8] */ + + CPU_OP_MOV = 0x0100, + CPU_OP_CLR = 0x0101, + CPU_OP_SWAP = 0x0102, + CPU_OP_BSWAP = 0x0103, /* raw byte reversal: Rdst, Rsrc */ + CPU_OP_LDI = 0x0110, /* R, signed integer64 immediate */ + CPU_OP_LDR = 0x0111, /* R, IEEE binary64 immediate */ + CPU_OP_LDC = 0x0112, /* R, 2 x IEEE binary32 */ + CPU_OP_LOAD = 0x0120, /* R, DATA ADDR64 */ + CPU_OP_STORE = 0x0121, /* DATA ADDR64, R */ + CPU_OP_LEA = 0x0130, /* r64, PTR64 immediate */ + CPU_OP_LEASP = 0x0131, /* r64, signed OFF64 -> PTR64 */ + CPU_OP_LOADP = 0x0132, /* R/C, r64(PTR64) */ + CPU_OP_STOREP = 0x0133, /* r64(PTR64), R/C */ + CPU_OP_PADD = 0x0140, /* r64 = PTR64 + signed r64 */ + CPU_OP_PADDI = 0x0141, /* r64 = PTR64 + signed OFF64 */ + CPU_OP_PSUB = 0x0142, /* r64 = PTR64 - signed r64 */ + CPU_OP_PSUBI = 0x0143, /* r64 = PTR64 - signed OFF64 */ + CPU_OP_PDIFF = 0x0144, /* r64 = PTR64 - PTR64 bytes */ + CPU_OP_BMOV = 0x0150, /* PTR64 dst, PTR64 src, r64 byte count */ + CPU_OP_BMOVI = 0x0151, /* PTR64 dst, PTR64 src, IMM64 byte count */ + + CPU_OP_IADD = 0x1000, + CPU_OP_IADC = 0x1001, + CPU_OP_ISUB = 0x1002, + CPU_OP_ISBB = 0x1003, + CPU_OP_IAND = 0x1004, + CPU_OP_IOR = 0x1005, + CPU_OP_IXOR = 0x1006, + CPU_OP_INOT = 0x1010, + CPU_OP_INEG = 0x1011, + CPU_OP_ICMP = 0x1020, + CPU_OP_ITEST = 0x1021, + + CPU_OP_ISHL = 0x1030, /* logical shift left by one bit */ + CPU_OP_ISHR = 0x1031, /* logical shift right by one bit */ + CPU_OP_ISAL = 0x1032, /* arithmetic shift left by one bit */ + CPU_OP_ISAR = 0x1033, /* arithmetic shift right by one bit */ + CPU_OP_IROL = 0x1034, /* rotate left by one bit */ + CPU_OP_IROR = 0x1035, /* rotate right by one bit */ + CPU_OP_IRCL = 0x1036, /* rotate left through CF by one bit */ + CPU_OP_IRCR = 0x1037, /* rotate right through CF by one bit */ + + CPU_OP_ISHLN = 0x1040, /* Rdst,Rsrc,r64 count */ + CPU_OP_ISHRN = 0x1041, + CPU_OP_ISALN = 0x1042, + CPU_OP_ISARN = 0x1043, + CPU_OP_IROLN = 0x1044, + CPU_OP_IRORN = 0x1045, + CPU_OP_IRCLN = 0x1046, + CPU_OP_IRCRN = 0x1047, + + CPU_OP_IINC = 0x1050, + CPU_OP_IDEC = 0x1051, + CPU_OP_IXCHG = 0x1052, + CPU_OP_ICPY = 0x1053, /* width-changing unsigned copy */ + CPU_OP_ICVT = 0x1054, /* width-changing signed conversion */ + + CPU_OP_IMUL = 0x1060, /* unsigned full product */ + CPU_OP_ISMUL = 0x1061, /* signed full product */ + CPU_OP_IDIV = 0x1062, /* quot,rem,num,den (unsigned) */ + CPU_OP_ISDIV = 0x1063, /* quot,rem,num,den (signed) */ + CPU_OP_IBITSLEN = 0x1064, /* r64 result, integer source */ + + CPU_OP_RADD = 0x2000, + CPU_OP_RSUB = 0x2001, + CPU_OP_RMUL = 0x2002, + CPU_OP_RDIV = 0x2003, + CPU_OP_RSQRT = 0x2010, + CPU_OP_RSIN = 0x2020, + CPU_OP_RCOS = 0x2021, + CPU_OP_RTAN = 0x2022, + CPU_OP_RASIN = 0x2023, + CPU_OP_RACOS = 0x2024, + CPU_OP_RATAN = 0x2025, + CPU_OP_RLOG = 0x2030, + CPU_OP_RLOG10 = 0x2031, + CPU_OP_RLOG2 = 0x2032, + CPU_OP_REXP = 0x2033, + CPU_OP_RSINH = 0x2040, + CPU_OP_RCOSH = 0x2041, + CPU_OP_RTANH = 0x2042, + CPU_OP_RPOW = 0x2050, + CPU_OP_RHYPOT = 0x2051, + CPU_OP_RATAN2 = 0x2052, + + CPU_OP_RNEG = 0x2060, + CPU_OP_RABS = 0x2061, + CPU_OP_RCMP = 0x2062, /* r64 result {-2,-1,0,+1}, Ra, Rb */ + CPU_OP_RCPY = 0x2063, + CPU_OP_RCVT = 0x2064, + + CPU_OP_RFLOOR = 0x2070, + CPU_OP_RCEIL = 0x2071, + CPU_OP_RROUND = 0x2072, + CPU_OP_RFREXP = 0x2073, /* R significand, I exponent, R source */ + CPU_OP_RLDEXP = 0x2074, /* R dst, R src, I exponent */ + CPU_OP_RLOGB = 0x2075, /* I dst, R src */ + CPU_OP_RMODF = 0x2076, /* R frac, R integer, R source */ + CPU_OP_RREMAIN = 0x2077, + + CPU_OP_RLOG1P = 0x2080, + CPU_OP_REXPM1 = 0x2081, + CPU_OP_RASINH = 0x2082, + CPU_OP_RACOSH = 0x2083, + CPU_OP_RATANH = 0x2084, + + CPU_OP_ITOR = 0x2090, /* signed integer -> real */ + CPU_OP_UITOR = 0x2091, /* unsigned integer -> real */ + CPU_OP_RTOI = 0x2092, /* I dst, R frac, R src */ + CPU_OP_RTOUI = 0x2093, /* UI dst, R frac, R src */ + + CPU_OP_RISNEG = 0x20a0, /* r64 predicate, R src */ + CPU_OP_RSIGN = 0x20a1, /* r64 signed {-3..+1}, R src */ + CPU_OP_RISIND = 0x20a2, + CPU_OP_RISNAN = 0x20a3, + CPU_OP_RISNANMAX = 0x20a4, + CPU_OP_RISNANMIN = 0x20a5, + CPU_OP_RISINF = 0x20a6, + CPU_OP_RISSIGNULL = 0x20a7, + + CPU_OP_RCONST = 0x2100, /* R, CONST8 */ + + CPU_OP_CADD = 0x3000, + CPU_OP_CSUB = 0x3001, + CPU_OP_CMUL = 0x3002, + CPU_OP_CDIV = 0x3003, + CPU_OP_CEXP = 0x3020, + CPU_OP_CSIN = 0x3021, + CPU_OP_CCOS = 0x3022, + CPU_OP_CSINH = 0x3023, + CPU_OP_CCOSH = 0x3024, + CPU_OP_CLOG = 0x3025, + CPU_OP_CSQRT = 0x3026, + CPU_OP_CPOW = 0x3050, + + CPU_OP_CREAL = 0x3060, /* R component dst, C src */ + CPU_OP_CIMAG = 0x3061, /* R component dst, C src */ + CPU_OP_CRTOC = 0x3062, /* C dst, R src */ + CPU_OP_CGEN = 0x3063, /* C dst, R real, R imaginary */ + CPU_OP_CPOLAR = 0x3064, /* C dst, R rho, R theta */ + CPU_OP_CCONJ = 0x3065, + CPU_OP_CABS = 0x3066, /* R dst, C src */ + CPU_OP_CNORM = 0x3067, /* R dst, C src */ + CPU_OP_CARG = 0x3068, /* R dst, C src */ + + CPU_OP_CISEQ = 0x3070, /* r64 predicate, C a, C b */ + CPU_OP_CISNE = 0x3071, + CPU_OP_CCPY = 0x3072, + CPU_OP_CCVT = 0x3073, + + CPU_OP_JMP = 0x4000, /* CODE64 */ + CPU_OP_JSET = 0x4001, /* PSWBIT8, CODE64 */ + CPU_OP_JCLR = 0x4002, /* PSWBIT8, CODE64 */ + CPU_OP_JMPP = 0x4003, /* r64(PROGRAM PTR64) */ + CPU_OP_CALL = 0x4010, /* CODE64; push next PC */ + CPU_OP_RET = 0x4011, /* pop PC from STACK */ + CPU_OP_CALLP = 0x4012, /* r64(PROGRAM PTR64); push next PC */ + + CPU_OP_PUSH = 0x5000, /* R/C */ + CPU_OP_POP = 0x5001, /* R/C */ + CPU_OP_LDSP = 0x5010, /* R/C, signed OFF64 */ + CPU_OP_STSP = 0x5011, /* signed OFF64, R/C */ + CPU_OP_ADJSP = 0x5020, /* signed OFF64 */ + + CPU_OP_PUSHFP = 0x5030, /* push current 64-bit FP on STACK */ + CPU_OP_SETFP = 0x5031, /* FP = SP */ + CPU_OP_RESTSP = 0x5032, /* SP = FP */ + CPU_OP_POPFP = 0x5033, /* pop 64-bit FP from STACK */ + + CPU_OP_LDFP = 0x5040, /* R/C, signed OFF64 relative to FP */ + CPU_OP_STFP = 0x5041, /* signed OFF64 relative to FP, R/C */ + CPU_OP_LEAFP = 0x5042, /* r64, signed OFF64 -> STACK PTR64 */ + + CPU_OP_SETSP = 0x5050 /* r64(STACK PTR64) -> SP */ +} cpu_opcode; + + + +/*************************************************************** + PSW bit selectors used by JSET/JCLR and by writable-flag + instructions where explicitly permitted. + + MODE is a multi-bit field and is intentionally not + addressable through JSET/JCLR. Branch selectors cover + individual bits 0..18. SETF/CLRF are restricted to bits + 0..15 by CPU_PSWBIT_WRITE_MAX. + ***************************************************************/ +typedef enum __cpu_psw_bit +{ + CPU_PSWBIT_AF = 0, + CPU_PSWBIT_CF = 1, + CPU_PSWBIT_OF = 2, + CPU_PSWBIT_SF = 3, + CPU_PSWBIT_PF = 4, + CPU_PSWBIT_ZF = 5, + CPU_PSWBIT_RF = 6, + CPU_PSWBIT_VF = 7, + CPU_PSWBIT_DOMF = 8, + CPU_PSWBIT_SNGF = 9, + CPU_PSWBIT_OVFF = 10, + CPU_PSWBIT_UDFF = 11, + CPU_PSWBIT_TLSF = 12, + CPU_PSWBIT_PLSF = 13, + CPU_PSWBIT_INDF = 14, + CPU_PSWBIT_INXF = 15, + CPU_PSWBIT_HF = 16, + CPU_PSWBIT_TF = 17, + CPU_PSWBIT_IF = 18 +} cpu_psw_bit; + +#define CPU_PSWBIT_MAX CPU_PSWBIT_IF +#define CPU_PSWBIT_WRITE_MAX CPU_PSWBIT_INXF + +/*************************************************************** + Predefined real mathematical constants for RCONST. + ***************************************************************/ +typedef enum __cpu_real_constant +{ + CPU_RCONST_ZERO = 0x00, + CPU_RCONST_HALF, + CPU_RCONST_ONE, + CPU_RCONST_TWO, + CPU_RCONST_TEN, + CPU_RCONST_MTEN, + CPU_RCONST_32, + + CPU_RCONST_PI = 0x10, + CPU_RCONST_E, + CPU_RCONST_1_LN2, + CPU_RCONST_LN2, + CPU_RCONST_1_LN10, + CPU_RCONST_LN10, + CPU_RCONST_1_LG2, + CPU_RCONST_LG2, + + CPU_RCONST_PI_2 = 0x20, + CPU_RCONST_PI_3, + CPU_RCONST_PI_4, + CPU_RCONST_PI_5, + CPU_RCONST_PI_6, + CPU_RCONST_1_PI, + CPU_RCONST_2_PI, + CPU_RCONST_3_PI, + CPU_RCONST_4_PI, + CPU_RCONST_5_PI, + CPU_RCONST_2PI, + CPU_RCONST_3PI, + CPU_RCONST_1_2PI, + CPU_RCONST_1_3PI, + CPU_RCONST_1_4PI, + CPU_RCONST_1_5PI, + CPU_RCONST_1_6PI, + CPU_RCONST_3PI_4, + + CPU_RCONST_SQRTPI = 0x40, + CPU_RCONST_1_SQRTPI, + CPU_RCONST_2_SQRTPI, + CPU_RCONST_SQRT2, + CPU_RCONST_1_SQRT2, + CPU_RCONST_SQRT3, + CPU_RCONST_1_SQRT3, + CPU_RCONST_DEGREE, + CPU_RCONST_1_DEGREE, + CPU_RCONST_GOLDENRATIO, + CPU_RCONST_EULERGAMMA, + CPU_RCONST_CATALAN, + + CPU_RCONST_EPSILON = 0x50, + CPU_RCONST_IND, + CPU_RCONST_PNAN, + CPU_RCONST_NNAN, + CPU_RCONST_PNANMAX, + CPU_RCONST_NNANMAX, + CPU_RCONST_PNANMIN, + CPU_RCONST_NNANMIN, + CPU_RCONST_PINF, + CPU_RCONST_NINF, + CPU_RCONST_PREALMIN, + CPU_RCONST_NREALMIN, + CPU_RCONST_PREALMAX, + CPU_RCONST_NREALMAX, + CPU_RCONST_PZERO, + CPU_RCONST_NZERO +} cpu_real_constant; + +/*************************************************************** + DECODED INSTRUCTION REPRESENTATION. + ***************************************************************/ +typedef enum __cpu_operand_type +{ + CPU_OPERAND_NONE = 0, + CPU_OPERAND_REGISTER, + CPU_OPERAND_IMM64, + CPU_OPERAND_ADDR64, + CPU_OPERAND_CODE64, + CPU_OPERAND_OFF64, + CPU_OPERAND_CONST8, + CPU_OPERAND_PSWBIT8, + CPU_OPERAND_PTR64 +} cpu_operand_type; + +#define CPU_OPERAND_IMMEDIATE CPU_OPERAND_IMM64 + +typedef struct __cpu_operand cpu_operand; +struct __cpu_operand +{ + cpu_operand_type type; + union + { + cpu_register reg; + __mpu_uint64_t imm64; + __mpu_uint64_t addr64; + __mpu_uint64_t code64; + __mpu_int64_t off64; + __mpu_uint8_t const8; + __mpu_uint8_t pswbit8; + __mpu_uint64_t ptr64; + } value; +}; + +#define CPU_INSTRUCTION_MAX_OPERANDS 4 + +typedef struct __cpu_instruction cpu_instruction; +struct __cpu_instruction +{ + cpu_opcode opcode; + cpu_operand operand[CPU_INSTRUCTION_MAX_OPERANDS]; + __mpu_uint64_t length; +}; + +#define CPU_EXEC_SUCCESS 0 +#define CPU_EXEC_INSTRUCTION_FAULT -1 +#define CPU_EXEC_OPCODE_FAULT -2 +#define CPU_EXEC_OPERAND_FAULT -3 +#define CPU_EXEC_REGISTER_FAULT -4 +#define CPU_EXEC_WIDTH_FAULT -5 +#define CPU_EXEC_MEMORY_FAULT -6 +#define CPU_EXEC_DECODE_FAULT -7 +#define CPU_EXEC_STACK_FAULT -8 +#define CPU_EXEC_POINTER_FAULT -9 +#define CPU_EXEC_HALT 1 +#define CPU_EXEC_BRANCH 2 +#define CPU_EXEC_END 3 +#define CPU_EXEC_EXIT 4 + +typedef enum __cpu_stop_reason +{ + CPU_STOP_NONE = 0, + CPU_STOP_END, + CPU_STOP_EXIT, + CPU_STOP_HALT, + CPU_STOP_TRAP, + CPU_STOP_FAULT, + CPU_STOP_KILLED +} cpu_stop_reason; + +extern cpu_stop_reason __cpu_get_stop_reason( void ); +extern __mpu_int32_t __cpu_get_exit_status( void ); +extern void __cpu_clear_stop_reason( void ); + +extern int __cpu_exec ( const cpu_instruction *instruction ); +extern int __cpu_decode_at( const __mpu_UNIT_t *program, + __mpu_uint64_t program_size, + __mpu_uint64_t pc, + cpu_instruction *instruction ); +extern int __cpu_decode ( cpu_instruction *instruction ); +extern int __cpu_step ( void ); +extern int __cpu_run ( void ); + +#ifdef __cplusplus +} /* ... extern "C" */ +#endif + +#endif /* __LIB_MCPU_H */ diff --git a/include/mcpu-elf.h b/include/mcpu-elf.h new file mode 100644 index 0000000..f8436a9 --- /dev/null +++ b/include/mcpu-elf.h @@ -0,0 +1,3120 @@ +/* + * mcpu-elf.h + * + * MELF (MCPU ELF-derived format) definitions for LibMCPU/MCPU. + * + * Implemented specification stages: + * + * 1. MELF identification and file-header ABI. + * 2. MELF ET_REL / ET_EXEC file model and lifecycle entries. + * 3. MELF section ABI and MCPU architectural address-space mapping. + * 4. MELF symbol ABI. + * 5. MELF RELA relocation ABI. + * 6. MCPU target-profile and lifecycle metadata. + * 7. MELF program-header ABI and MCPU segment mapping. + * 8. Static-linker, loader/startup and runtime lifecycle contract. + * + * Stages 1-8 define the original static ABI-v1 contract. LibMCPU 0.1.0 + * extends this header with MELF ABI-v2 startup dynamic linking (ET_DYN, + * .dynsym/.dynstr and retained startup RELA). LibMCPU 0.2.14 introduces + * development ABI-v3 dependency metadata (.dynamic, SONAME and NEEDED) + * while keeping ABI-v1 and ABI-v2 files supported. + * + * The current MCPU ABIs are MELF64. MELF32 names are reserved for a + * possible future 32-bit MCPU ABI and are accepted by neither ABI v1, + * ABI v2 nor ABI v3. + * + * IMPORTANT + * --------- + * The C structures below describe logical MELF fields. They are not an + * on-disk serialization mechanism. MELF readers and writers must + * encode/decode every multi-byte field explicitly according to EI_DATA. + * Do not read/write MELF headers with structure casts or by fwrite()/ + * fread() of the structures, and do not depend on host alignment, + * structure padding or host endian. + * + * PROGRAM section payload is a separate byte-order domain. LibMCPU + * machine fields (OPCODE16, REG24, IMM64, ADDR64, CODE64, OFF64, ...) + * remain canonical MSB-first regardless of MELF EI_DATA. + */ + +#ifndef MCPU_ELF_H +#define MCPU_ELF_H + +#include <libmpu.h> + + +/* + * -------------------------------------------------------------------------- + * MELF identification + * -------------------------------------------------------------------------- + */ + +/* e_ident[] indices. */ +#define MELF_EI_MAG0 0 +#define MELF_EI_MAG1 1 +#define MELF_EI_MAG2 2 +#define MELF_EI_MAG3 3 +#define MELF_EI_CLASS 4 +#define MELF_EI_DATA 5 +#define MELF_EI_VERSION 6 +#define MELF_EI_OSABI 7 +#define MELF_EI_ABIVERSION 8 +#define MELF_EI_PAD 9 +#define MELF_EI_NIDENT 16 + + +/* + * MELF magic. + * + * MELF intentionally does not use the ordinary ELF 0x7f,'E','L','F' + * signature. "_ELF" identifies the MCPU ELF-derived container and + * prevents accidental interpretation by ordinary host ELF loaders. + */ +#define MELFMAG0 ((__mpu_uint8_t)'_') +#define MELFMAG1 ((__mpu_uint8_t)'E') +#define MELFMAG2 ((__mpu_uint8_t)'L') +#define MELFMAG3 ((__mpu_uint8_t)'F') + + +/* + * File class. + * + * ABI versions 1 and 2 accept MELF_CLASS_64 only. + * MELF_CLASS_32 is reserved for a possible future MCPU32 ABI. + * + * MELF class is a TARGET property. It must never be selected from the + * build host's sizeof(void *), sizeof(long), ILP32/LP64/LLP64 model, etc. + */ +#define MELF_CLASS_NONE 0 +#define MELF_CLASS_32 1 +#define MELF_CLASS_64 2 + + +/* + * MELF metadata/data-object encoding. + * + * EI_DATA controls the byte order of MELF multi-byte metadata fields and + * the target architectural data-object representation. + * + * It does NOT change PROGRAM instruction serialization: PROGRAM machine + * fields remain canonical MSB-first. + * + * LibMPU word-order information that cannot be represented by this field + * belongs to future MCPU target-profile metadata. + */ +#define MELF_DATA_NONE 0 +#define MELF_DATA_LSB 1 +#define MELF_DATA_MSB 2 + + +/* MELF format version. */ +#define MELF_EV_NONE 0 +#define MELF_EV_CURRENT 1 + + +/* + * MCPU execution ABI. + * + * The OSABI value identifies the MCPU execution environment, usable both + * for ordinary programs and for managed program models. + */ +#define MELF_OSABI_MCPU 64 +#define MELF_ABIVERSION_MCPU_1 1 +#define MELF_ABIVERSION_MCPU_2 2 +#define MELF_ABIVERSION_MCPU_3 3 + +/* + * ABI 1 is the static object/executable contract. + * ABI 2 is the historical explicit-preload startup dynamic-link contract. + * ABI 3 adds .dynamic, SONAME and NEEDED metadata and is the frozen + * normal dynamic-link ABI used by current --dynamic/--shared outputs. + */ +#define MELF_ABIVERSION_STATIC MELF_ABIVERSION_MCPU_1 +#define MELF_ABIVERSION_DYNAMIC_EXPLICIT MELF_ABIVERSION_MCPU_2 +#define MELF_ABIVERSION_DYNAMIC_NEEDED MELF_ABIVERSION_MCPU_3 + +/* Historical source alias used by the ABI-v2 writer/loader paths. */ +#define MELF_ABIVERSION_DYNAMIC MELF_ABIVERSION_DYNAMIC_EXPLICIT + +/* Historical/current default used by ET_REL and static ET_EXEC writers. */ +#define MELF_ABIVERSION_CURRENT MELF_ABIVERSION_STATIC + + +/* + * Object file types. + * + * ABI version 1 supports ET_REL and fully-static ET_EXEC. + * ABI version 2 adds startup-dynamic ET_EXEC and explicit-preload ET_DYN. + * ABI version 3 adds dependency metadata to dynamic ET_EXEC/ET_DYN. + * ET_CORE remains reserved and unsupported. + */ +#define MELF_ET_NONE 0 +#define MELF_ET_REL 1 +#define MELF_ET_EXEC 2 +#define MELF_ET_DYN 3 +#define MELF_ET_CORE 4 + + +/* + * Machine architecture. + * + * MELF_EM_MCPU is a private MELF value, not an official ELF e_machine + * assignment. 0x4d43 is ASCII "MC". + * + * MCPU32/MCPU64 are not separate e_machine values. Machine architecture + * is MCPU; container/address class is selected by EI_CLASS, while a future + * C-like language programming model (ILP32/LP64/LLP64, etc.) belongs to + * target-profile ABI metadata. + */ +#define MELF_EM_NONE 0x0000 +#define MELF_EM_MCPU 0x4d43 + + +/* + * Processor-specific e_flags. + * + * No e_flags bits are assigned in ABI version 1. A conforming ABI-v1 + * writer emits zero and a conforming ABI-v1 loader requires zero. + */ +#define MELF_EF_MCPU_NONE 0x00000000U + + +/* + * -------------------------------------------------------------------------- + * MELF scalar types + * -------------------------------------------------------------------------- + */ + +/* MELF32 scalar types: reserved for a possible future MCPU32 ABI. */ +typedef __mpu_uint16_t MElf32_Half; +typedef __mpu_uint32_t MElf32_Word; +typedef __mpu_int32_t MElf32_Sword; +typedef __mpu_uint32_t MElf32_Addr; +typedef __mpu_uint32_t MElf32_Off; + + +/* MELF64 scalar types. */ +typedef __mpu_uint16_t MElf64_Half; +typedef __mpu_uint32_t MElf64_Word; +typedef __mpu_int32_t MElf64_Sword; +typedef __mpu_uint64_t MElf64_Xword; +typedef __mpu_int64_t MElf64_Sxword; +typedef __mpu_uint64_t MElf64_Addr; +typedef __mpu_uint64_t MElf64_Off; + + +/* + * -------------------------------------------------------------------------- + * MELF file header + * -------------------------------------------------------------------------- + */ + +/* + * Lifecycle ABI for MELF_ET_EXEC. + * + * _start is mandatory. + * _life is mandatory. + * + * e_entry always addresses _start. + * + * If .init exists: + * + * .init + * _start: + * ... + * END + * + * .text + * _life: + * ... + * + * then: + * + * e_entry = PTR(PROGRAM, _start) + * e_init_entry = PTR(PROGRAM, _start) + * e_life_entry = PTR(PROGRAM, _life) + * + * If .init does not exist, _start and _life MUST be consecutive labels + * at exactly the same .text address: + * + * .text + * _start: + * _life: + * ... + * + * then: + * + * e_init_entry = 0 + * e_entry == e_life_entry + * + * .fini/_fini are optional: + * + * e_fini_entry = PTR(PROGRAM, _fini), or zero when absent. + * + * main() is never a MELF entry point. The loader/runtime constructs the + * startup area containing argc/argv before _start. Startup data remains + * valid for the program lifetime. _life constructs the ordinary MCPU + * CALL-ABI argument block and calls main(argc, argv). + * + * MELF_ET_REL has no final lifecycle addresses. Therefore e_entry, + * e_init_entry, e_life_entry and e_fini_entry are all zero in ET_REL. + */ + + +/* + * MELF32 file header. + * + * Serialized ABI size: 64 bytes. + */ +typedef struct +{ + __mpu_uint8_t e_ident[MELF_EI_NIDENT]; + + MElf32_Half e_type; + MElf32_Half e_machine; + MElf32_Word e_version; + + MElf32_Addr e_entry; + MElf32_Addr e_init_entry; + MElf32_Addr e_life_entry; + MElf32_Addr e_fini_entry; + + MElf32_Off e_phoff; + MElf32_Off e_shoff; + + MElf32_Word e_flags; + + MElf32_Half e_ehsize; + MElf32_Half e_phentsize; + MElf32_Half e_phnum; + MElf32_Half e_shentsize; + MElf32_Half e_shnum; + MElf32_Half e_shstrndx; + +} MElf32_Ehdr; + + +/* + * MELF64 file header. + * + * Serialized ABI size: 88 bytes. + * + * MElf64_Addr is a 64-bit MCPU architectural address. For executable + * lifecycle entry fields it contains a full PTR64(PROGRAM, offset), not a + * raw PROGRAM offset. Therefore zero is available as an unambiguous + * "entry absent" value, while PTR64(PROGRAM, 0) is nonzero. + * + * Current ABI v1 uses MELF64. + */ +typedef struct +{ + __mpu_uint8_t e_ident[MELF_EI_NIDENT]; + + MElf64_Half e_type; + MElf64_Half e_machine; + MElf64_Word e_version; + + MElf64_Addr e_entry; + MElf64_Addr e_init_entry; + MElf64_Addr e_life_entry; + MElf64_Addr e_fini_entry; + + MElf64_Off e_phoff; + MElf64_Off e_shoff; + + MElf64_Word e_flags; + + MElf64_Half e_ehsize; + MElf64_Half e_phentsize; + MElf64_Half e_phnum; + MElf64_Half e_shentsize; + MElf64_Half e_shnum; + MElf64_Half e_shstrndx; + +} MElf64_Ehdr; + + +/* + * Serialized file-header sizes. + * + * Use these constants for e_ehsize and file I/O. Do not use sizeof() + * as the definition of the on-disk ABI. + */ +#define MELF32_EHDR_SIZE 64U +#define MELF64_EHDR_SIZE 88U + + +/* MELF32 file-header serialized offsets. */ +#define MELF32_EHDR_E_IDENT_OFF 0U +#define MELF32_EHDR_E_TYPE_OFF 16U +#define MELF32_EHDR_E_MACHINE_OFF 18U +#define MELF32_EHDR_E_VERSION_OFF 20U +#define MELF32_EHDR_E_ENTRY_OFF 24U +#define MELF32_EHDR_E_INIT_ENTRY_OFF 28U +#define MELF32_EHDR_E_LIFE_ENTRY_OFF 32U +#define MELF32_EHDR_E_FINI_ENTRY_OFF 36U +#define MELF32_EHDR_E_PHOFF_OFF 40U +#define MELF32_EHDR_E_SHOFF_OFF 44U +#define MELF32_EHDR_E_FLAGS_OFF 48U +#define MELF32_EHDR_E_EHSIZE_OFF 52U +#define MELF32_EHDR_E_PHENTSIZE_OFF 54U +#define MELF32_EHDR_E_PHNUM_OFF 56U +#define MELF32_EHDR_E_SHENTSIZE_OFF 58U +#define MELF32_EHDR_E_SHNUM_OFF 60U +#define MELF32_EHDR_E_SHSTRNDX_OFF 62U + + +/* MELF64 file-header serialized offsets. */ +#define MELF64_EHDR_E_IDENT_OFF 0U +#define MELF64_EHDR_E_TYPE_OFF 16U +#define MELF64_EHDR_E_MACHINE_OFF 18U +#define MELF64_EHDR_E_VERSION_OFF 20U +#define MELF64_EHDR_E_ENTRY_OFF 24U +#define MELF64_EHDR_E_INIT_ENTRY_OFF 32U +#define MELF64_EHDR_E_LIFE_ENTRY_OFF 40U +#define MELF64_EHDR_E_FINI_ENTRY_OFF 48U +#define MELF64_EHDR_E_PHOFF_OFF 56U +#define MELF64_EHDR_E_SHOFF_OFF 64U +#define MELF64_EHDR_E_FLAGS_OFF 72U +#define MELF64_EHDR_E_EHSIZE_OFF 76U +#define MELF64_EHDR_E_PHENTSIZE_OFF 78U +#define MELF64_EHDR_E_PHNUM_OFF 80U +#define MELF64_EHDR_E_SHENTSIZE_OFF 82U +#define MELF64_EHDR_E_SHNUM_OFF 84U +#define MELF64_EHDR_E_SHSTRNDX_OFF 86U + + +/* + * -------------------------------------------------------------------------- + * MELF section ABI + * -------------------------------------------------------------------------- + */ + +/* + * Section types. + * + * MCPU address-space semantics are NOT encoded by inventing one sh_type + * for each architectural segment. sh_type describes the physical nature + * of section contents; architectural placement is encoded by sh_flags. + * + * Only section types required by the current static object/executable + * model are declared here. Their detailed symbol/relocation semantics + * are defined by later ABI stages. + */ +#define MELF_SHT_NULL 0U +#define MELF_SHT_PROGBITS 1U +#define MELF_SHT_SYMTAB 2U +#define MELF_SHT_STRTAB 3U +#define MELF_SHT_RELA 4U +#define MELF_SHT_DYNAMIC 6U +#define MELF_SHT_NOBITS 8U +#define MELF_SHT_DYNSYM 11U + +/* + * Processor-specific section-type range. + * + * MELF is a private MCPU ELF-derived format, so these assignments are + * stable MELF/MCPU ABI values and do not claim ordinary ELF registry + * assignments. + */ +#define MELF_SHT_LOPROC 0x70000000U +#define MELF_SHT_MCPU_TARGET 0x70000000U +#define MELF_SHT_MCPU_LIFECYCLE 0x70000001U +#define MELF_SHT_HIPROC 0x7fffffffU + + +/* + * Standard section attribute flags used by MELF. + * + * MELF_SHF_WRITE means writable by the guest CPU. Host/runtime write + * access is independent of this flag. Thus CONTROL and INPUT do not + * carry MELF_SHF_WRITE even though the host runtime may provide/update + * their contents at lifecycle synchronization points. + */ +#define MELF_SHF_WRITE 0x00000001ULL +#define MELF_SHF_ALLOC 0x00000002ULL +#define MELF_SHF_EXECINSTR 0x00000004ULL + + +/* + * MCPU architectural segment field in sh_flags. + * + * Bits 20..23 : PTR64 segment selector. + * Bit 24 : segment field is valid. + * + * These bits live in the OSABI-specific flag range and fit identically + * in both MELF32 and MELF64 sh_flags. + * + * A separate VALID bit is required because DATA has selector zero. + * Without it, a DATA section could not be distinguished from a section + * with no guest architectural address at all (.symtab, .strtab, ...). + */ +#define MELF_SHF_MCPU_SEG_SHIFT 20U +#define MELF_SHF_MCPU_SEG_MASK 0x00f00000ULL +#define MELF_SHF_MCPU_SEG_VALID 0x01000000ULL + +#define MELF_SHF_MCPU_SEG(seg) \ + (MELF_SHF_MCPU_SEG_VALID | \ + ((((MElf64_Xword)(seg)) & 0x0fULL) << MELF_SHF_MCPU_SEG_SHIFT)) + +#define MELF_SHF_MCPU_HAS_SEG(flags) \ + ((((MElf64_Xword)(flags)) & MELF_SHF_MCPU_SEG_VALID) != 0) + +#define MELF_SHF_MCPU_GET_SEG(flags) \ + ((unsigned)((((MElf64_Xword)(flags)) & MELF_SHF_MCPU_SEG_MASK) >> \ + MELF_SHF_MCPU_SEG_SHIFT)) + + +/* + * MCPU PTR64 architectural segment selectors. + * + * STACK and HEAP are architectural spaces but ABI-v1 object files do not + * contain allocated STACK/HEAP payload sections. They are created by + * the runtime. Selectors 0x8..0xf remain reserved and cannot be used by + * ABI-v1 allocated sections. + */ +#define MELF_MCPU_SEG_DATA 0x0U +#define MELF_MCPU_SEG_STACK 0x1U +#define MELF_MCPU_SEG_PROGRAM 0x2U +#define MELF_MCPU_SEG_CONTROL 0x3U +#define MELF_MCPU_SEG_INPUT 0x4U +#define MELF_MCPU_SEG_OUTPUT 0x5U +#define MELF_MCPU_SEG_TRACE 0x6U +#define MELF_MCPU_SEG_HEAP 0x7U + + +/* Convenient encoded segment flags. */ +#define MELF_SHF_MCPU_DATA MELF_SHF_MCPU_SEG(MELF_MCPU_SEG_DATA) +#define MELF_SHF_MCPU_STACK MELF_SHF_MCPU_SEG(MELF_MCPU_SEG_STACK) +#define MELF_SHF_MCPU_PROGRAM MELF_SHF_MCPU_SEG(MELF_MCPU_SEG_PROGRAM) +#define MELF_SHF_MCPU_CONTROL MELF_SHF_MCPU_SEG(MELF_MCPU_SEG_CONTROL) +#define MELF_SHF_MCPU_INPUT MELF_SHF_MCPU_SEG(MELF_MCPU_SEG_INPUT) +#define MELF_SHF_MCPU_OUTPUT MELF_SHF_MCPU_SEG(MELF_MCPU_SEG_OUTPUT) +#define MELF_SHF_MCPU_TRACE MELF_SHF_MCPU_SEG(MELF_MCPU_SEG_TRACE) +#define MELF_SHF_MCPU_HEAP MELF_SHF_MCPU_SEG(MELF_MCPU_SEG_HEAP) + + +/* + * Canonical ABI-v1 flags for the architectural sections. + * + * No custom SHT_MCPU_* type is required for these spaces. + */ +#define MELF_SHFLAGS_INIT \ + (MELF_SHF_ALLOC | MELF_SHF_EXECINSTR | MELF_SHF_MCPU_PROGRAM) + +#define MELF_SHFLAGS_TEXT \ + (MELF_SHF_ALLOC | MELF_SHF_EXECINSTR | MELF_SHF_MCPU_PROGRAM) + +#define MELF_SHFLAGS_FINI \ + (MELF_SHF_ALLOC | MELF_SHF_EXECINSTR | MELF_SHF_MCPU_PROGRAM) + +#define MELF_SHFLAGS_DATA \ + (MELF_SHF_ALLOC | MELF_SHF_WRITE | MELF_SHF_MCPU_DATA) + +#define MELF_SHFLAGS_BSS \ + (MELF_SHF_ALLOC | MELF_SHF_WRITE | MELF_SHF_MCPU_DATA) + +#define MELF_SHFLAGS_CONTROL \ + (MELF_SHF_ALLOC | MELF_SHF_MCPU_CONTROL) + +#define MELF_SHFLAGS_INPUT \ + (MELF_SHF_ALLOC | MELF_SHF_MCPU_INPUT) + +#define MELF_SHFLAGS_OUTPUT \ + (MELF_SHF_ALLOC | MELF_SHF_WRITE | MELF_SHF_MCPU_OUTPUT) + +#define MELF_SHFLAGS_TRACE \ + (MELF_SHF_ALLOC | MELF_SHF_WRITE | MELF_SHF_MCPU_TRACE) + + +/* + * Canonical section names. + * + * Names identify the conventional role of a section for the assembler + * and linker. The authoritative architectural address space is encoded + * in sh_flags, not inferred from the string name by the loader. + */ +#define MELF_SEC_INIT ".init" +#define MELF_SEC_TEXT ".text" +#define MELF_SEC_FINI ".fini" + +#define MELF_SEC_DATA ".data" +#define MELF_SEC_BSS ".bss" +#define MELF_SEC_CONTROL ".control" +#define MELF_SEC_INPUT ".input" +#define MELF_SEC_OUTPUT ".output" +#define MELF_SEC_TRACE ".trace" + +#define MELF_SEC_SYMTAB ".symtab" +#define MELF_SEC_STRTAB ".strtab" +#define MELF_SEC_SHSTRTAB ".shstrtab" +#define MELF_SEC_DYNSYM ".dynsym" +#define MELF_SEC_DYNSTR ".dynstr" +#define MELF_SEC_DYNAMIC ".dynamic" + +#define MELF_SEC_MCPU_TARGET ".mcpu.target" +#define MELF_SEC_MCPU_LIFECYCLE ".mcpu.lifecycle" + + +/* + * Section-header semantics. + * + * ET_REL: + * + * - sh_addr is zero for all sections because final architectural + * addresses have not yet been assigned. + * - each allocated input section contribution carries its target + * architectural segment in sh_flags; + * - sh_addralign carries the maximum required guest alignment of that + * contribution; + * - relocatable DATA has no architectural 16-byte NULL guard. + * + * ET_EXEC: + * + * - every MELF_SHF_ALLOC section has a final full architectural address + * in sh_addr: + * + * PTR64(segment, final_offset) + * + * - .init/.text/.fini are separate sections, but all map to the single + * PROGRAM architectural space (selector 0x2); + * - .data/.bss map to DATA; + * - .control maps to CONTROL; + * - .input maps to INPUT; + * - .output maps to OUTPUT; + * - .trace maps to TRACE; + * - STACK and HEAP do not have object payload sections in ABI v1. + * + * sh_addralign is a guest-address alignment requirement. Values zero + * and one mean no alignment requirement; otherwise the value must be a + * power of two. + * + * SHT_NOBITS sections occupy architectural memory (sh_size bytes) but + * have no payload bytes in the MELF file. + */ + + +/* + * MELF32 section header. + * + * Serialized ABI size: 40 bytes. + */ +typedef struct +{ + MElf32_Word sh_name; + MElf32_Word sh_type; + MElf32_Word sh_flags; + MElf32_Addr sh_addr; + MElf32_Off sh_offset; + MElf32_Word sh_size; + MElf32_Word sh_link; + MElf32_Word sh_info; + MElf32_Word sh_addralign; + MElf32_Word sh_entsize; + +} MElf32_Shdr; + + +/* + * MELF64 section header. + * + * Serialized ABI size: 64 bytes. + */ +typedef struct +{ + MElf64_Word sh_name; + MElf64_Word sh_type; + MElf64_Xword sh_flags; + MElf64_Addr sh_addr; + MElf64_Off sh_offset; + MElf64_Xword sh_size; + MElf64_Word sh_link; + MElf64_Word sh_info; + MElf64_Xword sh_addralign; + MElf64_Xword sh_entsize; + +} MElf64_Shdr; + + +#define MELF32_SHDR_SIZE 40U +#define MELF64_SHDR_SIZE 64U + + +/* MELF32 section-header serialized offsets. */ +#define MELF32_SHDR_SH_NAME_OFF 0U +#define MELF32_SHDR_SH_TYPE_OFF 4U +#define MELF32_SHDR_SH_FLAGS_OFF 8U +#define MELF32_SHDR_SH_ADDR_OFF 12U +#define MELF32_SHDR_SH_OFFSET_OFF 16U +#define MELF32_SHDR_SH_SIZE_OFF 20U +#define MELF32_SHDR_SH_LINK_OFF 24U +#define MELF32_SHDR_SH_INFO_OFF 28U +#define MELF32_SHDR_SH_ADDRALIGN_OFF 32U +#define MELF32_SHDR_SH_ENTSIZE_OFF 36U + + +/* MELF64 section-header serialized offsets. */ +#define MELF64_SHDR_SH_NAME_OFF 0U +#define MELF64_SHDR_SH_TYPE_OFF 4U +#define MELF64_SHDR_SH_FLAGS_OFF 8U +#define MELF64_SHDR_SH_ADDR_OFF 16U +#define MELF64_SHDR_SH_OFFSET_OFF 24U +#define MELF64_SHDR_SH_SIZE_OFF 32U +#define MELF64_SHDR_SH_LINK_OFF 40U +#define MELF64_SHDR_SH_INFO_OFF 44U +#define MELF64_SHDR_SH_ADDRALIGN_OFF 48U +#define MELF64_SHDR_SH_ENTSIZE_OFF 56U + + +/* + * -------------------------------------------------------------------------- + * MELF symbol ABI + * -------------------------------------------------------------------------- + */ + +/* + * Symbol bindings. + * + * Ordinary assembler labels are local by default. + * + * .global name + * .globl name + * + * make a defined symbol GLOBAL. + * + * .extern name + * + * creates/requires a GLOBAL undefined symbol. + * + * A future/current assembler .weak directive may mark a symbol WEAK. + * Lifecycle symbols _start, _life and _fini may not be WEAK. + */ +#define MELF_STB_LOCAL 0U +#define MELF_STB_GLOBAL 1U +#define MELF_STB_WEAK 2U + + +/* + * Symbol types. + * + * Ordinary assembler labels may remain STT_NOTYPE when no stronger type + * information is available. Compiler/toolchain generated symbols should + * use STT_FUNC or STT_OBJECT when their semantic kind is known. + * + * Lifecycle symbols _start, _life and _fini are always STT_FUNC. + */ +#define MELF_STT_NOTYPE 0U +#define MELF_STT_OBJECT 1U +#define MELF_STT_FUNC 2U +#define MELF_STT_SECTION 3U +#define MELF_STT_FILE 4U + + +/* + * Symbol visibility. + * + * ABI versions 1 and 2 use MELF_STV_DEFAULT for ordinary link-visible + * symbols. ABI-v2 startup interposition currently exports/preempts only + * DEFAULT GLOBAL/WEAK names. The remaining visibility values stay reserved. + */ +#define MELF_STV_DEFAULT 0U +#define MELF_STV_INTERNAL 1U +#define MELF_STV_HIDDEN 2U +#define MELF_STV_PROTECTED 3U + +#define MELF_ST_VISIBILITY(other) \ + ((unsigned)((other) & 0x03U)) + + +/* + * st_info encoding. + * + * Binding occupies the high four bits and type the low four bits. + */ +#define MELF32_ST_BIND(info) \ + ((unsigned)(((__mpu_uint8_t)(info)) >> 4)) + +#define MELF32_ST_TYPE(info) \ + ((unsigned)(((__mpu_uint8_t)(info)) & 0x0fU)) + +#define MELF32_ST_INFO(bind, type) \ + ((__mpu_uint8_t)((((unsigned)(bind) & 0x0fU) << 4) | \ + ((unsigned)(type) & 0x0fU))) + +#define MELF64_ST_BIND(info) MELF32_ST_BIND(info) +#define MELF64_ST_TYPE(info) MELF32_ST_TYPE(info) +#define MELF64_ST_INFO(bind, type) \ + MELF32_ST_INFO((bind), (type)) + + +/* + * Special section indices used by st_shndx. + */ +#define MELF_SHN_UNDEF 0x0000U +#define MELF_SHN_LORESERVE 0xff00U +#define MELF_SHN_ABS 0xfff1U +#define MELF_SHN_COMMON 0xfff2U +#define MELF_SHN_HIRESERVE 0xffffU + + +/* + * Symbol table entry zero. + * + * Symbol index zero is the undefined symbol and must contain all-zero + * fields. Therefore st_name == 0 refers to the empty string in the + * associated string table. + */ +#define MELF_STN_UNDEF 0U + + +/* + * Canonical lifecycle symbol names. + */ +#define MELF_SYM_START "_start" +#define MELF_SYM_LIFE "_life" +#define MELF_SYM_FINI "_fini" + +/* + * Assembler-only lifecycle convenience pseudo-label. + * + * This is source syntax, not an additional MELF symbol. + */ +#define MELF_ASM_PSEUDO_START_LIFE "_start_life" + + +/* + * MELF32 symbol table entry. + * + * Serialized ABI size: 16 bytes. + */ +typedef struct +{ + MElf32_Word st_name; + MElf32_Addr st_value; + MElf32_Word st_size; + __mpu_uint8_t st_info; + __mpu_uint8_t st_other; + MElf32_Half st_shndx; + +} MElf32_Sym; + + +/* + * MELF64 symbol table entry. + * + * Serialized ABI size: 24 bytes. + */ +typedef struct +{ + MElf64_Word st_name; + __mpu_uint8_t st_info; + __mpu_uint8_t st_other; + MElf64_Half st_shndx; + MElf64_Addr st_value; + MElf64_Xword st_size; + +} MElf64_Sym; + + +#define MELF32_SYM_SIZE 16U +#define MELF64_SYM_SIZE 24U + + +/* MELF32 symbol-entry serialized offsets. */ +#define MELF32_SYM_ST_NAME_OFF 0U +#define MELF32_SYM_ST_VALUE_OFF 4U +#define MELF32_SYM_ST_SIZE_OFF 8U +#define MELF32_SYM_ST_INFO_OFF 12U +#define MELF32_SYM_ST_OTHER_OFF 13U +#define MELF32_SYM_ST_SHNDX_OFF 14U + + +/* MELF64 symbol-entry serialized offsets. */ +#define MELF64_SYM_ST_NAME_OFF 0U +#define MELF64_SYM_ST_INFO_OFF 4U +#define MELF64_SYM_ST_OTHER_OFF 5U +#define MELF64_SYM_ST_SHNDX_OFF 6U +#define MELF64_SYM_ST_VALUE_OFF 8U +#define MELF64_SYM_ST_SIZE_OFF 16U + + +/* + * Symbol-table section rules. + * + * A SHT_SYMTAB section: + * + * sh_link = section index of the associated SHT_STRTAB (.strtab); + * sh_info = symbol-table index of the first non-local symbol; + * sh_entsize = MELF32_SYM_SIZE or MELF64_SYM_SIZE. + * + * All STB_LOCAL symbols MUST precede STB_GLOBAL/STB_WEAK symbols. + * + * String-table offset zero contains an empty NUL byte. st_name is an + * offset into the associated string table and symbol names are + * case-sensitive. + */ + + +/* + * st_value semantics. + * + * MELF_ET_REL: + * + * - defined ordinary symbol: + * st_shndx = defining section index + * st_value = byte offset from the beginning of that section + * + * - undefined symbol: + * st_shndx = MELF_SHN_UNDEF + * st_value = 0 + * + * - STT_SECTION symbol: + * st_value = 0 + * + * MELF_ET_EXEC: + * + * For a symbol defined in an allocated MCPU architectural section: + * + * st_value = PTR64(segment, final_offset) + * + * Thus a .text/.init/.fini function has a PROGRAM PTR64 value, + * a .data/.bss object has a DATA PTR64 value, .control has a CONTROL + * PTR64 value, and so on. + * + * Symbols in non-allocated metadata sections have no guest runtime + * address in ABI version 1 and must use st_value == 0 unless a later + * ABI explicitly defines another meaning. + * + * st_size is the object/function size in bytes when known. Zero means + * that no size is supplied by this symbol entry. + */ + + +/* + * Absolute and COMMON symbols. + * + * Assembler .equ symbols are resolved completely by the assembler and + * do NOT enter the relocatable symbol namespace. Therefore current + * mcpu-as does not emit .equ definitions as MELF_SHN_ABS symbols. + * + * MELF_SHN_COMMON is reserved for format compatibility. COMMON symbol + * allocation semantics are not part of MCPU ABI version 1 and a v1 + * linker must reject input requiring COMMON allocation. + */ + + +/* + * Binding and resolution rules. + * + * LOCAL: + * visible only inside its own relocatable object; never participates + * in cross-object name resolution. + * + * GLOBAL: + * a defined GLOBAL symbol is exported for static link resolution. + * an undefined GLOBAL symbol must be satisfied by another input object; + * otherwise the static link fails. + * + * WEAK: + * a strong GLOBAL definition overrides WEAK definitions of the same + * name. If only multiple WEAK definitions exist, mcpu-ld selects the + * first definition in deterministic linker input order. + * + * An unresolved WEAK symbol has symbol value zero. Whether a specific + * relocation kind may encode that unresolved zero value without + * ambiguity is defined by the relocation ABI (specification stage 5). + * + * Multiple strong GLOBAL definitions of one name are a link error. + */ + + +/* + * Lifecycle symbol ABI. + * + * _start and _life are mandatory in every MELF_ET_EXEC. + * _fini is optional. + * + * These symbols are automatically: + * + * binding = MELF_STB_GLOBAL + * type = MELF_STT_FUNC + * + * They cannot be LOCAL or WEAK. + * + * With .init: + * + * _start is defined in .init + * _life is defined in .text + * + * e_entry = st_value(_start) + * e_init_entry = st_value(_start) + * e_life_entry = st_value(_life) + * + * Without .init: + * + * _start and _life are defined in .text as consecutive labels with + * exactly the same byte offset: + * + * _start: + * _life: + * + * e_init_entry = 0 + * e_entry = st_value(_start) + * e_life_entry = st_value(_life) + * e_entry == e_life_entry + * + * If .fini is present, _fini is defined in .fini and: + * + * e_fini_entry = st_value(_fini) + * + * Otherwise: + * + * e_fini_entry = 0 + * + * main() has no special MELF symbol status and is never a MELF entry + * point. It is an ordinary function symbol. _life constructs the + * normal CALL-ABI argument block and calls main(argc, argv). + */ + + +/* + * -------------------------------------------------------------------------- + * MELF ABI-v3 dynamic dependency metadata + * -------------------------------------------------------------------------- + * + * ABI-v3 dynamic ET_EXEC/ET_DYN files contain exactly one .dynamic section: + * + * sh_type = MELF_SHT_DYNAMIC + * sh_flags = 0 + * sh_link = section index of .dynstr + * sh_info = 0 + * sh_addralign = 8 + * sh_entsize = MELF64_DYN_SIZE + * + * .dynamic is non-ALLOC startup metadata. Every entry is a signed tag and + * an unsigned value. MELF_DT_NEEDED and MELF_DT_SONAME values are byte + * offsets into the .dynstr section named by sh_link. + * + * The canonical stream ends with exactly one MELF_DT_NULL entry and has no + * entries after it. ABI-v3 ET_DYN used as a normal shared library has exactly + * one MELF_DT_SONAME. ET_EXEC must not contain MELF_DT_SONAME. Both ET_EXEC + * and ET_DYN may contain zero or more MELF_DT_NEEDED entries. + * + * ABI-v3 is intentionally a development ABI until explicitly frozen. + */ +#define MELF_DT_NULL 0 +#define MELF_DT_NEEDED 1 +#define MELF_DT_SONAME 14 + +typedef struct +{ + MElf64_Sxword d_tag; + MElf64_Xword d_val; + +} MElf64_Dyn; + +#define MELF64_DYN_SIZE 16U +#define MELF64_DYN_D_TAG_OFF 0U +#define MELF64_DYN_D_VAL_OFF 8U + + +/* + * -------------------------------------------------------------------------- + * MELF RELA relocation ABI + * -------------------------------------------------------------------------- + * + * MCPU uses RELA-style relocations only. The relocation addend is stored + * explicitly in the relocation record and is never recovered implicitly + * from the field being relocated. + * + * The current MCPU ABI was deliberately defined before MELF and has + * exactly five semantic relocation kinds: + * + * CODE64 + * DATA64 + * PTR64_CODE + * PTR64_DATA + * CPTR64_DATA + * + * MELF maps them one-to-one to machine-specific relocation numbers. + */ + + +/* + * Relocation types. + * + * Numeric values are part of MELF/MCPU ABI version 1. + */ +#define MELF_R_MCPU_NONE 0U +#define MELF_R_MCPU_CODE64 1U +#define MELF_R_MCPU_DATA64 2U +#define MELF_R_MCPU_PTR64_CODE 3U +#define MELF_R_MCPU_PTR64_DATA 4U +#define MELF_R_MCPU_CPTR64_DATA 5U + + +/* + * r_info encoding. + * + * MELF32 follows the conventional ELF32 split: + * + * bits 31..8 : symbol-table index + * bits 7..0 : relocation type + * + * MELF64 follows the conventional ELF64 split: + * + * bits 63..32 : symbol-table index + * bits 31..0 : relocation type + * + * MCPU ABI version 1 is MELF64. MELF32 remains reserved for a possible + * future 32-bit ABI. + */ +#define MELF32_R_SYM(info) \ + ((MElf32_Word)(((MElf32_Word)(info)) >> 8)) + +#define MELF32_R_TYPE(info) \ + ((MElf32_Word)(((MElf32_Word)(info)) & 0xffU)) + +#define MELF32_R_INFO(sym, type) \ + ((MElf32_Word)((((MElf32_Word)(sym)) << 8) | \ + (((MElf32_Word)(type)) & 0xffU))) + + +#define MELF64_R_SYM(info) \ + ((MElf64_Word)(((MElf64_Xword)(info)) >> 32)) + +#define MELF64_R_TYPE(info) \ + ((MElf64_Word)(((MElf64_Xword)(info)) & 0xffffffffULL)) + +#define MELF64_R_INFO(sym, type) \ + ((MElf64_Xword)((((MElf64_Xword)(sym)) << 32) | \ + (((MElf64_Xword)(type)) & 0xffffffffULL))) + + +/* + * MELF32 RELA relocation entry. + * + * This structure is reserved for a possible future MELF32 ABI. + * MCPU ABI version 1 does not accept MELF32 files. + * + * Serialized size: 12 bytes. + */ +typedef struct +{ + MElf32_Addr r_offset; + MElf32_Word r_info; + MElf32_Sword r_addend; + +} MElf32_Rela; + + +/* + * MELF64 RELA relocation entry. + * + * r_addend is a signed 64-bit addend, matching the already-defined MCPU + * relocatable expression: + * + * SYMBOL + signed_constant + * + * Serialized size: 24 bytes. + */ +typedef struct +{ + MElf64_Addr r_offset; + MElf64_Xword r_info; + MElf64_Sxword r_addend; + +} MElf64_Rela; + + +#define MELF32_RELA_SIZE 12U +#define MELF64_RELA_SIZE 24U + + +/* MELF32 RELA serialized offsets. */ +#define MELF32_RELA_R_OFFSET_OFF 0U +#define MELF32_RELA_R_INFO_OFF 4U +#define MELF32_RELA_R_ADDEND_OFF 8U + + +/* MELF64 RELA serialized offsets. */ +#define MELF64_RELA_R_OFFSET_OFF 0U +#define MELF64_RELA_R_INFO_OFF 8U +#define MELF64_RELA_R_ADDEND_OFF 16U + + +/* + * Canonical relocation section names used by mcpu-as/mcpu-ld. + * + * The name is conventional; SHT_RELA together with sh_info/sh_link is + * authoritative. + */ +#define MELF_SEC_RELA_INIT ".rela.init" +#define MELF_SEC_RELA_TEXT ".rela.text" +#define MELF_SEC_RELA_FINI ".rela.fini" + +#define MELF_SEC_RELA_DATA ".rela.data" +#define MELF_SEC_RELA_CONTROL ".rela.control" +#define MELF_SEC_RELA_INPUT ".rela.input" +#define MELF_SEC_RELA_OUTPUT ".rela.output" +#define MELF_SEC_RELA_TRACE ".rela.trace" + + +/* + * SHT_RELA section rules. + * + * For every SHT_RELA section: + * + * sh_link = section index of the associated SHT_SYMTAB; + * sh_info = section index of the section whose contents are patched; + * sh_entsize = MELF32_RELA_SIZE or MELF64_RELA_SIZE. + * + * In MELF_ET_REL: + * + * r_offset is the byte offset, from the beginning of the section named + * by sh_info, of the first byte of the 8-byte relocation field. + * + * MELF_R_SYM(r_info) is an index into the symbol table named by + * sh_link. + * + * MELF_R_TYPE(r_info) selects one of the MCPU relocation kinds below. + * + * Every ABI-v1 MCPU relocation patches exactly 8 bytes. + * + * The complete relocation field [r_offset, r_offset + 8) must lie inside + * the target section. Relocations into SHT_NOBITS contents are invalid + * in ABI version 1 because there are no stored bytes to patch. + * + * In a final MELF_ET_EXEC produced by the static linker all required + * link-time relocations have already been applied. ABI version 1 defines + * no dynamic/runtime relocation mechanism. A runtime loader therefore + * must not be required to perform these relocations. + */ + + +/* + * Relocation expression. + * + * The only relocatable expression represented by an ABI-v1 RELA record is + * + * S + A + * + * where: + * + * S = final byte offset of the referenced symbol within its + * architectural MCPU segment; + * + * A = signed r_addend. + * + * For a symbol defined in input object O: + * + * S + A = + * + * output_base(O, symbol_section) + * + symbol_section_relative_offset + * + r_addend + * + * No ABI-v1 relocation represents: + * + * symbol1 - symbol2 + * symbol1 + symbol2 + * k * symbol + * + * except where mcpu-as can reduce such an expression completely to an + * absolute constant before emitting the object file. + * + * The linker must evaluate addition with overflow detection. Pointer + * relocations additionally require the resulting byte offset to fit the + * 60-bit PTR64 offset field. + */ + + +/* + * Relocation serialization domains. + * + * There are two independent byte-order domains: + * + * PROGRAM machine-field domain + * canonical MSB-first, independent of EI_DATA; + * + * architectural data-object domain + * target object representation described by the MELF target profile. + * + * The relocation kind determines which domain is used to write the + * resulting 8-byte value. + */ + + +/* + * MELF_R_MCPU_CODE64 + * ------------------ + * + * Relocation field: + * PROGRAM section only. + * + * Referenced symbol: + * must resolve to PROGRAM. + * + * Value written: + * + * final PROGRAM byte offset = S + A + * + * This is a raw CODE64 offset, NOT a PTR64. + * + * Serialization: + * exactly 8 bytes, canonical MSB-first. + * + * Typical users: + * direct JMP/CALL and other machine-code fields containing CODE64. + */ +#define MELF_R_MCPU_CODE64_FIELD_SIZE 8U + + +/* + * MELF_R_MCPU_DATA64 + * ------------------ + * + * Relocation field: + * PROGRAM section only. + * + * Referenced symbol: + * must resolve to DATA. + * + * Value written: + * + * final DATA byte offset = S + A + * + * This is a raw ADDR64/DATA offset, NOT a PTR64. + * + * Serialization: + * exactly 8 bytes, canonical MSB-first. + * + * Typical users: + * direct LOAD/STORE fields containing ADDR64. + */ +#define MELF_R_MCPU_DATA64_FIELD_SIZE 8U + + +/* + * MELF_R_MCPU_PTR64_CODE + * ---------------------- + * + * Relocation field: + * PROGRAM section only. + * + * Referenced symbol: + * may resolve to an image-backed architectural section in: + * + * DATA + * PROGRAM + * CONTROL + * INPUT + * OUTPUT + * TRACE + * + * Value written: + * + * PTR64(target_segment, S + A) + * + * Serialization: + * exactly 8 bytes, canonical MSB-first. + * + * Typical user: + * LEA immediate fields. + */ +#define MELF_R_MCPU_PTR64_CODE_FIELD_SIZE 8U + + +/* + * MELF_R_MCPU_PTR64_DATA + * ---------------------- + * + * Relocation field: + * stored data-object section only: + * + * DATA + * CONTROL + * INPUT + * OUTPUT + * TRACE + * + * Referenced symbol: + * may resolve to: + * + * DATA + * PROGRAM + * CONTROL + * INPUT + * OUTPUT + * TRACE + * + * Value written: + * + * PTR64(target_segment, S + A) + * + * Serialization: + * exactly 8 bytes in the target architectural uint64 object + * representation, NOT canonical PROGRAM MSB-first. + * + * Typical user: + * .ptr expression. + */ +#define MELF_R_MCPU_PTR64_DATA_FIELD_SIZE 8U + + +/* + * MELF_R_MCPU_CPTR64_DATA + * ----------------------- + * + * Relocation field: + * stored data-object section only: + * + * DATA + * CONTROL + * INPUT + * OUTPUT + * TRACE + * + * Referenced symbol: + * MUST resolve to PROGRAM. + * + * Value written: + * + * PTR64(PROGRAM, S + A) + * + * Serialization: + * exactly 8 bytes in the target architectural uint64 object + * representation. + * + * Typical user: + * .cptr expression. + * + * mcpu-ld must reject a target that resolves to any segment other than + * PROGRAM. + */ +#define MELF_R_MCPU_CPTR64_DATA_FIELD_SIZE 8U + + +/* + * Static target-segment restrictions. + * + * ABI-v1 relocatable objects have no STACK or HEAP payload and therefore + * no link-time symbol can denote a static STACK or HEAP object. + * + * Pointer relocations in ABI version 1 consequently may construct PTR64 + * values only for image-backed spaces: + * + * DATA, PROGRAM, CONTROL, INPUT, OUTPUT, TRACE. + * + * STACK, HEAP and reserved selectors 0x8..0xf are invalid relocation + * targets in ABI version 1. + */ + + +/* + * Unresolved WEAK symbols. + * + * For MELF_R_MCPU_CODE64 and MELF_R_MCPU_DATA64 an unresolved WEAK symbol + * is a link error. Raw offset zero is a real architectural offset and + * cannot represent "symbol absent". + * + * For: + * + * MELF_R_MCPU_PTR64_CODE + * MELF_R_MCPU_PTR64_DATA + * MELF_R_MCPU_CPTR64_DATA + * + * an unresolved WEAK symbol is permitted only when r_addend == 0. The + * linker writes the all-zero PTR64 value, i.e. architectural NULL. + * + * An unresolved WEAK pointer relocation with a non-zero addend is a link + * error; the linker must not manufacture a non-NULL pointer by adding an + * offset to an absent symbol. + */ + + +/* + * R_MCPU_NONE. + * + * MELF_R_MCPU_NONE performs no write. Its symbol index and addend have no + * relocation effect. Writers should normally emit symbol index zero and + * addend zero for this type. + */ + + +/* + * PC-relative relocations. + * + * ABI version 1 intentionally defines no PC-relative relocation. + * Current direct MCPU JMP/CALL operands contain absolute PROGRAM CODE64 + * byte offsets. A future relative-control-flow instruction, if added to + * the ISA, must receive a new explicit relocation kind rather than + * changing the semantics of MELF_R_MCPU_CODE64. + */ + + +/* + * -------------------------------------------------------------------------- + * MCPU target-profile metadata + * -------------------------------------------------------------------------- + * + * The target profile is deliberately separate from MELF EI_CLASS. + * + * EI_CLASS describes the MELF container/address class. The current MCPU + * ABI is MELF64 because architectural addresses, PC, SP, FP and PTR64 are + * 64-bit quantities. + * + * The programming/data model recorded here describes the configured MCPU/ + * LibMPU target data profile. It must never be inferred from the host on + * which mcpu-as, mcpu-ld or mcpu-run happen to execute. + * + * .mcpu.target is container metadata, not a guest data object. All its + * multi-byte fields are serialized according to EI_DATA. + */ + + +/* + * Target-profile record format version. + * + * This versions the layout/meaning of MElf_McpuTarget itself. It is + * independent of MELF_EV_CURRENT and EI_ABIVERSION. + */ +#define MELF_MCPU_TARGET_VERSION_NONE 0U +#define MELF_MCPU_TARGET_VERSION_1 1U +#define MELF_MCPU_TARGET_VERSION_CURRENT MELF_MCPU_TARGET_VERSION_1 + + +/* + * MCPU ISA and ABI revisions carried by target metadata. + * + * Revision 1 denotes the current architecture/ABI contract being encoded + * by this MELF specification. These are architecture revisions, not + * LibMCPU package release numbers such as 0.0.x. + */ +#define MELF_MCPU_ISA_REVISION_1 1U +#define MELF_MCPU_ISA_REVISION_CURRENT MELF_MCPU_ISA_REVISION_1 + +#define MELF_MCPU_ABI_REVISION_1 1U +#define MELF_MCPU_ABI_REVISION_CURRENT MELF_MCPU_ABI_REVISION_1 + + +/* + * Programming/data models. + * + * These names describe the target language/LibMPU scalar data model. + * They do not change the architectural MCPU PTR64 representation: + * MCPU ABI v1 still uses the 64-bit SEG:OFFSET pointer/address model + * described below. + */ +#define MELF_MCPU_MODEL_NONE 0U +#define MELF_MCPU_MODEL_ILP32 1U +#define MELF_MCPU_MODEL_LP64 2U +#define MELF_MCPU_MODEL_LLP64 3U + + +/* + * Target data byte order. + * + * Values intentionally match MELF_DATA_LSB/MELF_DATA_MSB. In every + * valid ABI-v1 file: + * + * mt_data_byte_order == e_ident[MELF_EI_DATA] + * + * This duplicate is a deliberate target-profile consistency check. + */ +#define MELF_MCPU_BYTE_ORDER_NONE 0U +#define MELF_MCPU_BYTE_ORDER_LSB MELF_DATA_LSB +#define MELF_MCPU_BYTE_ORDER_MSB MELF_DATA_MSB + + +/* + * Target data word order. + * + * This records the configured LibMPU word-order profile independently of + * byte order. mcpu-as/mcpu-ld/mcpu-run map these values to the configured + * MPU_WORD_ORDER semantics of the target toolchain. + */ +#define MELF_MCPU_WORD_ORDER_NONE 0U +#define MELF_MCPU_WORD_ORDER_LSB 1U +#define MELF_MCPU_WORD_ORDER_MSB 2U + + +/* Integer object representation. */ +#define MELF_MCPU_INTEGER_MODEL_NONE 0U +#define MELF_MCPU_INTEGER_MODEL_TWOS_COMPLEMENT 1U + + +/* + * Architectural address/pointer model. + * + * PTR64: + * bits 63..60 : architectural segment selector + * bits 59..0 : byte offset within the segment + */ +#define MELF_MCPU_ADDRESS_MODEL_NONE 0U +#define MELF_MCPU_ADDRESS_MODEL_PTR64_SEG4_OFF60 1U + + +/* + * Register-file model. + * + * REG24 identifies an overlapping view in the 512 KiB byte-addressable + * MCPU register file. + */ +#define MELF_MCPU_REGISTER_MODEL_NONE 0U +#define MELF_MCPU_REGISTER_MODEL_REG24_512K 1U + + +/* + * Real/Complex object representations. + * + * MCPU does not define an independent floating-point or complex storage + * format. ABI-v1 real and complex objects use the configured LibMPU + * external object representation. Complex component/half ordering + * follows the configured LibMPU word-order profile. + */ +#define MELF_MCPU_REAL_MODEL_NONE 0U +#define MELF_MCPU_REAL_MODEL_LIBMPU 1U + +#define MELF_MCPU_COMPLEX_MODEL_NONE 0U +#define MELF_MCPU_COMPLEX_MODEL_LIBMPU 1U + + +/* + * ABI-v1 natural maximum alignment for ordinary language objects. + * + * Larger explicit section/table alignment remains legal through + * sh_addralign; this constant is the normal object-layout ABI maximum. + */ +#define MELF_MCPU_ABI_MAX_ALIGN 16U + + +/* + * Target-profile flags / feature bitmap. + * + * No optional target-profile flags or required feature bits are assigned + * by ABI version 1 yet. Writers emit zero. Readers reject unknown + * required feature bits. + */ +#define MELF_MCPU_TARGET_FLAGS_NONE 0x00000000U +#define MELF_MCPU_REQUIRED_FEATURES_NONE 0x0000000000000000ULL + + +/* + * Fixed class-independent target-profile record. + * + * Serialized size: 64 bytes. + * + * This metadata record intentionally contains no host pointers and no + * MELF-class-sized address fields, so one stable layout is sufficient. + */ +typedef struct +{ + __mpu_uint32_t mt_version; + __mpu_uint32_t mt_size; + + __mpu_uint32_t mt_isa_revision; + __mpu_uint32_t mt_abi_revision; + + __mpu_uint32_t mt_program_model; + __mpu_uint32_t mt_data_byte_order; + __mpu_uint32_t mt_data_word_order; + __mpu_uint32_t mt_integer_model; + + __mpu_uint32_t mt_address_model; + __mpu_uint32_t mt_register_model; + __mpu_uint32_t mt_real_model; + __mpu_uint32_t mt_complex_model; + + __mpu_uint32_t mt_max_align; + __mpu_uint32_t mt_flags; + + __mpu_uint64_t mt_required_features; + +} MElf_McpuTarget; + + +#define MELF_MCPU_TARGET_SIZE 64U + +#define MELF_MCPU_TARGET_MT_VERSION_OFF 0U +#define MELF_MCPU_TARGET_MT_SIZE_OFF 4U +#define MELF_MCPU_TARGET_MT_ISA_REVISION_OFF 8U +#define MELF_MCPU_TARGET_MT_ABI_REVISION_OFF 12U +#define MELF_MCPU_TARGET_MT_PROGRAM_MODEL_OFF 16U +#define MELF_MCPU_TARGET_MT_DATA_BYTE_ORDER_OFF 20U +#define MELF_MCPU_TARGET_MT_DATA_WORD_ORDER_OFF 24U +#define MELF_MCPU_TARGET_MT_INTEGER_MODEL_OFF 28U +#define MELF_MCPU_TARGET_MT_ADDRESS_MODEL_OFF 32U +#define MELF_MCPU_TARGET_MT_REGISTER_MODEL_OFF 36U +#define MELF_MCPU_TARGET_MT_REAL_MODEL_OFF 40U +#define MELF_MCPU_TARGET_MT_COMPLEX_MODEL_OFF 44U +#define MELF_MCPU_TARGET_MT_MAX_ALIGN_OFF 48U +#define MELF_MCPU_TARGET_MT_FLAGS_OFF 52U +#define MELF_MCPU_TARGET_MT_REQUIRED_FEATURES_OFF 56U + + +/* + * .mcpu.target section rules. + * + * ET_REL: + * exactly one .mcpu.target section is mandatory. + * + * ET_EXEC: + * exactly one .mcpu.target section is mandatory. + * + * The section has: + * + * sh_type = MELF_SHT_MCPU_TARGET + * sh_flags = 0 + * sh_addr = 0 + * sh_size = MELF_MCPU_TARGET_SIZE + * sh_link = 0 + * sh_info = 0 + * sh_addralign = 8 + * sh_entsize = MELF_MCPU_TARGET_SIZE + * + * It is never MELF_SHF_ALLOC and never carries an MCPU segment selector. + * + * mcpu-ld must reject ET_REL inputs whose target profiles are incompatible. + * For ABI version 1 the semantic profile fields must match exactly: + * + * mt_version + * mt_isa_revision + * mt_abi_revision + * mt_program_model + * mt_data_byte_order + * mt_data_word_order + * mt_integer_model + * mt_address_model + * mt_register_model + * mt_real_model + * mt_complex_model + * mt_max_align + * mt_flags + * mt_required_features + * + * mt_size is validated as the record size, not as a target property. + * + * mcpu-run must validate the final ET_EXEC target profile against the + * runtime before mapping/executing guest contents. It must reject an + * incompatible target rather than reinterpret or byte-convert DATA. + */ + + +/* + * ABI-v1 target-profile invariants. + * + * The current architecture requires: + * + * mt_version == MELF_MCPU_TARGET_VERSION_1 + * mt_isa_revision == MELF_MCPU_ISA_REVISION_1 + * mt_abi_revision == MELF_MCPU_ABI_REVISION_1 + * mt_integer_model == MELF_MCPU_INTEGER_MODEL_TWOS_COMPLEMENT + * mt_address_model == MELF_MCPU_ADDRESS_MODEL_PTR64_SEG4_OFF60 + * mt_register_model == MELF_MCPU_REGISTER_MODEL_REG24_512K + * mt_real_model == MELF_MCPU_REAL_MODEL_LIBMPU + * mt_complex_model == MELF_MCPU_COMPLEX_MODEL_LIBMPU + * mt_max_align == MELF_MCPU_ABI_MAX_ALIGN + * mt_flags == 0 + * + * mt_program_model, mt_data_byte_order and mt_data_word_order are selected + * by the configured target profile and must be supported by the toolchain/ + * runtime. mt_data_byte_order must equal EI_DATA. + */ + + +/* + * -------------------------------------------------------------------------- + * MCPU lifecycle metadata + * -------------------------------------------------------------------------- + * + * Lifecycle entry ADDRESSES are NOT duplicated here. + * + * Their single authoritative representation remains MElf*_Ehdr: + * + * e_entry + * e_init_entry + * e_life_entry + * e_fini_entry + * + * .mcpu.lifecycle records which lifecycle contract gives those header + * fields their meaning. This avoids two independently relocatable copies + * of _start/_life/_fini addresses. + */ + + +/* Lifecycle metadata record/layout version. */ +#define MELF_MCPU_LIFECYCLE_VERSION_NONE 0U +#define MELF_MCPU_LIFECYCLE_VERSION_1 1U +#define MELF_MCPU_LIFECYCLE_VERSION_CURRENT MELF_MCPU_LIFECYCLE_VERSION_1 + + +/* Lifecycle ABI identifier. */ +#define MELF_MCPU_LIFECYCLE_ABI_NONE 0U +#define MELF_MCPU_LIFECYCLE_ABI_1 1U +#define MELF_MCPU_LIFECYCLE_ABI_CURRENT MELF_MCPU_LIFECYCLE_ABI_1 + + +/* + * Lifecycle ABI semantic flags. + * + * These describe the contract, not the actual presence of .init/.fini. + * Actual presence is determined solely from e_init_entry/e_fini_entry. + */ +#define MELF_MCPU_LF_START_REQUIRED 0x0000000000000001ULL +#define MELF_MCPU_LF_LIFE_REQUIRED 0x0000000000000002ULL +#define MELF_MCPU_LF_INIT_OPTIONAL 0x0000000000000004ULL +#define MELF_MCPU_LF_FINI_OPTIONAL 0x0000000000000008ULL +#define MELF_MCPU_LF_ENTRY_IS_START 0x0000000000000010ULL +#define MELF_MCPU_LF_NOINIT_START_EQ_LIFE 0x0000000000000020ULL +#define MELF_MCPU_LF_LIFE_END_RESUME 0x0000000000000040ULL +#define MELF_MCPU_LF_EXIT_ENTERS_FINI 0x0000000000000080ULL +#define MELF_MCPU_LF_STARTUP_PERSISTENT 0x0000000000000100ULL + +#define MELF_MCPU_LIFECYCLE_ABI1_FLAGS \ + (MELF_MCPU_LF_START_REQUIRED | \ + MELF_MCPU_LF_LIFE_REQUIRED | \ + MELF_MCPU_LF_INIT_OPTIONAL | \ + MELF_MCPU_LF_FINI_OPTIONAL | \ + MELF_MCPU_LF_ENTRY_IS_START | \ + MELF_MCPU_LF_NOINIT_START_EQ_LIFE | \ + MELF_MCPU_LF_LIFE_END_RESUME | \ + MELF_MCPU_LF_EXIT_ENTERS_FINI | \ + MELF_MCPU_LF_STARTUP_PERSISTENT) + + +/* + * Fixed class-independent lifecycle metadata record. + * + * Serialized size: 32 bytes. + * + * The concrete ABI-v1 startup-area layout is defined below by the + * loader/startup contract. The STARTUP_PERSISTENT flag fixes the rule + * that startup data constructed before _start remains valid for the + * lifetime of the executable instance. + */ +typedef struct +{ + __mpu_uint32_t ml_version; + __mpu_uint32_t ml_size; + + __mpu_uint32_t ml_abi; + __mpu_uint32_t ml_reserved0; + + __mpu_uint64_t ml_flags; + __mpu_uint64_t ml_reserved1; + +} MElf_McpuLifecycle; + + +#define MELF_MCPU_LIFECYCLE_SIZE 32U + +#define MELF_MCPU_LIFECYCLE_ML_VERSION_OFF 0U +#define MELF_MCPU_LIFECYCLE_ML_SIZE_OFF 4U +#define MELF_MCPU_LIFECYCLE_ML_ABI_OFF 8U +#define MELF_MCPU_LIFECYCLE_ML_RESERVED0_OFF 12U +#define MELF_MCPU_LIFECYCLE_ML_FLAGS_OFF 16U +#define MELF_MCPU_LIFECYCLE_ML_RESERVED1_OFF 24U + + +/* + * .mcpu.lifecycle section rules. + * + * ET_REL: + * .mcpu.lifecycle is not emitted. Relocatable objects carry lifecycle + * names through the ordinary symbol table (_start/_life/_fini), while + * final lifecycle composition is a linker responsibility. + * + * ET_EXEC: + * exactly one .mcpu.lifecycle section is mandatory. + * + * The section has: + * + * sh_type = MELF_SHT_MCPU_LIFECYCLE + * sh_flags = 0 + * sh_addr = 0 + * sh_size = MELF_MCPU_LIFECYCLE_SIZE + * sh_link = 0 + * sh_info = 0 + * sh_addralign = 8 + * sh_entsize = MELF_MCPU_LIFECYCLE_SIZE + * + * It is metadata only: not MELF_SHF_ALLOC and no MCPU segment selector. + * + * ABI-v1 ET_EXEC requires: + * + * ml_version == MELF_MCPU_LIFECYCLE_VERSION_1 + * ml_size == MELF_MCPU_LIFECYCLE_SIZE + * ml_abi == MELF_MCPU_LIFECYCLE_ABI_1 + * ml_reserved0 == 0 + * ml_flags == MELF_MCPU_LIFECYCLE_ABI1_FLAGS + * ml_reserved1 == 0 + */ + + +/* + * Lifecycle/header consistency checks for ET_EXEC. + * + * Every valid executable: + * + * e_entry != 0 + * e_life_entry != 0 + * e_entry == st_value(_start) + * e_life_entry == st_value(_life) + * + * With .init: + * + * e_init_entry != 0 + * e_init_entry == e_entry + * _start belongs to .init + * _life belongs to .text + * + * Without .init: + * + * e_init_entry == 0 + * _start and _life both belong to .text + * st_value(_start) == st_value(_life) + * e_entry == e_life_entry + * + * With .fini: + * + * e_fini_entry == st_value(_fini) + * _fini belongs to .fini + * + * Without .fini: + * + * e_fini_entry == 0 + * + * _start and _life are mandatory GLOBAL/FUNC symbols. _fini, when + * present, is also GLOBAL/FUNC. None of the lifecycle symbols may be + * WEAK. + */ + + +/* + * -------------------------------------------------------------------------- + * MELF program-header ABI and MCPU segment mapping + * -------------------------------------------------------------------------- + * + * Program headers describe the final ET_EXEC memory image. They do not + * describe host virtual memory mappings. Guest architectural addresses + * are MCPU PTR64 values; host addresses are never stored in MELF. + * + * ET_REL has no Program Header Table: + * + * e_phoff = 0 + * e_phentsize = 0 + * e_phnum = 0 + * + * ET_EXEC has a Program Header Table whose entries are described below. + */ + + +/* + * Program-header types. + * + * MELF_PT_NULL and MELF_PT_LOAD retain the conventional ELF meanings. + * Runtime-only MCPU STACK and HEAP descriptors use processor-specific + * program-header types. + */ +#define MELF_PT_NULL 0U +#define MELF_PT_LOAD 1U + +#define MELF_PT_LOPROC 0x70000000U +#define MELF_PT_MCPU_STACK 0x70000000U +#define MELF_PT_MCPU_HEAP 0x70000001U +#define MELF_PT_HIPROC 0x7fffffffU + + +/* + * Program-header permission flags. + * + * These are GUEST CPU permissions. Host/runtime access is an independent + * implementation matter. In particular CONTROL and INPUT are guest + * read-only even though the host runtime may update their backing storage + * at defined synchronization points. + */ +#define MELF_PF_X 0x00000001U +#define MELF_PF_W 0x00000002U +#define MELF_PF_R 0x00000004U + + +/* Canonical ABI-v1 guest permissions. */ +#define MELF_PFLAGS_PROGRAM (MELF_PF_R | MELF_PF_X) +#define MELF_PFLAGS_DATA (MELF_PF_R | MELF_PF_W) +#define MELF_PFLAGS_CONTROL (MELF_PF_R) +#define MELF_PFLAGS_INPUT (MELF_PF_R) +#define MELF_PFLAGS_OUTPUT (MELF_PF_R | MELF_PF_W) +#define MELF_PFLAGS_TRACE (MELF_PF_R | MELF_PF_W) +#define MELF_PFLAGS_STACK (MELF_PF_R | MELF_PF_W) +#define MELF_PFLAGS_HEAP (MELF_PF_R | MELF_PF_W) + + +/* + * MCPU PTR64 helpers used by MELF64 executable metadata. + * + * Current MCPU ABI: + * + * bits 63..60 : SEG + * bits 59..0 : byte OFFSET + * + * PTR64 value zero is architectural NULL. + * + * MELF32 cannot represent the current PTR64 architecture and remains + * reserved for a possible future ABI with separately specified semantics. + */ +#define MELF_MCPU_PTR64_SEG_SHIFT 60U +#define MELF_MCPU_PTR64_SEG_MASK 0xf000000000000000ULL +#define MELF_MCPU_PTR64_OFFSET_MASK 0x0fffffffffffffffULL + +#define MELF_MCPU_PTR64(seg, off) \ + ((MElf64_Addr)((((MElf64_Xword)(seg) & 0x0fULL) << \ + MELF_MCPU_PTR64_SEG_SHIFT) | \ + ((MElf64_Xword)(off) & MELF_MCPU_PTR64_OFFSET_MASK))) + +#define MELF_MCPU_PTR64_SEG(addr) \ + ((unsigned)((((MElf64_Xword)(addr)) & MELF_MCPU_PTR64_SEG_MASK) >> \ + MELF_MCPU_PTR64_SEG_SHIFT)) + +#define MELF_MCPU_PTR64_OFFSET(addr) \ + ((MElf64_Xword)(((MElf64_Xword)(addr)) & \ + MELF_MCPU_PTR64_OFFSET_MASK)) + + +/* + * Canonical architectural segment-base addresses for MELF64 ET_EXEC. + * + * Every program header describing a complete MCPU architectural space + * starts at byte offset zero of that space. + */ +#define MELF_MCPU_VADDR_DATA \ + MELF_MCPU_PTR64(MELF_MCPU_SEG_DATA, 0) + +#define MELF_MCPU_VADDR_STACK \ + MELF_MCPU_PTR64(MELF_MCPU_SEG_STACK, 0) + +#define MELF_MCPU_VADDR_PROGRAM \ + MELF_MCPU_PTR64(MELF_MCPU_SEG_PROGRAM, 0) + +#define MELF_MCPU_VADDR_CONTROL \ + MELF_MCPU_PTR64(MELF_MCPU_SEG_CONTROL, 0) + +#define MELF_MCPU_VADDR_INPUT \ + MELF_MCPU_PTR64(MELF_MCPU_SEG_INPUT, 0) + +#define MELF_MCPU_VADDR_OUTPUT \ + MELF_MCPU_PTR64(MELF_MCPU_SEG_OUTPUT, 0) + +#define MELF_MCPU_VADDR_TRACE \ + MELF_MCPU_PTR64(MELF_MCPU_SEG_TRACE, 0) + +#define MELF_MCPU_VADDR_HEAP \ + MELF_MCPU_PTR64(MELF_MCPU_SEG_HEAP, 0) + + +/* + * MELF32 program header. + * + * p_maxsz is a MELF extension. Its general meaning is the maximum + * architectural size allowed for the described MCPU space. + * + * Serialized ABI size: 36 bytes. + * + * MELF32 is reserved and is not accepted by MCPU ABI version 1. + */ +typedef struct +{ + MElf32_Word p_type; + MElf32_Off p_offset; + MElf32_Addr p_vaddr; + MElf32_Addr p_paddr; + MElf32_Word p_filesz; + MElf32_Word p_memsz; + MElf32_Word p_maxsz; + MElf32_Word p_flags; + MElf32_Word p_align; + +} MElf32_Phdr; + + +/* + * MELF64 program header. + * + * p_maxsz is a MELF extension beyond the conventional ELF64 Phdr. + * + * Serialized ABI size: 64 bytes. + */ +typedef struct +{ + MElf64_Word p_type; + MElf64_Word p_flags; + MElf64_Off p_offset; + MElf64_Addr p_vaddr; + MElf64_Addr p_paddr; + MElf64_Xword p_filesz; + MElf64_Xword p_memsz; + MElf64_Xword p_maxsz; + MElf64_Xword p_align; + +} MElf64_Phdr; + + +#define MELF32_PHDR_SIZE 36U +#define MELF64_PHDR_SIZE 64U + + +/* MELF32 program-header serialized offsets. */ +#define MELF32_PHDR_P_TYPE_OFF 0U +#define MELF32_PHDR_P_OFFSET_OFF 4U +#define MELF32_PHDR_P_VADDR_OFF 8U +#define MELF32_PHDR_P_PADDR_OFF 12U +#define MELF32_PHDR_P_FILESZ_OFF 16U +#define MELF32_PHDR_P_MEMSZ_OFF 20U +#define MELF32_PHDR_P_MAXSZ_OFF 24U +#define MELF32_PHDR_P_FLAGS_OFF 28U +#define MELF32_PHDR_P_ALIGN_OFF 32U + + +/* MELF64 program-header serialized offsets. */ +#define MELF64_PHDR_P_TYPE_OFF 0U +#define MELF64_PHDR_P_FLAGS_OFF 4U +#define MELF64_PHDR_P_OFFSET_OFF 8U +#define MELF64_PHDR_P_VADDR_OFF 16U +#define MELF64_PHDR_P_PADDR_OFF 24U +#define MELF64_PHDR_P_FILESZ_OFF 32U +#define MELF64_PHDR_P_MEMSZ_OFF 40U +#define MELF64_PHDR_P_MAXSZ_OFF 48U +#define MELF64_PHDR_P_ALIGN_OFF 56U + + +/* + * p_paddr. + * + * MCPU has no separate physical-address namespace in MELF ABI version 1. + * Therefore every non-NULL ABI-v1 program header has: + * + * p_paddr = 0 + * + * Writers emit zero and readers reject non-zero p_paddr unless a future + * ABI explicitly assigns it a meaning. + */ + + +/* + * p_align. + * + * p_align is a guest/file layout requirement, never a host mmap page size. + * + * Values 0 and 1 mean no special alignment. Any larger value must be a + * power of two. + * + * For MELF_PT_LOAD: + * + * p_offset % p_align == MELF_MCPU_PTR64_OFFSET(p_vaddr) % p_align + * + * Since ABI-v1 architectural load segments begin at segment offset zero, + * a nontrivial p_align therefore also aligns p_offset. + * + * p_align must be at least the maximum sh_addralign requirement of every + * allocated section contained in the segment. + * + * Host page rounding is outside the MELF ABI. + */ + + +/* + * Image-backed architectural spaces. + * + * A final ET_EXEC contains at most one MELF_PT_LOAD for each of: + * + * PROGRAM + * DATA + * CONTROL + * INPUT + * OUTPUT + * TRACE + * + * PROGRAM is mandatory. + * + * DATA is emitted by mcpu-ld when the final DATA architectural space is + * present. When present, it includes the single linker-owned 16-byte + * DATA NULL guard at offsets 0..15. + * + * CONTROL, INPUT, OUTPUT and TRACE load segments are emitted when the + * corresponding architectural space exists in the linked executable. + * + * STACK and HEAP never use MELF_PT_LOAD; they use the runtime-only + * descriptors MELF_PT_MCPU_STACK and MELF_PT_MCPU_HEAP below. + * + * Reserved selectors 0x8..0xf cannot appear in an ABI-v1 program header. + */ + + +/* + * MELF_PT_LOAD common rules. + * + * p_vaddr: + * full PTR64(segment, 0), identifying one complete MCPU architectural + * space. + * + * p_offset: + * file offset of the initial-image byte corresponding to architectural + * segment offset zero. If p_filesz == 0, no file bytes are consumed + * and p_offset has no load effect, though writers still keep it valid + * and aligned. + * + * p_filesz: + * number of bytes stored in MELF for the initial segment image. + * + * p_memsz: + * exact guest-visible architectural segment size. + * + * p_maxsz: + * equals p_memsz for every MELF_PT_LOAD in ABI version 1. + * + * Required relation: + * + * p_filesz <= p_memsz + * p_memsz == p_maxsz + * + * Load semantics: + * + * architectural bytes [0, p_filesz) are initialized from the file; + * architectural bytes [p_filesz, p_memsz) are initialized to zero. + * + * The stored file image includes any linker-created padding that lies + * before the last file-backed byte. Thus a PROGBITS section contained in + * a load segment obeys: + * + * sh_offset - p_offset == + * MELF_MCPU_PTR64_OFFSET(sh_addr) - + * MELF_MCPU_PTR64_OFFSET(p_vaddr) + * + * NOBITS sections consume architectural memory but no file payload. + * + * The loader creates independent anonymous host backing and copies/reads + * the initial image into it. MELF does not require or authorize direct + * file-backed guest mappings. + */ + + +/* + * PROGRAM load segment. + * + * Exactly one PROGRAM MELF_PT_LOAD exists in every ET_EXEC: + * + * p_type = MELF_PT_LOAD + * p_vaddr = MELF_MCPU_VADDR_PROGRAM + * p_paddr = 0 + * p_flags = MELF_PFLAGS_PROGRAM + * + * .init, .text and .fini remain separate section-header entities but are + * laid out in this one PROGRAM architectural space. Their lifecycle + * entry addresses are carried by MElf*_Ehdr, not by the Phdr. + * + * p_memsz is the exact final program.size used by CPU bounds checks. + */ + + +/* + * DATA load segment. + * + * When present: + * + * p_type = MELF_PT_LOAD + * p_vaddr = MELF_MCPU_VADDR_DATA + * p_paddr = 0 + * p_flags = MELF_PFLAGS_DATA + * + * DATA offsets 0..15 are the one linker-owned NULL guard. No ordinary + * linked object may occupy that range. + * + * .data and .bss map to this same architectural DATA space. + */ + + +/* + * CONTROL load segment. + * + * When present: + * + * p_type = MELF_PT_LOAD + * p_vaddr = MELF_MCPU_VADDR_CONTROL + * p_paddr = 0 + * p_flags = MELF_PFLAGS_CONTROL + * + * CONTROL is guest read-only. Its initial contents are linked from + * .control contributions. Host/runtime write access is not represented + * by MELF_PF_W. + */ + + +/* + * INPUT load segment. + * + * When present: + * + * p_type = MELF_PT_LOAD + * p_vaddr = MELF_MCPU_VADDR_INPUT + * p_paddr = 0 + * p_flags = MELF_PFLAGS_INPUT + * + * INPUT is guest read-only. The runtime may provide/update input values + * according to the execution/model policy defined outside guest write + * permissions. + */ + + +/* + * OUTPUT load segment. + * + * When present: + * + * p_type = MELF_PT_LOAD + * p_vaddr = MELF_MCPU_VADDR_OUTPUT + * p_paddr = 0 + * p_flags = MELF_PFLAGS_OUTPUT + */ + + +/* + * TRACE load segment. + * + * When present: + * + * p_type = MELF_PT_LOAD + * p_vaddr = MELF_MCPU_VADDR_TRACE + * p_paddr = 0 + * p_flags = MELF_PFLAGS_TRACE + * + * TRACE represents the current telemetry frame, not an accumulating log. + */ + + +/* + * Runtime-created STACK descriptor. + * + * STACK has no MELF file payload. + * + * Exactly one MELF_PT_MCPU_STACK is mandatory in every ET_EXEC: + * + * p_type = MELF_PT_MCPU_STACK + * p_offset = 0 + * p_vaddr = MELF_MCPU_VADDR_STACK + * p_paddr = 0 + * p_filesz = 0 + * p_memsz = initial allocated STACK size + * p_maxsz = p_memsz + * p_flags = MELF_PFLAGS_STACK + * p_align = at least 16 + * + * ABI version 1 describes a fixed allocated STACK size; p_maxsz therefore + * equals p_memsz. + * + * Before startup data is constructed an empty allocated stack has: + * + * SP = FP = stack_size + * + * The loader then constructs the persistent ABI-v1 startup area at the + * high end of STACK and sets the architectural initial SP/FP according to + * the stage-8 startup contract below. + * + * STACK size is part of the executable ABI. mcpu-run has no stack-size + * override for MELF and must not replace p_memsz with a command-line or + * host policy value. + */ + + +/* + * Runtime-created HEAP descriptor. + * + * HEAP has no MELF file payload and is always created zero-filled. + * + * When MELF_PT_MCPU_HEAP is present: + * + * p_type = MELF_PT_MCPU_HEAP + * p_offset = 0 + * p_vaddr = MELF_MCPU_VADDR_HEAP + * p_paddr = 0 + * p_filesz = 0 + * p_memsz = initial zero-filled HEAP backing/logical extent + * p_maxsz = immutable maximum HEAP size permitted by the executable profile + * p_flags = MELF_PFLAGS_HEAP + * p_align = at least 16 + * + * Required relation: + * + * p_memsz <= p_maxsz + * + * HEAP offsets 0..15 remain the architectural heap guard. Therefore a + * non-empty ABI-v1 HEAP descriptor must reserve at least those 16 bytes. + * + * The linker-defined symbol _end is HEAP:16. At process start _end is + * also the initial program break and the minimum value to which the break + * may ever be reduced. Guest HEAP dereference is bounded by the current + * program break, not by p_memsz or by host mapping capacity. + * + * p_maxsz records an immutable executable heap limit. SYS_brk may move + * the program break in the inclusive range [HEAP:16, p_maxsz]. LibMCPU + * may grow or relocate host backing when required, but p_maxsz is never + * enlarged and guest PTR64 HEAP values remain segment+offset addresses. + * Shrinking the break keeps the backing allocation and zeroes the released + * range before it can later become accessible again. + */ + + +/* + * Program Header Table consistency with Section Headers. + * + * Every MELF_SHF_ALLOC section in ET_EXEC must belong to exactly one + * image-backed MELF_PT_LOAD whose segment selector matches the selector + * encoded in sh_flags and in sh_addr. + * + * For every such section: + * + * MELF_MCPU_PTR64_SEG(sh_addr) == + * MELF_MCPU_PTR64_SEG(p_vaddr) + * + * and the complete architectural range: + * + * [OFFSET(sh_addr), OFFSET(sh_addr) + sh_size) + * + * must lie within: + * + * [0, p_memsz) + * + * Non-ALLOC metadata sections (.symtab, .strtab, .shstrtab, + * .mcpu.target, .mcpu.lifecycle, .rela.*) do not require and must not + * acquire guest PT_LOAD coverage solely because they exist in the file. + */ + + +/* + * Canonical ABI-v1 program-header order. + * + * mcpu-ld emits entries in this deterministic order when present: + * + * PROGRAM + * DATA + * CONTROL + * INPUT + * OUTPUT + * TRACE + * STACK + * HEAP + * + * Readers must identify entries by p_type/p_vaddr and must not depend on + * table order. Duplicate descriptors for one architectural MCPU space + * are invalid in ABI version 1. + */ + + +/* + * -------------------------------------------------------------------------- + * Static-linker, loader/startup and runtime lifecycle contract + * -------------------------------------------------------------------------- + * + * This section fixes specification stage 8. + * + * Core rule: + * + * mcpu-ld constructs the complete executable image. + * mcpu-run validates and instantiates it. + * mcpu-run never repairs or relinks it. + */ + + +/* + * -------------------------------------------------------------------------- + * Static linker contract: mcpu-ld + * -------------------------------------------------------------------------- + * + * mcpu-ld is responsible for all link-time semantic work before ET_EXEC is + * handed to the loader. + * + * For ABI-v1 output mcpu-ld must: + * + * 1. accept only compatible MCPU ET_REL input profiles; + * + * 2. resolve LOCAL/GLOBAL/WEAK symbols according to the symbol ABI; + * + * 3. reject unresolved strong GLOBAL symbols; + * + * 4. evaluate and apply every required RELA relocation, including all + * segment restrictions, signed-addend checks and range checks; + * + * 5. construct final PROGRAM/DATA/CONTROL/INPUT/OUTPUT/TRACE layouts; + * + * 6. insert exactly one linker-owned 16-byte DATA NULL guard at + * DATA offsets 0..15 when final DATA exists; + * + * 7. preserve the required alignment of every input contribution; + * + * 8. compute final sh_addr/st_value architectural addresses; + * + * 9. validate the lifecycle symbols and write: + * + * e_entry + * e_init_entry + * e_life_entry + * e_fini_entry + * + * 10. emit the final Program Header Table, including exactly one + * mandatory MELF_PT_MCPU_STACK descriptor; + * + * 11. emit the final .mcpu.target and .mcpu.lifecycle metadata; + * + * 12. set all executable segment sizes and limits, including STACK size + * and optional HEAP initial/maximum sizes. + * + * ABI-v1 ET_EXEC contains no unresolved/runtime relocation requirement. + * SHT_RELA sections are ET_REL link input; mcpu-ld does not emit SHT_RELA + * sections into the final ABI-v1 ET_EXEC. + * + * A symbol table may be retained in ET_EXEC for diagnostics/debugging, but + * the runtime loader must not require _start/_life/_fini symbol names. + * Numeric Ehdr lifecycle entries are authoritative at runtime. + */ + + +/* + * STACK size is executable ABI. + * + * The legacy mcpu-run --stack-size behavior is not part of the MELF ABI and + * must be removed from the MELF runtime. mcpu-run does not accept an + * alternate STACK size for a MELF executable. + * + * The final STACK size is p_memsz of MELF_PT_MCPU_STACK and can only be + * changed by producing/relinking a different executable. + */ + + +/* + * -------------------------------------------------------------------------- + * ABI-v1 startup area + * -------------------------------------------------------------------------- + * + * The loader constructs a persistent startup area in STACK before the + * first instruction of _start executes. + * + * All numeric fields and PTR64 values in this guest structure use the + * target architectural data-object representation. It is NOT a MELF + * metadata record and is NOT serialized with host C structure layout. + */ + + +/* Startup-area structure/layout version. */ +#define MCPU_STARTUP_VERSION_NONE 0U +#define MCPU_STARTUP_VERSION_1 1U +#define MCPU_STARTUP_VERSION_CURRENT MCPU_STARTUP_VERSION_1 + + +/* Startup block layout constants. */ +#define MCPU_STARTUP_ALIGN 16U +#define MCPU_STARTUP_SIZE 32U +#define MCPU_STARTUP_ARGV_SIZE 8U + + +/* + * Guest PTR64 scalar used by the startup ABI. + * + * Current MCPU ABI is intrinsically PTR64 even though a future MELF32 + * container class remains reserved. + */ +typedef __mpu_uint64_t McpuPtr64; + + +/* + * Persistent startup header. + * + * The type name intentionally does not carry "V1": the structure itself + * contains a version field. + * + * Guest-memory ABI layout: + * + * +0x00 uint32 version + * +0x04 uint32 size + * +0x08 uint64 argc + * +0x10 PTR64 argv + * +0x18 uint64 reserved + * + * version = MCPU_STARTUP_VERSION_1 + * size = MCPU_STARTUP_SIZE + * argc = number of argument strings + * argv = PTR64(STACK, argv_array_offset) + * reserved = 0 + */ +typedef struct McpuStartup +{ + __mpu_uint32_t version; + __mpu_uint32_t size; + + __mpu_uint64_t argc; + McpuPtr64 argv; + + __mpu_uint64_t reserved; + +} McpuStartup; + + +#define MCPU_STARTUP_VERSION_OFF 0U +#define MCPU_STARTUP_SIZE_OFF 4U +#define MCPU_STARTUP_ARGC_OFF 8U +#define MCPU_STARTUP_ARGV_OFF 16U +#define MCPU_STARTUP_RESERVED_OFF 24U + + +/* + * argv[] representation. + * + * argv points to an array of argc + 1 guest PTR64 values: + * + * argv[0] -> first argument byte string + * ... + * argv[argc - 1] -> last argument byte string + * argv[argc] = 0 (NULL) + * + * Every non-NULL argv[i] is PTR64(STACK, string_offset). + * + * Argument strings are NUL-terminated byte strings copied into the + * persistent startup area. The byte-string interpretation supplied by + * the invoking runtime/toolchain is outside the MELF container ABI; the + * loader does not perform target-endian conversion on string bytes. + * + * argc == 0 is valid and still creates the terminating argv[0] == NULL. + */ + + +/* + * Canonical ABI-v1 startup-area layout. + * + * Let: + * + * stack_size = MELF_PT_MCPU_STACK.p_memsz + * + * The loader computes: + * + * header_bytes = MCPU_STARTUP_SIZE + * argv_bytes = (argc + 1) * MCPU_STARTUP_ARGV_SIZE + * string_bytes = sum(strlen(argument[i]) + 1) + * + * with checked arithmetic. + * + * The variable data are arranged from low to high addresses as: + * + * startup_base: + * McpuStartup + * argv[argc + 1] + * argument string bytes + * zero padding, if any + * stack_size: + * + * startup_base is chosen so that: + * + * startup_base % MCPU_STARTUP_ALIGN == 0 + * + * and the whole startup region: + * + * [startup_base, stack_size) + * + * fits in the allocated STACK. + * + * The argv array is naturally 8-byte aligned because McpuStartup is + * 32 bytes and startup_base is 16-byte aligned. + * + * The loader writes: + * + * McpuStartup.version = MCPU_STARTUP_VERSION_1 + * McpuStartup.size = MCPU_STARTUP_SIZE + * McpuStartup.argc = argc + * McpuStartup.argv = PTR64(STACK, + * startup_base + MCPU_STARTUP_SIZE) + * McpuStartup.reserved = 0 + * + * All unused padding bytes in the startup region are zero. + * + * If the supplied argument set does not fit while preserving the required + * alignment, program startup fails. mcpu-run must not enlarge STACK to + * make the invocation fit. + */ + + +/* + * Initial architectural state supplied by the loader. + * + * After STACK allocation and startup-area construction: + * + * PC = e_entry + * SP = startup_base + * FP = stack_size + * + * No artificial CALL frame or return PC is created for _start. + * + * Other CPU reset state is defined by the MCPU execution/reset contract; + * argc/argv are not passed through hidden host pointers or host registers. + * + * The startup region remains allocated and valid for the entire executable + * lifetime. Normal ABI stack frames grow downward below startup_base. + * The runtime never reclaims or moves the startup region. + */ + + +/* + * Initial _life argument source. + * + * _life is responsible for constructing the ordinary MCPU CALL-ABI + * argument block for main(argc, argv). main() is never entered directly + * by the loader. + * + * At the initial top-level lifecycle stack state, SP points to + * McpuStartup. _life obtains argc and argv from that structure, converts/ + * lays out arguments according to the language CALL ABI if required, and + * CALLs main. + */ + + +/* + * Top-level lifecycle stack discipline. + * + * Runtime lifecycle transitions do not silently repair SP or FP. + * + * If .init exists, _start may use ordinary stack frames during INIT, but + * before its normal terminating END it must restore the top-level state: + * + * SP = startup_base + * FP = stack_size + * + * The runtime then changes PC to e_life_entry and leaves the remaining + * architectural context live. + * + * A normal _life trampoline similarly unwinds its main() call and argument + * block before executing EXIT, so graceful FINI entry sees the same + * top-level stack state. + * + * _fini may use ordinary stack frames but must unwind them before its + * normal terminating END. + * + * This rule keeps McpuStartup reachable at SP on each initial lifecycle + * entry without introducing a hidden startup register. + */ + + +/* + * -------------------------------------------------------------------------- + * Assembler lifecycle convenience syntax + * -------------------------------------------------------------------------- + * + * When .init is absent, mcpu-as accepts: + * + * .text + * _start_life: + * ... + * + * as an assembler-only pseudo-label exactly equivalent to: + * + * .text + * _start: + * _life: + * ... + * + * mcpu-as emits the two normative MELF symbols: + * + * _start STB_GLOBAL / STT_FUNC + * _life STB_GLOBAL / STT_FUNC + * + * at the same section-relative byte offset. + * + * mcpu-as does not need to emit a distinct "_start_life" MELF symbol. + * + * It is an assembler error to use _start_life: if _start or _life has + * already been defined in the same translation unit. + * + * A final executable containing .init cannot use the _start_life form: + * with .init, _start must belong to .init and _life to .text. + */ + + +/* + * -------------------------------------------------------------------------- + * Loader structural-validation contract + * -------------------------------------------------------------------------- + * + * mcpu-run validates a MELF ET_EXEC before executing guest code. + * + * Validation must use checked integer arithmetic for every file offset, + * count, size, alignment and end-position calculation. A wraparound is a + * load error. + * + * The loader performs at least the following validation classes before + * guest execution: + * + * A. MELF identification/header + * - magic "_ELF"; + * - MELF_CLASS_64 for ABI v1; + * - supported EI_DATA; + * - EI_VERSION/e_version == MELF_EV_CURRENT; + * - OSABI == MELF_OSABI_MCPU; + * - ABI version == MELF_ABIVERSION_CURRENT; + * - e_type == MELF_ET_EXEC; + * - e_machine == MELF_EM_MCPU; + * - e_flags == MELF_EF_MCPU_NONE; + * - e_ehsize == MELF64_EHDR_SIZE; + * - e_phentsize == MELF64_PHDR_SIZE; + * - valid section/program-header table file ranges. + * + * B. target/lifecycle metadata + * - exactly one MELF_SHT_MCPU_TARGET; + * - exactly one MELF_SHT_MCPU_LIFECYCLE; + * - valid record sizes/versions/reserved fields; + * - target profile supported by this runtime; + * - mt_data_byte_order == EI_DATA; + * - lifecycle ABI/flags exactly supported by ABI v1. + * + * C. Program Header Table + * - exactly one PROGRAM MELF_PT_LOAD; + * - exactly one MELF_PT_MCPU_STACK; + * - at most one DATA/CONTROL/INPUT/OUTPUT/TRACE load descriptor; + * - at most one MELF_PT_MCPU_HEAP; + * - no duplicate architectural segment descriptors; + * - no reserved selector 0x8..0xf; + * - canonical guest permission flags; + * - p_paddr == 0; + * - valid p_align; + * - p_filesz <= p_memsz; + * - PT_LOAD p_maxsz == p_memsz; + * - STACK p_filesz == 0 and p_maxsz == p_memsz; + * - HEAP p_filesz == 0 and p_memsz <= p_maxsz; + * - every architectural size/offset fits PTR64 OFF60. + * + * D. section-to-segment consistency + * - every SHF_ALLOC section belongs to exactly one matching PT_LOAD; + * - sh_addr selector agrees with sh_flags and p_vaddr; + * - section ranges lie inside segment p_memsz; + * - PROGBITS file ranges lie inside the corresponding load image; + * - metadata sections are non-ALLOC. + * + * E. lifecycle entries + * - e_entry and e_life_entry are nonzero PROGRAM PTR64 values; + * - optional e_init_entry/e_fini_entry are zero or PROGRAM PTR64; + * - every nonzero lifecycle entry offset is < PROGRAM p_memsz; + * - with INIT: e_init_entry == e_entry; + * - without INIT: e_init_entry == 0 and e_entry == e_life_entry; + * - lifecycle/header metadata are mutually consistent. + * + * Runtime loading does not require a symbol table. When a symbol table is + * retained, additional diagnostic consistency checks are allowed, but + * stripping ordinary .symtab/.strtab must not change executable behavior. + */ + + +/* + * DATA NULL-guard validation. + * + * If a DATA segment exists, its architectural size must be at least + * 16 bytes and final loaded DATA bytes 0..15 must all be zero. + * + * The loader does not insert or repair this guard: mcpu-ld owns it. + */ + + +/* + * -------------------------------------------------------------------------- + * Runtime image-instantiation contract + * -------------------------------------------------------------------------- + * + * Program Headers, not Section Headers, are the authoritative runtime + * description of architectural memory spaces. + * + * The loader uses Section Headers for required non-ALLOC metadata and + * optional diagnostics, but it does not concatenate sections to construct + * PROGRAM/DATA/etc. at runtime. + * + * For each image-backed PT_LOAD the runtime: + * + * 1. creates independent anonymous backing of at least p_memsz bytes; + * 2. initializes all architectural bytes [0, p_memsz) to zero; + * 3. copies p_filesz bytes verbatim from MELF file offset p_offset to + * architectural offset zero; + * 4. records exact architectural size = p_memsz; + * 5. enforces the guest permissions represented by p_flags. + * + * File payload bytes are copied verbatim: + * + * - PROGRAM already contains canonical MSB-first machine fields; + * - DATA-like payload already contains target data-object representation. + * + * The loader never byte-swaps an image payload to match the host. + * + * Host page size, rounded mapping capacity, chosen host base address and + * use of mprotect() are implementation details outside the guest ABI. + * Guest bounds checks always use exact architectural p_memsz. + * + * MELF does not require or authorize guest architectural state to depend + * on a file-backed mmap address. + */ + + +/* + * STACK instantiation. + * + * Exactly one MELF_PT_MCPU_STACK is mandatory. + * + * The runtime creates zero-filled writable STACK backing of exactly + * p_memsz guest-visible bytes, then writes the persistent startup area at + * the high end as specified above. + * + * The runtime does not change STACK size according to command-line policy. + */ + + +/* + * HEAP instantiation. + * + * MELF_PT_MCPU_HEAP is optional. + * + * If present, the runtime creates zero-filled writable HEAP backing with + * initial architectural size p_memsz and configured maximum p_maxsz. + * + * HEAP offsets 0..15 remain the heap guard. Future growth may increase + * architectural heap.size up to p_maxsz through a separately defined + * runtime/system-call ABI; such growth is not an ELF relocation or loader + * repair operation. + */ + + +/* + * Guest read-only spaces. + * + * PROGRAM, CONTROL and INPUT are guest write-protected according to their + * canonical p_flags. + * + * The host/runtime may update CONTROL/INPUT backing only as permitted by + * the execution/model runtime contract. Host write access does not imply + * MELF_PF_W and does not alter guest permissions. + */ + + +/* + * -------------------------------------------------------------------------- + * Runtime lifecycle state machine + * -------------------------------------------------------------------------- + * + * Initial entry: + * + * loader constructs all memory and McpuStartup; + * PC = e_entry; + * execution begins at _start. + * + * No .init: + * + * e_init_entry == 0 + * e_entry == e_life_entry + * _start and _life are the same PROGRAM address. + * + * Therefore the first instruction simultaneously begins START/LIFE. + * + * With .init: + * + * e_entry == e_init_entry -> _start in .init. + * + * Normal INIT completion is END. After CPU_STOP_END the runtime begins + * LIFE by setting: + * + * PC = e_life_entry + * + * and otherwise preserving the live architectural context. The ABI + * top-level stack-discipline rule above requires _start to have restored + * SP/FP before this END. + * + * LIFE: + * + * END is a cooperative boundary. Decoder/executor has already advanced + * PC to the instruction after END. Runtime may consume OUTPUT/TRACE, + * update INPUT/time/scheduling state, and later resumes the saved PC. + * + * Runtime MUST NOT jump back to _life on LIFE resume. + * + * EXIT: + * + * EXIT records the signed program status and requests graceful + * termination. + * + * If e_fini_entry == 0, execution becomes FINISHED(status). + * + * If e_fini_entry != 0, runtime enters FINI exactly once by setting: + * + * PC = e_fini_entry + * + * and preserving the exit status until FINI completes. + * + * FINI: + * + * normal FINI completion is END, after which the entity becomes + * FINISHED(saved_exit_status). + * + * HALT, architectural fault and external forced termination are not + * graceful EXIT and do not automatically enter _fini. + */ + + +/* + * -------------------------------------------------------------------------- + * Loader validates, never repairs + * -------------------------------------------------------------------------- + * + * For MELF ABI version 1 mcpu-run must not: + * + * - resolve symbols; + * - apply RELA relocations; + * - insert the DATA NULL guard; + * - rewrite sh_addr/st_value/p_vaddr; + * - reorder target data bytes for host endian; + * - translate one target profile into another; + * - invent missing _start/_life lifecycle entries; + * - infer lifecycle entries from section names; + * - resize STACK; + * - override PT_MCPU_STACK with --stack-size; + * - change HEAP limits from executable values; + * - reinterpret malformed executable metadata in order to continue. + * + * Any contradiction in required ABI-v1 metadata/layout is a load error + * before guest execution. + */ + + +/* + * -------------------------------------------------------------------------- + * MELF ABI version 2: explicit startup dynamic linking + * -------------------------------------------------------------------------- + * + * ABI-v2 dynamic linking is deliberately a startup-only facility. It does + * not define DT_NEEDED, SONAME/RPATH, PLT/GOT, lazy binding, dlopen(), + * dlclose() or dlsym(). mcpu-run receives every shared object explicitly via + * --ldpreload=a.so:b.so and completes all symbol resolution/RELA processing + * before the first _start instruction executes. + * + * ABI-v3 keeps the same image, symbol and RELA model and adds the non-ALLOC + * .dynamic metadata described above. ABI-v3 ET_DYN has an explicit SONAME; + * ABI-v3 ET_EXEC/ET_DYN may record NEEDED names. Dependency discovery and + * recursive loading are defined incrementally while ABI-v3 remains unfrozen. + * + * Historical ABI-v2 ET_EXEC/ET_DYN files remain accepted by mcpu-run. + * Beginning with LibMCPU 0.2.14, mcpu-ld --dynamic and mcpu-ld --shared + * produce ABI-v3 files. ABI-v3 ET_EXEC still owns STACK/HEAP and the ordinary + * executable lifecycle and retains relocations through preemptible + * GLOBAL/WEAK names in runtime .rela.* sections. + * + * ABI-v2 and ABI-v3 ET_DYN contain only library .text/.data/.bss plus + * non-ALLOC metadata. They have no .init/.fini, CONTROL/INPUT/OUTPUT/TRACE, + * PT_MCPU_STACK/PT_MCPU_HEAP or lifecycle entry points. ET_DYN DATA starts at + * relative offset zero and has no per-library NULL guard; the process owns + * exactly one DATA NULL guard. ABI-v3 ET_DYN additionally requires SONAME. + * + * Runtime symbols are separate from developer/debug symbols: + * + * .dynsym / .dynstr startup-link ABI and therefore retained; + * .symtab / .strtab optional developer/debug information. + * + * ABI-v2/ABI-v3 .dynsym uses MElf64_Sym. Entry zero is all-zero. All nonzero + * entries use DEFAULT visibility and GLOBAL/WEAK binding. Defined st_value + * is byte offset relative to the output section named by st_shndx. Undefined + * entries have SHN_UNDEF and st_value/st_size zero. + * + * ABI-v2/ABI-v3 runtime SHT_RELA sections use MElf64_Rela and link to .dynsym. + * sh_info names the allocated section containing the relocation field. + * r_offset is a byte offset relative to that output section. This makes a + * retained relocation independent of the final process base assigned to an + * ET_DYN module. The five existing MCPU relocation meanings and byte-order + * domains are unchanged. + * + * Symbol interposition namespace for: + * + * --ldpreload=a.so:b.so:c.so + * + * is main, a, b, c with later modules having higher priority among symbols of + * the same binding. A strong GLOBAL definition always wins over every WEAK + * definition; among GLOBALs the rightmost module wins, and when no GLOBAL + * exists the rightmost WEAK wins. Interposition applies even to a reference + * whose originating module also defines that DEFAULT GLOBAL/WEAK name. + * Lifecycle names _start/_life/_fini are executable-private and never + * preemptible. + * + * An unresolved strong runtime symbol is a load error before execution. + * An unresolved WEAK pointer relocation with addend zero resolves to NULL as + * in the static ABI; other unresolved WEAK relocation uses are errors. + */ + +/* + * -------------------------------------------------------------------------- + * Current target aliases + * -------------------------------------------------------------------------- + * + * CPU_MELF_CLASS is a TARGET configuration property, never a property of + * the host compiler/platform. ABI version 1 supports MELF_CLASS_64 only. + */ + +#ifndef CPU_MELF_CLASS +#define CPU_MELF_CLASS MELF_CLASS_64 +#endif + +#if CPU_MELF_CLASS == MELF_CLASS_64 + +typedef MElf64_Half MElfN_Half; +typedef MElf64_Word MElfN_Word; +typedef MElf64_Sword MElfN_Sword; +typedef MElf64_Xword MElfN_Xword; +typedef MElf64_Sxword MElfN_Sxword; +typedef MElf64_Addr MElfN_Addr; +typedef MElf64_Off MElfN_Off; + +typedef MElf64_Ehdr MElfN_Ehdr; +typedef MElf64_Shdr MElfN_Shdr; +typedef MElf64_Sym MElfN_Sym; +typedef MElf64_Rela MElfN_Rela; +typedef MElf64_Phdr MElfN_Phdr; + +#define MELFN_EHDR_SIZE MELF64_EHDR_SIZE +#define MELFN_SHDR_SIZE MELF64_SHDR_SIZE +#define MELFN_SYM_SIZE MELF64_SYM_SIZE +#define MELFN_RELA_SIZE MELF64_RELA_SIZE +#define MELFN_PHDR_SIZE MELF64_PHDR_SIZE + +#define MELFN_R_SYM(info) MELF64_R_SYM(info) +#define MELFN_R_TYPE(info) MELF64_R_TYPE(info) +#define MELFN_R_INFO(sym,type) MELF64_R_INFO((sym),(type)) + +#elif CPU_MELF_CLASS == MELF_CLASS_32 + +/* + * The type names exist for forward compatibility, but MCPU ABI version 1 + * does not accept MELF32 files. + */ +typedef MElf32_Half MElfN_Half; +typedef MElf32_Word MElfN_Word; +typedef MElf32_Sword MElfN_Sword; +typedef MElf32_Addr MElfN_Addr; +typedef MElf32_Off MElfN_Off; + +typedef MElf32_Ehdr MElfN_Ehdr; +typedef MElf32_Shdr MElfN_Shdr; +typedef MElf32_Sym MElfN_Sym; +typedef MElf32_Rela MElfN_Rela; +typedef MElf32_Phdr MElfN_Phdr; + +#define MELFN_EHDR_SIZE MELF32_EHDR_SIZE +#define MELFN_SHDR_SIZE MELF32_SHDR_SIZE +#define MELFN_SYM_SIZE MELF32_SYM_SIZE +#define MELFN_RELA_SIZE MELF32_RELA_SIZE +#define MELFN_PHDR_SIZE MELF32_PHDR_SIZE + +#define MELFN_R_SYM(info) MELF32_R_SYM(info) +#define MELFN_R_TYPE(info) MELF32_R_TYPE(info) +#define MELFN_R_INFO(sym,type) MELF32_R_INFO((sym),(type)) + +#else +#error "Unsupported CPU_MELF_CLASS" +#endif + + +#endif /* MCPU_ELF_H */ |
