summaryrefslogtreecommitdiff
path: root/tests/tst-strip-fixture.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tst-strip-fixture.c')
-rw-r--r--tests/tst-strip-fixture.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/tests/tst-strip-fixture.c b/tests/tst-strip-fixture.c
new file mode 100644
index 0000000..1d1fae3
--- /dev/null
+++ b/tests/tst-strip-fixture.c
@@ -0,0 +1,266 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libmcpu.h>
+#include <mcpu-elf.h>
+
+#include "mcpu-melf.h"
+
+
+typedef struct fixture_shdr
+{
+ __mpu_uint32_t name;
+ __mpu_uint32_t type;
+ __mpu_uint64_t flags;
+ __mpu_uint64_t addr;
+ __mpu_uint64_t offset;
+ __mpu_uint64_t size;
+ __mpu_uint32_t link;
+ __mpu_uint32_t info;
+ __mpu_uint64_t align;
+ __mpu_uint64_t entsize;
+} fixture_shdr;
+
+
+static void
+get_shdr( const unsigned char *p, int data, fixture_shdr *sh )
+{
+ memset( sh, 0, sizeof( *sh ) );
+ sh->name = cpu_melf_get32( p + MELF64_SHDR_SH_NAME_OFF, data );
+ sh->type = cpu_melf_get32( p + MELF64_SHDR_SH_TYPE_OFF, data );
+ sh->flags = cpu_melf_get64( p + MELF64_SHDR_SH_FLAGS_OFF, data );
+ sh->addr = cpu_melf_get64( p + MELF64_SHDR_SH_ADDR_OFF, data );
+ sh->offset = cpu_melf_get64( p + MELF64_SHDR_SH_OFFSET_OFF, data );
+ sh->size = cpu_melf_get64( p + MELF64_SHDR_SH_SIZE_OFF, data );
+ sh->link = cpu_melf_get32( p + MELF64_SHDR_SH_LINK_OFF, data );
+ sh->info = cpu_melf_get32( p + MELF64_SHDR_SH_INFO_OFF, data );
+ sh->align = cpu_melf_get64( p + MELF64_SHDR_SH_ADDRALIGN_OFF, data );
+ sh->entsize = cpu_melf_get64( p + MELF64_SHDR_SH_ENTSIZE_OFF, data );
+
+} /* End of get_shdr() */
+
+
+static void
+put_shdr( unsigned char *p, int data, const fixture_shdr *sh )
+{
+ memset( p, 0, MELF64_SHDR_SIZE );
+ cpu_melf_put32( p + MELF64_SHDR_SH_NAME_OFF, sh->name, data );
+ cpu_melf_put32( p + MELF64_SHDR_SH_TYPE_OFF, sh->type, data );
+ cpu_melf_put64( p + MELF64_SHDR_SH_FLAGS_OFF, sh->flags, data );
+ cpu_melf_put64( p + MELF64_SHDR_SH_ADDR_OFF, sh->addr, data );
+ cpu_melf_put64( p + MELF64_SHDR_SH_OFFSET_OFF, sh->offset, data );
+ cpu_melf_put64( p + MELF64_SHDR_SH_SIZE_OFF, sh->size, data );
+ cpu_melf_put32( p + MELF64_SHDR_SH_LINK_OFF, sh->link, data );
+ cpu_melf_put32( p + MELF64_SHDR_SH_INFO_OFF, sh->info, data );
+ cpu_melf_put64( p + MELF64_SHDR_SH_ADDRALIGN_OFF, sh->align, data );
+ cpu_melf_put64( p + MELF64_SHDR_SH_ENTSIZE_OFF, sh->entsize, data );
+
+} /* End of put_shdr() */
+
+
+static const char *
+name_at( const unsigned char *table, size_t size, __mpu_uint32_t offset )
+{
+ const unsigned char *p;
+
+ if( offset >= size )
+ return( NULL );
+ p = table + offset;
+ if( !memchr( p, 0, size - offset ) )
+ return( NULL );
+ return( (const char *)p );
+
+} /* End of name_at() */
+
+
+int
+main( int argc, char **argv )
+{
+ unsigned char *file = NULL;
+ unsigned char *out = NULL;
+ fixture_shdr *sh = NULL;
+ const unsigned char *old_shstr;
+ size_t file_size = 0;
+ size_t old_shstr_size;
+ size_t new_shstr_size;
+ size_t i;
+ size_t text_index = 0;
+ int data;
+ int overflow = 0;
+ __mpu_uint64_t old_shoff;
+ __mpu_uint64_t cur;
+ __mpu_uint64_t new_shoff;
+ __mpu_uint64_t total;
+ __mpu_uint16_t shnum;
+ __mpu_uint16_t shentsize;
+ __mpu_uint16_t shstrndx;
+ fixture_shdr strtab;
+ fixture_shdr symtab;
+ fixture_shdr shstr;
+ unsigned char symbols[2 * MELF64_SYM_SIZE];
+ const char fixture_strtab[] = "\0fixture_symbol\0";
+ const char strtab_name[] = ".strtab";
+ const char symtab_name[] = ".symtab";
+ char err[256];
+ int rc = EXIT_FAILURE;
+
+ if( argc != 3 )
+ {
+ fprintf( stderr, "usage: %s INPUT-ET_EXEC-OR-ET_DYN OUTPUT\n", argv[0] );
+ return( EXIT_FAILURE );
+ }
+
+ if( cpu_melf_readall( argv[1], &file, &file_size, err, sizeof( err ) ) )
+ {
+ fprintf( stderr, "%s\n", err );
+ return( EXIT_FAILURE );
+ }
+
+ if( file_size < MELF64_EHDR_SIZE ||
+ file[MELF_EI_MAG0] != MELFMAG0 || file[MELF_EI_MAG1] != MELFMAG1 ||
+ file[MELF_EI_MAG2] != MELFMAG2 || file[MELF_EI_MAG3] != MELFMAG3 ||
+ file[MELF_EI_CLASS] != MELF_CLASS_64 )
+ goto out;
+
+ data = file[MELF_EI_DATA];
+ if( data != MELF_DATA_LSB && data != MELF_DATA_MSB )
+ goto out;
+ {
+ __mpu_uint16_t type = cpu_melf_get16(
+ file + MELF64_EHDR_E_TYPE_OFF, data );
+
+ if( type != MELF_ET_EXEC && type != MELF_ET_DYN )
+ goto out;
+ }
+
+ old_shoff = cpu_melf_get64( file + MELF64_EHDR_E_SHOFF_OFF, data );
+ shnum = cpu_melf_get16( file + MELF64_EHDR_E_SHNUM_OFF, data );
+ shentsize = cpu_melf_get16( file + MELF64_EHDR_E_SHENTSIZE_OFF, data );
+ shstrndx = cpu_melf_get16( file + MELF64_EHDR_E_SHSTRNDX_OFF, data );
+ if( !shnum || shnum > UINT16_MAX - 2 || shentsize != MELF64_SHDR_SIZE ||
+ shstrndx >= shnum ||
+ !cpu_melf_span( file_size, old_shoff,
+ (__mpu_uint64_t)shnum * MELF64_SHDR_SIZE ) )
+ goto out;
+
+ sh = (fixture_shdr *)calloc( (size_t)shnum + 2, sizeof( *sh ) );
+ if( !sh )
+ goto out;
+ for( i = 0; i < shnum; ++i )
+ get_shdr( file + (size_t)old_shoff + i * MELF64_SHDR_SIZE,
+ data, &sh[i] );
+
+ if( sh[shstrndx].type != MELF_SHT_STRTAB ||
+ !cpu_melf_span( file_size, sh[shstrndx].offset,
+ sh[shstrndx].size ) ||
+ sh[shstrndx].size > SIZE_MAX )
+ goto out;
+
+ old_shstr = file + (size_t)sh[shstrndx].offset;
+ old_shstr_size = (size_t)sh[shstrndx].size;
+ for( i = 1; i < shnum; ++i )
+ {
+ const char *name = name_at( old_shstr, old_shstr_size, sh[i].name );
+
+ if( !name )
+ goto out;
+ if( !strcmp( name, MELF_SEC_TEXT ) )
+ text_index = i;
+ }
+ if( !text_index )
+ goto out;
+
+ cur = old_shoff;
+ memset( &strtab, 0, sizeof( strtab ) );
+ strtab.type = MELF_SHT_STRTAB;
+ strtab.offset = cur;
+ strtab.size = sizeof( fixture_strtab );
+ strtab.align = 1;
+ cur += strtab.size;
+
+ cur = cpu_melf_align_up( cur, 8, &overflow );
+ if( overflow )
+ goto out;
+ memset( &symtab, 0, sizeof( symtab ) );
+ symtab.type = MELF_SHT_SYMTAB;
+ symtab.offset = cur;
+ symtab.size = sizeof( symbols );
+ symtab.link = shnum;
+ symtab.info = 1;
+ symtab.align = 8;
+ symtab.entsize = MELF64_SYM_SIZE;
+ cur += symtab.size;
+
+ if( old_shstr_size > SIZE_MAX - sizeof( strtab_name ) ||
+ old_shstr_size + sizeof( strtab_name ) > SIZE_MAX - sizeof( symtab_name ) )
+ goto out;
+ new_shstr_size = old_shstr_size + sizeof( strtab_name ) +
+ sizeof( symtab_name );
+ shstr = sh[shstrndx];
+ shstr.offset = cur;
+ shstr.size = new_shstr_size;
+ cur += new_shstr_size;
+
+ new_shoff = cpu_melf_align_up( cur, 8, &overflow );
+ if( overflow || new_shoff > UINT64_MAX -
+ (__mpu_uint64_t)( shnum + 2 ) * MELF64_SHDR_SIZE )
+ goto out;
+ total = new_shoff + (__mpu_uint64_t)( shnum + 2 ) * MELF64_SHDR_SIZE;
+ if( total > SIZE_MAX )
+ goto out;
+
+ out = (unsigned char *)calloc( (size_t)total, 1 );
+ if( !out )
+ goto out;
+ memcpy( out, file, (size_t)old_shoff );
+ memcpy( out + (size_t)strtab.offset, fixture_strtab,
+ sizeof( fixture_strtab ) );
+
+ memset( symbols, 0, sizeof( symbols ) );
+ cpu_melf_put32( symbols + MELF64_SYM_SIZE + MELF64_SYM_ST_NAME_OFF,
+ 1, data );
+ symbols[MELF64_SYM_SIZE + MELF64_SYM_ST_INFO_OFF] =
+ MELF64_ST_INFO( MELF_STB_GLOBAL, MELF_STT_FUNC );
+ symbols[MELF64_SYM_SIZE + MELF64_SYM_ST_OTHER_OFF] = MELF_STV_DEFAULT;
+ cpu_melf_put16( symbols + MELF64_SYM_SIZE + MELF64_SYM_ST_SHNDX_OFF,
+ (__mpu_uint16_t)text_index, data );
+ cpu_melf_put64( symbols + MELF64_SYM_SIZE + MELF64_SYM_ST_VALUE_OFF,
+ sh[text_index].addr, data );
+ memcpy( out + (size_t)symtab.offset, symbols, sizeof( symbols ) );
+
+ memcpy( out + (size_t)shstr.offset, old_shstr, old_shstr_size );
+ memcpy( out + (size_t)shstr.offset + old_shstr_size,
+ strtab_name, sizeof( strtab_name ) );
+ memcpy( out + (size_t)shstr.offset + old_shstr_size + sizeof( strtab_name ),
+ symtab_name, sizeof( symtab_name ) );
+
+ strtab.name = (__mpu_uint32_t)old_shstr_size;
+ symtab.name = (__mpu_uint32_t)( old_shstr_size + sizeof( strtab_name ) );
+ sh[shstrndx] = shstr;
+ sh[shnum] = strtab;
+ sh[shnum + 1] = symtab;
+
+ for( i = 0; i < (size_t)shnum + 2; ++i )
+ put_shdr( out + (size_t)new_shoff + i * MELF64_SHDR_SIZE,
+ data, &sh[i] );
+
+ cpu_melf_put64( out + MELF64_EHDR_E_SHOFF_OFF, new_shoff, data );
+ cpu_melf_put16( out + MELF64_EHDR_E_SHNUM_OFF,
+ (__mpu_uint16_t)( shnum + 2 ), data );
+
+ if( cpu_melf_writeall( argv[2], out, (size_t)total, err, sizeof( err ) ) )
+ {
+ fprintf( stderr, "%s\n", err );
+ goto out;
+ }
+ rc = EXIT_SUCCESS;
+
+out:
+ free( out );
+ free( sh );
+ free( file );
+ return( rc );
+
+} /* End of main() */