diff options
| author | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
|---|---|---|
| committer | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
| commit | 065da3509019b15dd0e678072e6be629e5330bef (patch) | |
| tree | 69c934c9e786ac048b4fbe8f4c4c5571661521f4 /tests/tst-pointer-policy.c | |
| parent | d130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff) | |
| download | libmcpu-0.4.0.tar.xz | |
Version 0.4.00.4.0
Diffstat (limited to 'tests/tst-pointer-policy.c')
| -rw-r--r-- | tests/tst-pointer-policy.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/tests/tst-pointer-policy.c b/tests/tst-pointer-policy.c new file mode 100644 index 0000000..15d3b0f --- /dev/null +++ b/tests/tst-pointer-policy.c @@ -0,0 +1,152 @@ +#include <stdio.h> +#include <string.h> +#include <libmcpu.h> + +#define CHECK(c,m) do{if(!(c)){fprintf(stderr,"FAIL: %s\n",m);return 1;}}while(0) + +static void +regop( cpu_operand *o, unsigned bits, unsigned address ) +{ + memset( o, 0, sizeof( *o ) ); + o->type = CPU_OPERAND_REGISTER; + o->value.reg.bits = bits; + o->value.reg.address = address; +} + +static void +set_u64( unsigned address, __mpu_uint64_t v ) +{ + __cpu_data_put_u64( __cpu_reg_ptr( 64, address ), v ); +} + +static __mpu_uint64_t +get_u64( unsigned address ) +{ + return( __cpu_data_get_u64( __cpu_reg_ptr( 64, address ) ) ); +} + +static int +exec2( cpu_opcode op, unsigned a, unsigned b ) +{ + cpu_instruction i; + memset( &i, 0, sizeof( i ) ); + i.opcode = op; + regop( &i.operand[0], 64, a ); + regop( &i.operand[1], 64, b ); + return( __cpu_exec( &i ) ); +} + +static int +exec3( cpu_opcode op, unsigned d, unsigned a, unsigned b ) +{ + cpu_instruction i; + memset( &i, 0, sizeof( i ) ); + i.opcode = op; + regop( &i.operand[0], 64, d ); + regop( &i.operand[1], 64, a ); + regop( &i.operand[2], 64, b ); + return( __cpu_exec( &i ) ); +} + +int +main( void ) +{ + __mpu_uint64_t p, q, saved; + __mpu_UNIT_t code[2] = + { + 0, 0 + }; + cpu_instruction i; + + __cpu_init(); + CHECK( CPU_ABI_STACK_RED_ZONE_SIZE == 0U, "ABI red zone is zero bytes" ); + CHECK( __cpu_data_alloc( 128 ) == 0, "DATA alloc" ); + CHECK( __cpu_stack_alloc( 128 ) == 0, "STACK alloc" ); + CHECK( __cpu_program_set( code, sizeof( code ) ) == 0, "PROGRAM set" ); + + /* Pointer equality is full 64-bit equality and can be tested with ICMP/ZF. */ + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 32 ) == 0, "make DATA pointer p" ); + CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_DATA, 32 ) == 0, "make equal DATA pointer q" ); + set_u64( 0x100, p ); + set_u64( 0x108, q ); + CHECK( exec2( CPU_OP_ICMP, 0x100, 0x108 ) == CPU_EXEC_SUCCESS, "ICMP equal pointers" ); + CHECK( ( __cpu_get_psw() & PSW_ZF_MASK ) != 0, "equal PTR64 sets ZF" ); + + CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_STACK, 32 ) == 0, "make STACK pointer q" ); + set_u64( 0x108, q ); + CHECK( exec2( CPU_OP_ICMP, 0x100, 0x108 ) == CPU_EXEC_SUCCESS, "ICMP cross-segment bit patterns" ); + CHECK( ( __cpu_get_psw() & PSW_ZF_MASK ) == 0, "different segments are not equal" ); + + /* Pointer ordering is defined by PDIFF only inside one selector. */ + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 64 ) == 0, "make lower DATA pointer" ); + CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_DATA, 96 ) == 0, "make upper DATA pointer" ); + set_u64( 0x100, p ); + set_u64( 0x108, q ); + CHECK( exec3( CPU_OP_PDIFF, 0x110, 0x100, 0x108 ) == CPU_EXEC_SUCCESS, "same-segment PDIFF" ); + CHECK( (__mpu_int64_t)get_u64( 0x110 ) == -32, "PDIFF gives signed byte difference" ); + CHECK( exec2( CPU_OP_ITEST, 0x110, 0x110 ) == CPU_EXEC_SUCCESS, "ITEST pointer difference" ); + CHECK( ( __cpu_get_psw() & PSW_SF_MASK ) != 0, "negative pointer difference sets SF" ); + + saved = __mpu_UINT64_C( 0x1122334455667788 ); + set_u64( 0x110, saved ); + CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_STACK, 96 ) == 0, "make cross-segment pointer" ); + set_u64( 0x108, q ); + CHECK( exec3( CPU_OP_PDIFF, 0x110, 0x100, 0x108 ) == CPU_EXEC_POINTER_FAULT, "PDIFF rejects cross-segment ordering" ); + CHECK( get_u64( 0x110 ) == saved, "PDIFF cross-segment fault is atomic" ); + + /* Reserved selectors are structurally valid and support non-dereferencing arithmetic. */ + CHECK( __cpu_ptr_make( &p, 0x0f, 123 ) == 0, "make reserved pointer p" ); + CHECK( __cpu_ptr_make( &q, 0x0f, 100 ) == 0, "make reserved pointer q" ); + set_u64( 0x100, p ); + set_u64( 0x108, q ); + CHECK( exec3( CPU_OP_PDIFF, 0x110, 0x100, 0x108 ) == CPU_EXEC_SUCCESS, "reserved same-selector PDIFF" ); + CHECK( (__mpu_int64_t)get_u64( 0x110 ) == 23, "reserved PDIFF difference" ); + + /* A reserved PTR64 may be stored as data but may not be dereferenced. */ + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_STORE; + i.operand[0].type = CPU_OPERAND_ADDR64; + i.operand[0].value.addr64 = 16; + regop( &i.operand[1], 64, 0x100 ); + CHECK( __cpu_exec( &i ) == CPU_EXEC_SUCCESS, "STORE preserves reserved PTR64 as ordinary data" ); + CHECK( __cpu_data_get_u64( __cpu_data_ptr() + 16 ) == p, "stored reserved PTR64 bits" ); + + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_LOADP; + regop( &i.operand[0], 64, 0x118 ); + regop( &i.operand[1], 64, 0x100 ); + CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "LOADP rejects reserved selector" ); + + /* Even a zero-length BMOVI requires semantically valid address-space selectors. */ + CHECK( __cpu_ptr_make( &q, CPU_PTR_SEG_DATA, 16 ) == 0, "make valid DATA pointer" ); + set_u64( 0x108, q ); + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_BMOVI; + regop( &i.operand[0], 64, 0x108 ); + regop( &i.operand[1], 64, 0x100 ); + i.operand[2].type = CPU_OPERAND_IMM64; + i.operand[2].value.imm64 = 0; + CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "zero-length BMOVI rejects reserved source" ); + + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_JMPP; + regop( &i.operand[0], 64, 0x100 ); + CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "JMPP rejects reserved selector" ); + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_CALLP; + regop( &i.operand[0], 64, 0x100 ); + CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "CALLP rejects reserved selector" ); + memset( &i, 0, sizeof( i ) ); + i.opcode = CPU_OP_SETSP; + regop( &i.operand[0], 64, 0x100 ); + CHECK( __cpu_exec( &i ) == CPU_EXEC_POINTER_FAULT, "SETSP rejects reserved selector" ); + + /* DATA offsets 1..15 are ABI-reserved guard values, but only all-zero PTR64 is NULL. */ + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 1 ) == 0, "make DATA guard pointer" ); + CHECK( p != CPU_NULL_PTR, "DATA:1 is not NULL" ); + CHECK( __cpu_ptr_make( &p, CPU_PTR_SEG_DATA, 0 ) == 0 && p == CPU_NULL_PTR, "DATA:0 is canonical NULL" ); + + __cpu_free_context(); + puts( "libcpu pointer-comparison/red-zone/reserved-segment policy regression: PASS" ); + return( 0 ); +} |
