summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/libmcpu.h729
-rw-r--r--include/mcpu-elf.h3120
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 */