/* * 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 /* * -------------------------------------------------------------------------- * 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 */