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 /utils/mcpu-ld-options.c | |
| parent | d130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff) | |
| download | libmcpu-0.4.0.tar.xz | |
Version 0.4.00.4.0
Diffstat (limited to 'utils/mcpu-ld-options.c')
| -rw-r--r-- | utils/mcpu-ld-options.c | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/utils/mcpu-ld-options.c b/utils/mcpu-ld-options.c new file mode 100644 index 0000000..6b64654 --- /dev/null +++ b/utils/mcpu-ld-options.c @@ -0,0 +1,463 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libmcpu.h> + +#include "mcpu-ld-options.h" + +static int +parse_size( const char *s, __mpu_uint64_t *v ) +{ + unsigned long long x; + __mpu_uint64_t m = 1; + char *e; + + if( !s || !*s || *s == '-' ) return( -1 ); + + errno = 0; + x = strtoull( s, &e, 0 ); + if( errno || e == s ) return( -1 ); + + if( *e == '\0' ) + m = 1; + else if( !strcmp( e, "K" ) || !strcmp( e, "KiB" ) ) + m = __mpu_UINT64_C( 1024 ); + else if( !strcmp( e, "M" ) || !strcmp( e, "MiB" ) ) + m = __mpu_UINT64_C( 1024 ) * __mpu_UINT64_C( 1024 ); + else if( !strcmp( e, "G" ) || !strcmp( e, "GiB" ) ) + m = __mpu_UINT64_C( 1024 ) * __mpu_UINT64_C( 1024 ) * __mpu_UINT64_C( 1024 ); + else + return( -1 ); + + if( (__mpu_uint64_t)x != x || (__mpu_uint64_t)x > UINT64_MAX / m ) + return( -1 ); + + *v = (__mpu_uint64_t)x * m; + return( 0 ); + +} /* End of parse_size() */ + + +static int +append_input( mcpu_ld_options *options, char *name ) +{ + char **p; + size_t capacity; + + if( options->input_count == options->input_capacity ) + { + capacity = options->input_capacity ? options->input_capacity * 2U : 8U; + if( capacity < options->input_capacity || + capacity > SIZE_MAX / sizeof(*p) ) + { + errno = EOVERFLOW; + return( -1 ); + } + + p = (char **)realloc( options->inputs, capacity * sizeof(*p) ); + if( p == NULL ) + return( -1 ); + + options->inputs = p; + options->input_capacity = capacity; + } + + options->inputs[options->input_count++] = name; + return( 0 ); + +} /* End of append_input() */ + + +static int +append_library( mcpu_ld_options *options, char *name ) +{ + char **p; + size_t capacity; + + if( options->library_count == options->library_capacity ) + { + capacity = options->library_capacity ? options->library_capacity * 2U : 8U; + if( capacity < options->library_capacity || + capacity > SIZE_MAX / sizeof(*p) ) + { + errno = EOVERFLOW; + return( -1 ); + } + + p = (char **)realloc( options->libraries, capacity * sizeof(*p) ); + if( p == NULL ) + return( -1 ); + + options->libraries = p; + options->library_capacity = capacity; + } + + options->libraries[options->library_count++] = name; + return( 0 ); + +} /* End of append_library() */ + + +void +mcpu_ld_options_init( mcpu_ld_options *options, const char *progname ) +{ + if( options == NULL ) + return; + + memset( options, 0, sizeof(*options) ); + mcpu_tool_options_init( &options->common, progname ); + options->exec.stack_size = 1048576U; + options->exec.have_heap = 1; + options->exec.heap_size = 1048576U; + options->exec.heap_limit = 1048576U; + options->mode = CPU_LINK_STATIC_EXEC; + +} /* End of mcpu_ld_options_init() */ + + +void +mcpu_ld_options_free( mcpu_ld_options *options ) +{ + if( options == NULL ) + return; + + free( options->inputs ); + options->inputs = NULL; + options->input_count = 0; + options->input_capacity = 0; + free( options->libraries ); + options->libraries = NULL; + options->library_count = 0; + options->library_capacity = 0; + mcpu_tool_options_free( &options->common ); + +} /* End of mcpu_ld_options_free() */ + + +void +mcpu_ld_usage( const mcpu_ld_options *options ) +{ + const char *name = options ? options->common.progname : "mcpu-ld"; + + fprintf( stderr, + "usage: %s [link-options] -o output input.o ...\n\n" + "Link LibMCPU MELF ET_REL object files.\n\n" + "Output mode (at most one):\n" + " -r - produce one partial-link MELF ET_REL object\n" + " --shared - produce ABI-v3 MELF ET_DYN shared object\n" + " --dynamic - produce ABI-v3 startup-dynamic MELF ET_EXEC\n" + " (default without these options: ABI-v1 static ET_EXEC)\n\n" + "MCPU system options:\n" + " --no-config - do not read mcpu-ld.conf files\n" + " --sys-root=PATH - use PATH as MCPU root and do not read config files\n" + " --dump-config - print effective MCPU configuration and exit\n" + " --print-search-dirs - print effective library search directories and exit\n\n" + "Library dependency options:\n" + " -L <dir>, -L<dir> - add explicit MCPU library search directory\n" + " -l <name>, -l<name> - link against lib<name>; ABI-v1 and -r search .a,\n" + " ABI-v3 searches .so then .a in each directory\n" + " --static - force every -l<name> lookup to use lib<name>.a\n" + " without changing the selected output mode\n" + " (selected .so files alone create DT_NEEDED)\n\n" + "Shared-library identity:\n" + " --soname=NAME - set mandatory ABI-v3 ET_DYN SONAME\n" + " --soname NAME - NAME must be a logical name without '/'\n\n" + "Link options:\n" + " -o <file> - write output to <file>\n" + " --stack-size=<size> - set fixed STACK size; positive and %u-byte aligned\n" + " (default for executables: 1048576)\n" + " --heap-size=<size> - set initial HEAP size (default: 1048576)\n" + " --heap-limit=<size> - set immutable maximum HEAP size (default: 1048576)\n" + " --no-heap - omit PT_MCPU_HEAP from an executable\n" + " -v, --verbose - print output-object summary\n" + " -h, --help - show this help\n" + " --version - show program version\n" + " --dump-version - show version number only\n\n" + "<size> is bytes by default; K/KiB, M/MiB and G/GiB suffixes are accepted.\n" + "K, M and G use binary multipliers (1024, 1024^2 and 1024^3).\n\n" + "Partial -r output is MELF ET_REL: STACK/HEAP/SONAME and shared objects are\n" + "not part of this mode; unresolved symbols and RELA records are preserved.\n" + "Shared objects may contain only .text/.data/.bss allocated sections,\n" + "must define --soname and must not use STACK/HEAP sizing options. ABI-v3\n" + "dynamic executables retain preemptible GLOBAL/WEAK relocations; mcpu-run\n" + "continues to accept explicit --ldpreload and legacy ABI-v2 files.\n", + name, CPU_ABI_STACK_ALIGN ); + +} /* End of mcpu_ld_usage() */ + + +int +mcpu_ld_handle_options( mcpu_ld_options *options, int argc, char **argv ) +{ + int i; + + if( options == NULL || argv == NULL ) + { + errno = EINVAL; + return( -1 ); + } + + for( i = 1; i < argc; ++i ) + { + int common; + + if( !strcmp( argv[i], "-h" ) || !strcmp( argv[i], "--help" ) ) + { + options->common.help = 1; + return( 0 ); + } + + common = mcpu_tool_parse_common_option( &options->common, + argc, argv, &i ); + if( common < 0 ) + return( -1 ); + if( common > 0 ) + { + if( options->common.version_action != MCPU_VERSION_NONE ) + return( 0 ); + continue; + } + + if( !strcmp( argv[i], "-v" ) || !strcmp( argv[i], "--verbose" ) ) + { + options->verbose = 1; + } + else if( !strcmp( argv[i], "-r" ) ) + { + if( options->mode_seen++ ) + { + fprintf( stderr, "%s: -r/--shared/--dynamic are mutually exclusive\n", + options->common.progname ); + return( -1 ); + } + options->mode = CPU_LINK_RELOCATABLE; + } + else if( !strcmp( argv[i], "--shared" ) ) + { + if( options->mode_seen++ ) + { + fprintf( stderr, "%s: -r/--shared/--dynamic are mutually exclusive\n", + options->common.progname ); + return( -1 ); + } + options->mode = CPU_LINK_SHARED; + } + else if( !strcmp( argv[i], "--dynamic" ) ) + { + if( options->mode_seen++ ) + { + fprintf( stderr, "%s: -r/--shared/--dynamic are mutually exclusive\n", + options->common.progname ); + return( -1 ); + } + options->mode = CPU_LINK_DYNAMIC_EXEC; + } + else if( !strcmp( argv[i], "--static" ) ) + { + options->force_static = 1; + } + else if( !strncmp( argv[i], "--soname=", 9 ) ) + { + const char *name = argv[i] + 9; + + if( options->soname != NULL || name[0] == 0 || + strchr( name, '/' ) != NULL ) + { + fprintf( stderr, "%s: invalid or duplicate --soname\n", + options->common.progname ); + return( -1 ); + } + options->soname = name; + } + else if( !strcmp( argv[i], "--soname" ) ) + { + const char *name; + + if( ++i >= argc ) + { + fprintf( stderr, "%s: argument missing after --soname\n", + options->common.progname ); + return( -1 ); + } + name = argv[i]; + if( options->soname != NULL || name[0] == 0 || + strchr( name, '/' ) != NULL ) + { + fprintf( stderr, "%s: invalid or duplicate --soname\n", + options->common.progname ); + return( -1 ); + } + options->soname = name; + } + else if( !strcmp( argv[i], "-L" ) ) + { + if( ++i >= argc || argv[i][0] == 0 || + mcpu_tool_add_library_directory(&options->common, argv[i]) != 0 ) + { + fprintf( stderr, "%s: argument missing or invalid after -L\n", + options->common.progname ); + return( -1 ); + } + } + else if( !strncmp( argv[i], "-L", 2 ) ) + { + if( argv[i][2] == 0 || + mcpu_tool_add_library_directory(&options->common, argv[i] + 2) != 0 ) + { + fprintf( stderr, "%s: bad -L directory: %s\n", + options->common.progname, argv[i] + 2 ); + return( -1 ); + } + } + else if( !strcmp( argv[i], "-l" ) ) + { + char *name; + + if( ++i >= argc ) + { + fprintf( stderr, "%s: argument missing after -l\n", + options->common.progname ); + return( -1 ); + } + name = argv[i]; + if( name[0] == 0 || strchr(name, '/') != NULL || + append_library(options, name) != 0 ) + { + fprintf( stderr, "%s: invalid library name after -l: %s\n", + options->common.progname, name ); + return( -1 ); + } + } + else if( !strncmp( argv[i], "-l", 2 ) ) + { + char *name = argv[i] + 2; + + if( name[0] == 0 || strchr(name, '/') != NULL || + append_library(options, name) != 0 ) + { + fprintf( stderr, "%s: invalid library option: %s\n", + options->common.progname, argv[i] ); + return( -1 ); + } + } + else if( !strcmp( argv[i], "-o" ) ) + { + if( ++i >= argc || options->out_fname != NULL ) + { + mcpu_ld_usage( options ); + return( -1 ); + } + options->out_fname = argv[i]; + } + else if( !strncmp( argv[i], "--stack-size=", 13 ) ) + { + options->size_option_seen = 1; + if( parse_size(argv[i] + 13, &options->exec.stack_size) || + !options->exec.stack_size || + options->exec.stack_size % CPU_ABI_STACK_ALIGN ) + { + fprintf( stderr, "%s: stack size must be a positive multiple of %u\n", + options->common.progname, CPU_ABI_STACK_ALIGN ); + return( -1 ); + } + } + else if( !strncmp( argv[i], "--heap-size=", 12 ) ) + { + options->size_option_seen = 1; + if( parse_size(argv[i] + 12, &options->exec.heap_size) || + options->exec.heap_size < CPU_HEAP_BEGIN ) + { + fprintf( stderr, "%s: heap size must be at least %u\n", + options->common.progname, CPU_HEAP_BEGIN ); + return( -1 ); + } + options->exec.have_heap = 1; + } + else if( !strncmp( argv[i], "--heap-limit=", 13 ) ) + { + options->size_option_seen = 1; + if( parse_size(argv[i] + 13, &options->exec.heap_limit) || + options->exec.heap_limit < CPU_HEAP_BEGIN ) + { + fprintf( stderr, "%s: bad heap limit\n", options->common.progname ); + return( -1 ); + } + options->exec.have_heap = 1; + } + else if( !strcmp( argv[i], "--no-heap" ) ) + { + options->size_option_seen = 1; + options->exec.have_heap = 0; + options->exec.heap_size = options->exec.heap_limit = 0; + } + else if( argv[i][0] == '-' ) + { + fprintf( stderr, "%s: unknown option %s\n", + options->common.progname, argv[i] ); + return( -1 ); + } + else if( append_input(options, argv[i]) != 0 ) + { + perror( "realloc" ); + return( -1 ); + } + } + + if( options->common.help || + mcpu_tool_has_information_action(&options->common) ) + return( 0 ); + + if( options->out_fname == NULL || options->input_count == 0 ) + { + mcpu_ld_usage( options ); + return( -1 ); + } + + if( options->mode == CPU_LINK_RELOCATABLE && options->size_option_seen ) + { + fprintf( stderr, "%s: STACK/HEAP options are invalid with -r\n", + options->common.progname ); + return( -1 ); + } + + if( options->mode == CPU_LINK_SHARED && options->size_option_seen ) + { + fprintf( stderr, "%s: STACK/HEAP options are invalid with --shared\n", + options->common.progname ); + return( -1 ); + } + + if( options->mode == CPU_LINK_SHARED && options->soname == NULL ) + { + fprintf( stderr, "%s: ABI-v3 --shared requires --soname=NAME\n", + options->common.progname ); + return( -1 ); + } + + if( options->mode != CPU_LINK_SHARED && options->soname != NULL ) + { + fprintf( stderr, "%s: --soname is valid only with --shared\n", + options->common.progname ); + return( -1 ); + } + + if( options->mode != CPU_LINK_SHARED && + options->mode != CPU_LINK_RELOCATABLE && + options->exec.have_heap && + options->exec.heap_limit < options->exec.heap_size ) + { + fprintf( stderr, "%s: heap limit is smaller than heap size\n", + options->common.progname ); + return( -1 ); + } + + return( 0 ); + +} /* End of mcpu_ld_handle_options() */ |
