#include #include #include #include #include #include #include "mcpu-melf.h" int cpu_melf_data_encoding( void ) { #if CPU_DATA_BYTE_ORDER_LITTLE_ENDIAN == 1 return( MELF_DATA_LSB ); #elif CPU_DATA_BYTE_ORDER_BIG_ENDIAN == 1 return( MELF_DATA_MSB ); #else # error "Unsupported CPU_DATA_BYTE_ORDER" #endif } static int is_le( int data ) { return( data == MELF_DATA_LSB ); } void cpu_melf_put16( unsigned char *p, __mpu_uint16_t v, int data ) { if( is_le( data ) ) { p[0] = (unsigned char)v; p[1] = (unsigned char)(v >> 8); } else { p[0] = (unsigned char)(v >> 8); p[1] = (unsigned char)v; } } void cpu_melf_put32( unsigned char *p, __mpu_uint32_t v, int data ) { unsigned i; if( is_le( data ) ) for( i = 0; i < 4; ++i ) p[i] = (unsigned char)(v >> (8 * i)); else for( i = 0; i < 4; ++i ) p[i] = (unsigned char)(v >> (8 * (3 - i))); } void cpu_melf_put64( unsigned char *p, __mpu_uint64_t v, int data ) { unsigned i; if( is_le( data ) ) for( i = 0; i < 8; ++i ) p[i] = (unsigned char)(v >> (8 * i)); else for( i = 0; i < 8; ++i ) p[i] = (unsigned char)(v >> (8 * (7 - i))); } __mpu_uint16_t cpu_melf_get16( const unsigned char *p, int data ) { if( is_le( data ) ) return (__mpu_uint16_t)(p[0] | ((__mpu_uint16_t)p[1] << 8)); return (__mpu_uint16_t)(((__mpu_uint16_t)p[0] << 8) | p[1]); } __mpu_uint32_t cpu_melf_get32( const unsigned char *p, int data ) { __mpu_uint32_t v = 0; unsigned i; if( is_le( data ) ) for( i = 0; i < 4; ++i ) v |= (__mpu_uint32_t)p[i] << (8 * i); else for( i = 0; i < 4; ++i ) v = (v << 8) | p[i]; return( v ); } __mpu_uint64_t cpu_melf_get64( const unsigned char *p, int data ) { __mpu_uint64_t v = 0; unsigned i; if( is_le( data ) ) for( i = 0; i < 8; ++i ) v |= (__mpu_uint64_t)p[i] << (8 * i); else for( i = 0; i < 8; ++i ) v = (v << 8) | p[i]; return( v ); } int cpu_melf_span( size_t n, __mpu_uint64_t off, __mpu_uint64_t len ) { return( off <= (__mpu_uint64_t)n && len <= (__mpu_uint64_t)n - off ); } int cpu_melf_is_pow2( __mpu_uint64_t v ) { return( v != 0 && ( v & ( v - 1 ) ) == 0 ); } __mpu_uint64_t cpu_melf_align_up( __mpu_uint64_t v, __mpu_uint64_t a, int *ov ) { __mpu_uint64_t r; if( ov ) *ov = 0; if( a <= 1 ) return( v ); if( !cpu_melf_is_pow2( a ) ) { if( ov ) *ov = 1; return( 0 ); } r = v & (a - 1); if( !r ) return( v ); if( v > UINT64_MAX - ( a - r ) ) { if( ov ) *ov = 1; return( 0 ); } return( v + ( a - r ) ); } int cpu_melf_readall( const char *path, unsigned char **pp, size_t *pn, char *err, size_t es) { FILE *f; long z; unsigned char *p; if( !path || !pp || !pn ) return( -1 ); f = fopen( path, "rb" ); if( !f ) { snprintf( err, es, "%s: %s", path, strerror( errno ) ); return( -1 ); } if( fseek( f, 0, SEEK_END ) || ( z = ftell( f ) ) < 0 || fseek( f, 0, SEEK_SET ) ) { snprintf( err, es, "cannot size %s", path ); fclose( f ); return( -1 ); } p = (unsigned char *)malloc( z ? (size_t)z : 1 ); if( !p ) { snprintf( err, es, "out of memory" ); fclose( f ); return( -1 ); } if( z && fread( p, 1, (size_t)z, f ) != (size_t)z ) { snprintf( err, es, "cannot read %s", path ); free( p ); fclose( f ); return( -1 ); } if( fclose( f ) ) { snprintf( err, es, "cannot close %s", path ); free( p ); return( -1 ); } *pp = p; *pn = (size_t)z; return( 0 ); } int cpu_melf_writeall( const char *path, const void *data, size_t n, char *err, size_t es) { FILE *f = fopen( path, "wb" ); if( !f ) { snprintf( err, es, "%s: %s", path, strerror( errno ) ); return( -1 ); } if( n && fwrite( data, 1, n, f ) != n ) { snprintf( err, es, "cannot write %s", path ); fclose( f ); return( -1 ); } if( fclose( f ) ) { snprintf( err, es, "cannot close %s", path ); return( -1 ); } return( 0 ); } void cpu_melf_fill_target( MElf_McpuTarget *t ) { memset( t, 0, sizeof( *t ) ); t->mt_version = MELF_MCPU_TARGET_VERSION_CURRENT; t->mt_size = MELF_MCPU_TARGET_SIZE; t->mt_isa_revision = MELF_MCPU_ISA_REVISION_CURRENT; t->mt_abi_revision = MELF_MCPU_ABI_REVISION_CURRENT; t->mt_program_model = MELF_MCPU_MODEL_NONE; t->mt_data_byte_order = (__mpu_uint32_t)cpu_melf_data_encoding(); #if CPU_DATA_WORD_ORDER_LITTLE_ENDIAN == 1 t->mt_data_word_order = MELF_MCPU_WORD_ORDER_LSB; #elif CPU_DATA_WORD_ORDER_BIG_ENDIAN == 1 t->mt_data_word_order = MELF_MCPU_WORD_ORDER_MSB; #else # error "Unsupported CPU_DATA_WORD_ORDER" #endif t->mt_integer_model = MELF_MCPU_INTEGER_MODEL_TWOS_COMPLEMENT; t->mt_address_model = MELF_MCPU_ADDRESS_MODEL_PTR64_SEG4_OFF60; t->mt_register_model = MELF_MCPU_REGISTER_MODEL_REG24_512K; t->mt_real_model = MELF_MCPU_REAL_MODEL_LIBMPU; t->mt_complex_model = MELF_MCPU_COMPLEX_MODEL_LIBMPU; t->mt_max_align = MELF_MCPU_ABI_MAX_ALIGN; t->mt_flags = MELF_MCPU_TARGET_FLAGS_NONE; t->mt_required_features = MELF_MCPU_REQUIRED_FEATURES_NONE; } void cpu_melf_encode_target( unsigned char out[MELF_MCPU_TARGET_SIZE], const MElf_McpuTarget *t, int data) { memset( out, 0, MELF_MCPU_TARGET_SIZE ); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_VERSION_OFF, t->mt_version, data ); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_SIZE_OFF, t->mt_size, data ); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_ISA_REVISION_OFF, t->mt_isa_revision, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_ABI_REVISION_OFF, t->mt_abi_revision, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_PROGRAM_MODEL_OFF, t->mt_program_model, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_DATA_BYTE_ORDER_OFF, t->mt_data_byte_order, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_DATA_WORD_ORDER_OFF, t->mt_data_word_order, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_INTEGER_MODEL_OFF, t->mt_integer_model, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_ADDRESS_MODEL_OFF, t->mt_address_model, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_REGISTER_MODEL_OFF, t->mt_register_model, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_REAL_MODEL_OFF, t->mt_real_model, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_COMPLEX_MODEL_OFF, t->mt_complex_model, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_MAX_ALIGN_OFF, t->mt_max_align, data); cpu_melf_put32( out + MELF_MCPU_TARGET_MT_FLAGS_OFF, t->mt_flags, data); cpu_melf_put64( out + MELF_MCPU_TARGET_MT_REQUIRED_FEATURES_OFF, t->mt_required_features, data); } int cpu_melf_decode_target( const unsigned char in[MELF_MCPU_TARGET_SIZE], MElf_McpuTarget *t, int data) { if( data != MELF_DATA_LSB && data != MELF_DATA_MSB ) return( -1 ); memset( t, 0, sizeof( *t ) ); t->mt_version = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_VERSION_OFF, data ); t->mt_size = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_SIZE_OFF, data ); t->mt_isa_revision = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_ISA_REVISION_OFF, data); t->mt_abi_revision = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_ABI_REVISION_OFF, data); t->mt_program_model = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_PROGRAM_MODEL_OFF, data); t->mt_data_byte_order = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_DATA_BYTE_ORDER_OFF, data); t->mt_data_word_order = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_DATA_WORD_ORDER_OFF, data); t->mt_integer_model = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_INTEGER_MODEL_OFF, data); t->mt_address_model = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_ADDRESS_MODEL_OFF, data); t->mt_register_model = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_REGISTER_MODEL_OFF, data); t->mt_real_model = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_REAL_MODEL_OFF, data); t->mt_complex_model = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_COMPLEX_MODEL_OFF, data); t->mt_max_align = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_MAX_ALIGN_OFF, data); t->mt_flags = cpu_melf_get32( in + MELF_MCPU_TARGET_MT_FLAGS_OFF, data ); t->mt_required_features = cpu_melf_get64( in + MELF_MCPU_TARGET_MT_REQUIRED_FEATURES_OFF, data); return( 0 ); } int cpu_melf_validate_target( const MElf_McpuTarget *t, int data, char *err, size_t es) { MElf_McpuTarget x; cpu_melf_fill_target( &x ); #define EQ(FIELD) \ do { \ if(t->FIELD != x.FIELD) { \ snprintf(err, es, "incompatible MCPU target profile field %s", #FIELD); \ return -1; \ } \ } while(0) EQ( mt_version ); if( t->mt_size != MELF_MCPU_TARGET_SIZE ) { snprintf( err, es, "bad .mcpu.target record size" ); return( -1 ); } EQ( mt_isa_revision ); EQ( mt_abi_revision ); EQ( mt_program_model ); EQ( mt_data_byte_order ); EQ( mt_data_word_order ); EQ( mt_integer_model ); EQ( mt_address_model ); EQ( mt_register_model ); EQ( mt_real_model ); EQ( mt_complex_model ); EQ( mt_max_align ); EQ( mt_flags ); EQ( mt_required_features ); #undef EQ if( (int)t->mt_data_byte_order != data ) { snprintf( err, es, "MCPU target byte order disagrees with EI_DATA" ); return( -1 ); } return( 0 ); } void cpu_melf_fill_lifecycle( MElf_McpuLifecycle *l ) { memset( l, 0, sizeof( *l ) ); l->ml_version = MELF_MCPU_LIFECYCLE_VERSION_CURRENT; l->ml_size = MELF_MCPU_LIFECYCLE_SIZE; l->ml_abi = MELF_MCPU_LIFECYCLE_ABI_CURRENT; l->ml_flags = MELF_MCPU_LIFECYCLE_ABI1_FLAGS; } void cpu_melf_encode_lifecycle( unsigned char out[MELF_MCPU_LIFECYCLE_SIZE], const MElf_McpuLifecycle *l, int data) { memset( out, 0, MELF_MCPU_LIFECYCLE_SIZE ); cpu_melf_put32( out + MELF_MCPU_LIFECYCLE_ML_VERSION_OFF, l->ml_version, data); cpu_melf_put32( out + MELF_MCPU_LIFECYCLE_ML_SIZE_OFF, l->ml_size, data); cpu_melf_put32( out + MELF_MCPU_LIFECYCLE_ML_ABI_OFF, l->ml_abi, data); cpu_melf_put32( out + MELF_MCPU_LIFECYCLE_ML_RESERVED0_OFF, l->ml_reserved0, data); cpu_melf_put64( out + MELF_MCPU_LIFECYCLE_ML_FLAGS_OFF, l->ml_flags, data); cpu_melf_put64( out + MELF_MCPU_LIFECYCLE_ML_RESERVED1_OFF, l->ml_reserved1, data); } int cpu_melf_decode_lifecycle( const unsigned char in[MELF_MCPU_LIFECYCLE_SIZE], MElf_McpuLifecycle *l, int data) { if( data != MELF_DATA_LSB && data != MELF_DATA_MSB ) return( -1 ); memset( l, 0, sizeof( *l ) ); l->ml_version = cpu_melf_get32( in + MELF_MCPU_LIFECYCLE_ML_VERSION_OFF, data); l->ml_size = cpu_melf_get32( in + MELF_MCPU_LIFECYCLE_ML_SIZE_OFF, data); l->ml_abi = cpu_melf_get32( in + MELF_MCPU_LIFECYCLE_ML_ABI_OFF, data); l->ml_reserved0 = cpu_melf_get32( in + MELF_MCPU_LIFECYCLE_ML_RESERVED0_OFF, data); l->ml_flags = cpu_melf_get64( in + MELF_MCPU_LIFECYCLE_ML_FLAGS_OFF, data); l->ml_reserved1 = cpu_melf_get64( in + MELF_MCPU_LIFECYCLE_ML_RESERVED1_OFF, data); return( 0 ); } int cpu_melf_validate_lifecycle( const MElf_McpuLifecycle *l, char *err, size_t es) { if( l->ml_version != MELF_MCPU_LIFECYCLE_VERSION_CURRENT || l->ml_size != MELF_MCPU_LIFECYCLE_SIZE || l->ml_abi != MELF_MCPU_LIFECYCLE_ABI_CURRENT || l->ml_reserved0 != 0 || l->ml_flags != MELF_MCPU_LIFECYCLE_ABI1_FLAGS || l->ml_reserved1 != 0) { snprintf( err, es, "unsupported or malformed .mcpu.lifecycle record" ); return( -1 ); } return( 0 ); }