diff options
Diffstat (limited to 'utils/mcpu-ld.c')
| -rw-r--r-- | utils/mcpu-ld.c | 1038 |
1 files changed, 1038 insertions, 0 deletions
diff --git a/utils/mcpu-ld.c b/utils/mcpu-ld.c new file mode 100644 index 0000000..cf793ea --- /dev/null +++ b/utils/mcpu-ld.c @@ -0,0 +1,1038 @@ +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libmcpu.h> + +#include "mcpu-asm.h" +#include "mcpu-object.h" +#include "mcpu-link.h" +#include "mcpu-exec.h" +#include "mcpu-dyn.h" +#include "mcpu-archive.h" +#include "mcpu-ld-options.h" + + +typedef struct mcpu_ld_library +{ + char *path; + cpu_dyn_library_info info; +} mcpu_ld_library; + + +typedef enum mcpu_hll_program_kind +{ + MCPU_HLL_NONE = 0, + MCPU_HLL_PROGRAM, + MCPU_HLL_MODEL +} mcpu_hll_program_kind; + + +static void +free_libraries( mcpu_ld_library *libraries, size_t count ) +{ + size_t i; + + for( i = 0; i < count; ++i ) + { + free( libraries[i].path ); + cpu_dyn_library_free( &libraries[i].info ); + } + free( libraries ); + +} /* End of free_libraries() */ + + +static int +find_soname( const mcpu_ld_library *libraries, size_t count, + const char *soname ) +{ + size_t i; + + for( i = 0; i < count; ++i ) + if( strcmp(libraries[i].info.soname, soname) == 0 ) + return( (int)i ); + + return( -1 ); + +} /* End of find_soname() */ + + +static int +append_link_object( cpu_asm_object **objects, size_t *count, size_t *capacity, + cpu_asm_object *object, char *err, size_t es ) +{ + cpu_asm_object *p; + size_t c; + + if( *count == *capacity ) + { + c = *capacity ? *capacity * 2U : 8U; + if( c < *capacity || c > SIZE_MAX / sizeof( *p ) ) + { + snprintf( err, es, "too many input objects" ); + return( -1 ); + } + + p = (cpu_asm_object *)realloc( *objects, c * sizeof( *p ) ); + if( p == NULL ) + { + snprintf( err, es, "out of memory" ); + return( -1 ); + } + + *objects = p; + *capacity = c; + } + + (*objects)[*count] = *object; + memset( object, 0, sizeof( *object ) ); + ++*count; + return( 0 ); + +} /* End of append_link_object() */ + + +static int +hll_symbol_is_strong_func( const cpu_asm_symbol *symbol ) +{ + return( symbol != NULL && symbol->section != CPU_OBJ_SEC_UNDEF && + symbol->binding == CPU_OBJ_BIND_GLOBAL && + symbol->type == CPU_OBJ_TYPE_FUNC ); + +} /* End of hll_symbol_is_strong_func() */ + + +static int +hll_record_definition( const cpu_asm_object *objects, size_t object_index, + size_t symbol_index, size_t *definition_object, + const cpu_asm_symbol **definition_symbol, + char *err, size_t es ) +{ + const cpu_asm_symbol *symbol = &objects[object_index].symbols[symbol_index]; + + if( *definition_symbol != NULL ) + { + snprintf( err, es, "multiple HLL complete-program definitions of %s", + symbol->name ); + return( -1 ); + } + + *definition_object = object_index; + *definition_symbol = symbol; + return( 0 ); + +} /* End of hll_record_definition() */ + + +static int +classify_hll_program( const cpu_asm_object *objects, size_t count, + mcpu_hll_program_kind *kind, + char *err, size_t es ) +{ + const cpu_asm_symbol *main_symbol = NULL; + const cpu_asm_symbol *init_symbol = NULL; + const cpu_asm_symbol *life_symbol = NULL; + const cpu_asm_symbol *fini_symbol = NULL; + size_t main_object = 0, init_object = 0, life_object = 0, fini_object = 0; + size_t i, j; + int raw_lifecycle = 0; + + *kind = MCPU_HLL_NONE; + + for( i = 0; i < count; ++i ) + for( j = 0; j < objects[i].symbol_count; ++j ) + { + const cpu_asm_symbol *symbol = &objects[i].symbols[j]; + + if( symbol->section == CPU_OBJ_SEC_UNDEF ) + continue; + + if( !strncmp(symbol->name, "__mcpu_crt_", 11) ) + { + snprintf( err, es, "input object defines reserved CRT symbol: %s", + symbol->name ); + return( -1 ); + } + + if( !strcmp(symbol->name, "_start") || + !strcmp(symbol->name, "_life") || + !strcmp(symbol->name, "_fini") ) + { + raw_lifecycle = 1; + continue; + } + + if( symbol->binding == CPU_OBJ_BIND_LOCAL ) + continue; + + if( !strcmp(symbol->name, "main") ) + { + if( hll_record_definition(objects, i, j, &main_object, &main_symbol, + err, es) ) + return( -1 ); + } + else if( !strcmp(symbol->name, "init") ) + { + if( hll_record_definition(objects, i, j, &init_object, &init_symbol, + err, es) ) + return( -1 ); + } + else if( !strcmp(symbol->name, "life") ) + { + if( hll_record_definition(objects, i, j, &life_object, &life_symbol, + err, es) ) + return( -1 ); + } + else if( !strcmp(symbol->name, "fini") ) + { + if( hll_record_definition(objects, i, j, &fini_object, &fini_symbol, + err, es) ) + return( -1 ); + } + } + + if( raw_lifecycle && + (main_symbol != NULL || init_symbol != NULL || life_symbol != NULL) ) + { + snprintf( err, es, "cannot mix low-level lifecycle with HLL complete-program definitions" ); + return( -1 ); + } + + if( main_symbol != NULL ) + { + if( init_symbol != NULL || life_symbol != NULL ) + { + snprintf( err, es, "HLL PROGRAM main is incompatible with MODEL init/life" ); + return( -1 ); + } + if( !hll_symbol_is_strong_func(main_symbol) ) + { + snprintf( err, es, "HLL PROGRAM main must be strong GLOBAL/FUNC" ); + return( -1 ); + } + if( fini_symbol == NULL || fini_object != main_object || + !hll_symbol_is_strong_func(fini_symbol) ) + { + snprintf( err, es, + "HLL PROGRAM requires strong GLOBAL/FUNC main and fini in one ET_REL" ); + return( -1 ); + } + *kind = MCPU_HLL_PROGRAM; + return( 0 ); + } + + if( init_symbol != NULL || life_symbol != NULL ) + { + if( init_symbol == NULL || life_symbol == NULL ) + { + snprintf( err, es, "HLL MODEL requires both init and life" ); + return( -1 ); + } + if( init_object != life_object || fini_symbol == NULL || + fini_object != init_object || + !hll_symbol_is_strong_func(init_symbol) || + !hll_symbol_is_strong_func(life_symbol) || + !hll_symbol_is_strong_func(fini_symbol) ) + { + snprintf( err, es, + "HLL MODEL requires strong GLOBAL/FUNC init, life and fini in one ET_REL" ); + return( -1 ); + } + *kind = MCPU_HLL_MODEL; + } + + return( 0 ); + +} /* End of classify_hll_program() */ + + +static char * +hll_crt_path( const mcpu_ld_options *options, const char *name ) +{ + const char *root; + char *path; + size_t n; + + root = options->common.runtime.installation_root; + if( root == NULL || *root == 0 || name == NULL || *name == 0 ) + return( NULL ); + + if( strlen(root) > SIZE_MAX - strlen(name) - sizeof("/lib/mcpu/") ) + return( NULL ); + + n = strlen(root) + strlen(name) + sizeof("/lib/mcpu/"); + path = (char *)malloc( n ); + if( path != NULL ) + snprintf( path, n, "%s/lib/mcpu/%s", root, name ); + + return( path ); + +} /* End of hll_crt_path() */ + + +static int +read_hll_crt_object( const mcpu_ld_options *options, const char *name, + cpu_asm_object *object, char *err, size_t es ) +{ + char detail[512]; + char *path; + + memset( object, 0, sizeof( *object ) ); + path = hll_crt_path( options, name ); + if( path == NULL ) + { + snprintf( err, es, "cannot construct HLL CRT path for %s", name ); + return( -1 ); + } + + if( cpu_object_read(path, object, detail, sizeof(detail)) ) + { + snprintf( err, es, "cannot load HLL CRT object %.120s: %.300s", + path, detail ); + free( path ); + return( -1 ); + } + + free( path ); + return( 0 ); + +} /* End of read_hll_crt_object() */ + + +static int +inject_hll_crt( const mcpu_ld_options *options, mcpu_hll_program_kind kind, + cpu_asm_object **objects, size_t *count, size_t *capacity, + char *err, size_t es ) +{ + cpu_asm_object adapter, crti, crtn; + cpu_asm_object *combined; + const char *adapter_name; + size_t new_count; + + memset( &adapter, 0, sizeof(adapter) ); + memset( &crti, 0, sizeof(crti) ); + memset( &crtn, 0, sizeof(crtn) ); + + adapter_name = kind == MCPU_HLL_PROGRAM ? "crt0.o" : "crt1.o"; + if( read_hll_crt_object(options, adapter_name, &adapter, err, es) || + read_hll_crt_object(options, "crti.o", &crti, err, es) || + read_hll_crt_object(options, "crtn.o", &crtn, err, es) ) + goto bad; + + if( *count > SIZE_MAX - 3 || + *count + 3 > SIZE_MAX / sizeof(*combined) ) + { + snprintf( err, es, "too many input objects after HLL CRT insertion" ); + goto bad; + } + + new_count = *count + 3; + combined = (cpu_asm_object *)calloc( new_count, sizeof(*combined) ); + if( combined == NULL ) + { + snprintf( err, es, "out of memory" ); + goto bad; + } + + combined[0] = adapter; + combined[1] = crti; + if( *count != 0 ) + memcpy( combined + 2, *objects, *count * sizeof(*combined) ); + combined[new_count - 1] = crtn; + + memset( &adapter, 0, sizeof(adapter) ); + memset( &crti, 0, sizeof(crti) ); + memset( &crtn, 0, sizeof(crtn) ); + free( *objects ); + *objects = combined; + *count = new_count; + *capacity = new_count; + return( 0 ); + +bad: + cpu_asm_object_free( &adapter ); + cpu_asm_object_free( &crti ); + cpu_asm_object_free( &crtn ); + return( -1 ); + +} /* End of inject_hll_crt() */ + + +static int +object_defines_symbol( const cpu_asm_object *objects, size_t count, + const char *name ) +{ + size_t i, j; + + for( i = 0; i < count; ++i ) + for( j = 0; j < objects[i].symbol_count; ++j ) + { + const cpu_asm_symbol *s = &objects[i].symbols[j]; + + if( s->section != CPU_OBJ_SEC_UNDEF && + s->binding != CPU_OBJ_BIND_LOCAL && + strcmp(s->name, name) == 0 ) + return( 1 ); + } + + return( 0 ); + +} /* End of object_defines_symbol() */ + + +static int +library_defines_symbol( const mcpu_ld_library *libraries, size_t count, + const char *name ) +{ + size_t i; + + for( i = 0; i < count; ++i ) + if( cpu_dyn_library_find_symbol(&libraries[i].info, name, NULL) == 0 ) + return( 1 ); + + return( 0 ); + +} /* End of library_defines_symbol() */ + + +static int +name_in_list( const char *const *names, size_t count, const char *name ) +{ + size_t i; + + for( i = 0; i < count; ++i ) + if( strcmp(names[i], name) == 0 ) + return( 1 ); + + return( 0 ); + +} /* End of name_in_list() */ + + +static int +collect_strong_unresolved( const cpu_asm_object *objects, size_t object_count, + const mcpu_ld_library *libraries, + size_t library_count, + const char ***names_out, size_t *count_out, + char *err, size_t es ) +{ + const char **names = NULL; + size_t count = 0; + size_t i, j; + + *names_out = NULL; + *count_out = 0; + + for( i = 0; i < object_count; ++i ) + for( j = 0; j < objects[i].symbol_count; ++j ) + { + const cpu_asm_symbol *s = &objects[i].symbols[j]; + const char **p; + + if( s->section != CPU_OBJ_SEC_UNDEF || + s->binding != CPU_OBJ_BIND_GLOBAL ) + continue; + + if( object_defines_symbol(objects, object_count, s->name) || + library_defines_symbol(libraries, library_count, s->name) || + name_in_list(names, count, s->name) ) + continue; + + if( count == SIZE_MAX / sizeof( *p ) ) + { + free( names ); + snprintf( err, es, "too many unresolved symbols" ); + return( -1 ); + } + p = (const char **)realloc( names, (count + 1) * sizeof( *p ) ); + if( p == NULL ) + { + free( names ); + snprintf( err, es, "out of memory" ); + return( -1 ); + } + names = p; + names[count++] = s->name; + } + + *names_out = names; + *count_out = count; + return( 0 ); + +} /* End of collect_strong_unresolved() */ + + +static int +archive_member_is_needed( const mcpu_archive_member *member, + const char *const *unresolved, + size_t unresolved_count ) +{ + size_t i, j; + + for( i = 0; i < member->symbol_count; ++i ) + for( j = 0; j < unresolved_count; ++j ) + if( strcmp(member->symbols[i], unresolved[j]) == 0 ) + return( 1 ); + + return( 0 ); + +} /* End of archive_member_is_needed() */ + + +static int +extract_archive_members( const char *path, const mcpu_archive *archive, + cpu_asm_object **objects, size_t *object_count, + size_t *object_capacity, + const mcpu_ld_library *libraries, + size_t library_count, + char *err, size_t es ) +{ + unsigned char *selected = NULL; + int changed; + size_t i; + + if( archive->member_count != 0 ) + { + selected = (unsigned char *)calloc( archive->member_count, 1 ); + if( selected == NULL ) + { + snprintf( err, es, "out of memory" ); + return( -1 ); + } + } + + do + { + const char **unresolved = NULL; + size_t unresolved_count = 0; + + changed = 0; + if( collect_strong_unresolved(*objects, *object_count, + libraries, library_count, + &unresolved, &unresolved_count, + err, es) ) + { + free( selected ); + return( -1 ); + } + + for( i = 0; i < archive->member_count && unresolved_count != 0; ++i ) + { + cpu_asm_object object; + char detail[512]; + + if( selected[i] || + !archive_member_is_needed(&archive->members[i], + unresolved, unresolved_count) ) + continue; + + memset( &object, 0, sizeof( object ) ); + if( cpu_object_read_data(archive->members[i].data, + archive->members[i].size, + &object, detail, sizeof(detail)) ) + { + snprintf( err, es, "%.160s(%.120s): %.180s", + path, archive->members[i].name, detail ); + free( unresolved ); + free( selected ); + return( -1 ); + } + + if( append_link_object(objects, object_count, object_capacity, + &object, err, es) ) + { + cpu_asm_object_free( &object ); + free( unresolved ); + free( selected ); + return( -1 ); + } + + selected[i] = 1; + changed = 1; + + free( unresolved ); + unresolved = NULL; + unresolved_count = 0; + if( collect_strong_unresolved(*objects, *object_count, + libraries, library_count, + &unresolved, &unresolved_count, + err, es) ) + { + free( selected ); + return( -1 ); + } + } + + free( unresolved ); + } + while( changed ); + + free( selected ); + return( 0 ); + +} /* End of extract_archive_members() */ + + +static char * +library_filename( const char *name, const char *suffix ) +{ + size_t n; + char *result; + + if( strlen(name) > SIZE_MAX - strlen(suffix) - sizeof("lib") ) + return( NULL ); + + n = strlen(name) + strlen(suffix) + sizeof("lib"); + result = (char *)malloc( n ); + if( result != NULL ) + snprintf( result, n, "lib%s%s", name, suffix ); + + return( result ); + +} /* End of library_filename() */ + + +static int +process_libraries( const mcpu_ld_options *options, + cpu_asm_object **objects, size_t *object_count, + size_t *object_capacity, + mcpu_ld_library **libraries_out, size_t *count_out, + char *err, size_t es ) +{ + mcpu_ld_library *libraries = NULL; + size_t count = 0, i; + + *libraries_out = NULL; + *count_out = 0; + + if( options->library_count == 0 ) + return( 0 ); + + libraries = (mcpu_ld_library *)calloc( options->library_count, + sizeof(*libraries) ); + if( libraries == NULL ) + { + snprintf( err, es, "out of memory" ); + return( -1 ); + } + + for( i = 0; i < options->library_count; ++i ) + { + const char *name = options->libraries[i]; + char *shared_name = NULL; + char *archive_name = NULL; + const char *alternatives[2]; + size_t alternative_count = 0; + size_t selected_index = 0; + char *path = NULL; + + if( !options->force_static && + (options->mode == CPU_LINK_DYNAMIC_EXEC || + options->mode == CPU_LINK_SHARED) ) + { + shared_name = library_filename( name, ".so" ); + if( shared_name == NULL ) + { + snprintf( err, es, "library name is too long: %s", name ); + goto bad; + } + alternatives[alternative_count++] = shared_name; + } + + archive_name = library_filename( name, ".a" ); + if( archive_name == NULL ) + { + free( shared_name ); + snprintf( err, es, "library name is too long: %s", name ); + goto bad; + } + alternatives[alternative_count++] = archive_name; + + if( mcpu_tool_resolve_library_alternatives(&options->common, + alternatives, alternative_count, &path, &selected_index) != 0 ) + { + if( options->force_static || + options->mode == CPU_LINK_STATIC_EXEC || + options->mode == CPU_LINK_RELOCATABLE ) + snprintf( err, es, "cannot find -l%s (%s): %s", + name, archive_name, strerror(errno) ); + else + snprintf( err, es, "cannot find -l%s (%s or %s): %s", + name, shared_name, archive_name, strerror(errno) ); + free( shared_name ); + free( archive_name ); + goto bad; + } + + if( !options->force_static && + (options->mode == CPU_LINK_DYNAMIC_EXEC || + options->mode == CPU_LINK_SHARED) && selected_index == 0 ) + { + cpu_dyn_library_info info; + + memset( &info, 0, sizeof(info) ); + if( cpu_dyn_library_read(path, &info, err, es) != 0 ) + { + free( path ); + free( shared_name ); + free( archive_name ); + goto bad; + } + + if( find_soname(libraries, count, info.soname) >= 0 ) + { + free( path ); + cpu_dyn_library_free( &info ); + } + else + { + libraries[count].path = path; + libraries[count].info = info; + ++count; + } + } + else + { + mcpu_archive archive; + + mcpu_archive_init( &archive ); + if( mcpu_archive_read(path, &archive, err, es) != 0 ) + { + free( path ); + free( shared_name ); + free( archive_name ); + goto bad; + } + + if( extract_archive_members(path, &archive, + objects, object_count, object_capacity, + libraries, count, err, es) ) + { + mcpu_archive_free( &archive ); + free( path ); + free( shared_name ); + free( archive_name ); + goto bad; + } + + mcpu_archive_free( &archive ); + free( path ); + } + + free( shared_name ); + free( archive_name ); + } + + *libraries_out = libraries; + *count_out = count; + return( 0 ); + +bad: + free_libraries( libraries, count ); + return( -1 ); + +} /* End of process_libraries() */ + + +static int +validate_executable_imports( const cpu_asm_image *image, + const mcpu_ld_library *libraries, size_t count, + char *err, size_t es ) +{ + size_t i, j; + + for( i = 0; i < image->dyn_symbol_count; ++i ) + { + const cpu_dyn_symbol *need = &image->dyn_symbols[i]; + int found = 0; + + if( need->section != CPU_OBJ_SEC_UNDEF || + need->binding == CPU_OBJ_BIND_WEAK ) + continue; + + for( j = 0; j < count; ++j ) + { + const cpu_dyn_library_symbol *have = NULL; + + if( cpu_dyn_library_find_symbol(&libraries[j].info, need->name, + &have) == 0 ) + { + if( need->type != CPU_OBJ_TYPE_NOTYPE && + have->type != CPU_OBJ_TYPE_NOTYPE && + need->type != have->type ) + { + snprintf( err, es, + "symbol type mismatch for %s in %s", + need->name, libraries[j].path ); + return( -1 ); + } + found = 1; + break; + } + } + + if( !found ) + { + snprintf( err, es, "undefined symbol not provided by linked libraries: %s", + need->name ); + return( -1 ); + } + } + + return( 0 ); + +} /* End of validate_executable_imports() */ + + +static int +mcpu_ld_link( const mcpu_ld_options *options ) +{ + cpu_asm_object *objs = NULL; + cpu_asm_image im; + mcpu_ld_library *libraries = NULL; + size_t object_count; + size_t object_capacity; + size_t library_count = 0; + mcpu_hll_program_kind hll_kind = MCPU_HLL_NONE; + char err[512]; + size_t i; + int rc = 1; + + if( options == NULL ) + return( 1 ); + + object_count = options->input_count; + object_capacity = options->input_count; + objs = (cpu_asm_object *)calloc( object_capacity, sizeof(*objs) ); + if( objs == NULL ) + { + perror( "calloc" ); + return( 1 ); + } + + __mpu_init(); + memset( &im, 0, sizeof(im) ); + + for( i = 0; i < options->input_count; ++i ) + { + if( cpu_object_read(options->inputs[i], &objs[i], err, sizeof(err)) ) + { + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + goto cleanup_mpu; + } + } + + if( options->mode == CPU_LINK_STATIC_EXEC || + options->mode == CPU_LINK_DYNAMIC_EXEC ) + { + if( classify_hll_program(objs, object_count, &hll_kind, + err, sizeof(err)) ) + { + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + goto cleanup_mpu; + } + + if( hll_kind != MCPU_HLL_NONE && + inject_hll_crt(options, hll_kind, &objs, &object_count, + &object_capacity, err, sizeof(err)) ) + { + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + goto cleanup_mpu; + } + } + + if( process_libraries(options, &objs, &object_count, &object_capacity, + &libraries, &library_count, + err, sizeof(err)) != 0 ) + { + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + goto cleanup_mpu; + } + + if( options->mode == CPU_LINK_RELOCATABLE ) + { + cpu_asm_object merged; + + memset( &merged, 0, sizeof(merged) ); + if( cpu_link_relocatable(objs, object_count, &merged, err, sizeof(err)) ) + { + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + goto cleanup_libraries; + } + + if( cpu_object_write(options->out_fname, &merged, err, sizeof(err)) ) + { + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + cpu_asm_object_free( &merged ); + goto cleanup_libraries; + } + + if( options->verbose ) + printf( "MELF ET_REL partial link: %zu symbols, %zu relocations -> %s\n", + merged.symbol_count, merged.reloc_count, options->out_fname ); + cpu_asm_object_free( &merged ); + rc = 0; + goto cleanup_libraries; + } + + if( cpu_link_objects_mode(objs, object_count, &im, + options->mode, err, sizeof(err)) ) + { + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + goto cleanup_libraries; + } + + if( options->mode == CPU_LINK_DYNAMIC_EXEC && + options->library_count != 0 && + validate_executable_imports(&im, libraries, library_count, + err, sizeof(err)) != 0 ) + { + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + goto cleanup_image; + } + + if( options->mode == CPU_LINK_STATIC_EXEC ) + { + if( cpu_exec_write(options->out_fname, &im, &options->exec, + err, sizeof(err)) ) + { + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + goto cleanup_image; + } + + if( options->verbose ) + { + printf( "MELF ABI1 ET_EXEC: PROGRAM=%zu DATA=%zu STACK=%llu", + im.code_size, im.data_size, + (unsigned long long)options->exec.stack_size ); + if( options->exec.have_heap ) + printf( " HEAP=%llu/%llu", + (unsigned long long)options->exec.heap_size, + (unsigned long long)options->exec.heap_limit ); + printf( " -> %s\n", options->out_fname ); + } + } + else + { + cpu_dyn_metadata metadata; + const char **needed = NULL; + + memset( &metadata, 0, sizeof( metadata ) ); + metadata.soname = options->soname; + if( library_count != 0 ) + { + needed = (const char **)calloc( library_count, sizeof(*needed) ); + if( needed == NULL ) + { + fprintf( stderr, "%s: out of memory\n", options->common.progname ); + goto cleanup_image; + } + for( i = 0; i < library_count; ++i ) + needed[i] = libraries[i].info.soname; + metadata.needed = needed; + metadata.needed_count = library_count; + } + + if( cpu_dyn_write_abi3(options->out_fname, &im, + options->mode == CPU_LINK_SHARED ? NULL : &options->exec, + options->mode == CPU_LINK_SHARED, + &metadata, err, sizeof(err)) ) + { + free( needed ); + fprintf( stderr, "%s: %s\n", options->common.progname, err ); + goto cleanup_image; + } + free( needed ); + + if( options->verbose ) + { + if( options->mode == CPU_LINK_SHARED ) + printf( "MELF ABI3 ET_DYN: PROGRAM=%zu DATA=%zu DYNSYM=%zu RELA=%zu NEEDED=%zu -> %s\n", + im.code_size, im.data_size, im.dyn_symbol_count, + im.dyn_reloc_count, library_count, options->out_fname ); + else + { + printf( "MELF ABI3 ET_EXEC: PROGRAM=%zu DATA=%zu DYNSYM=%zu RELA=%zu NEEDED=%zu STACK=%llu", + im.code_size, im.data_size, im.dyn_symbol_count, + im.dyn_reloc_count, library_count, + (unsigned long long)options->exec.stack_size ); + if( options->exec.have_heap ) + printf( " HEAP=%llu/%llu", + (unsigned long long)options->exec.heap_size, + (unsigned long long)options->exec.heap_limit ); + printf( " -> %s\n", options->out_fname ); + } + } + } + + rc = 0; + +cleanup_image: + cpu_asm_image_free( &im ); + +cleanup_libraries: + free_libraries( libraries, library_count ); + +cleanup_mpu: + for( i = 0; i < object_count; ++i ) + cpu_asm_object_free( &objs[i] ); + free( objs ); + __mpu_free_context(); + + return( rc ); + +} /* End of mcpu_ld_link() */ + + +int +main( int argc, char **argv ) +{ + mcpu_ld_options options; + int rc = 1; + + mcpu_ld_options_init( &options, argv[0] ); + + if( mcpu_ld_handle_options(&options, argc, argv) != 0 ) + goto done; + + if( options.common.help ) + { + mcpu_ld_usage( &options ); + rc = 0; + goto done; + } + + if( options.common.version_action != MCPU_VERSION_NONE ) + { + if( mcpu_version_print(options.common.progname, + options.common.version_action) != 0 ) + goto done; + rc = 0; + goto done; + } + + if( mcpu_tool_options_prepare(&options.common, argv[0]) != 0 ) + goto done; + + if( mcpu_tool_has_information_action(&options.common) ) + { + if( options.common.dump_config && + mcpu_tool_dump_config(&options.common, stdout) != 0 ) + goto done; + if( options.common.print_search_dirs && + mcpu_tool_print_search_dirs(&options.common, stdout) != 0 ) + goto done; + rc = 0; + goto done; + } + + rc = mcpu_ld_link( &options ); + +done: + mcpu_ld_options_free( &options ); + return( rc ); + +} /* End of main() */ |
