summaryrefslogtreecommitdiff
path: root/utils/mcpu-melf.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/mcpu-melf.c')
-rw-r--r--utils/mcpu-melf.c435
1 files changed, 435 insertions, 0 deletions
diff --git a/utils/mcpu-melf.c b/utils/mcpu-melf.c
new file mode 100644
index 0000000..1178c6f
--- /dev/null
+++ b/utils/mcpu-melf.c
@@ -0,0 +1,435 @@
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 );
+}