static int _parse_long_options(struct ld *ld, struct ld_option *opts, int ac, int argc, char **argv, char *opt, enum ld_dash dash) { char *equal; size_t av_len; int i, match; if ((equal = strchr(opt, '=')) != NULL) { av_len = equal - opt; equal++; if (*equal == '\0') ld_fatal(ld, "no argument after ="); } else av_len = strlen(opt); match = 0; for (i = 0; opts[i].lo_long != NULL; i++) { if (opts[i].lo_dash != ANY_DASH && opts[i].lo_dash != dash) continue; if (strlen(opts[i].lo_long) == av_len && !strncmp(opt, opts[i].lo_long, av_len)) { match = 1; break; } } if (!match) return (-1); switch (opts[i].lo_arg) { case NO_ARG: if (equal != NULL) { ld_fatal(ld, "option %s does not accept argument", opts[i].lo_long); } _process_options(ld, opts[i].lo_key, NULL); break; case REQ_ARG: if (equal != NULL) _process_options(ld, opts[i].lo_key, equal); else { if (++ac >= argc) ld_fatal(ld, "require arg for option %s", opts[i].lo_long); _process_options(ld, opts[i].lo_key, argv[ac]); } break; case OPT_ARG: _process_options(ld, opts[i].lo_key, equal); break; default: assert(0); break; } return (++ac); }
static void _process_reloc(struct ld *ld, struct ld_input_section *is, struct ld_reloc_entry *lre, struct ld_symbol *lsb, uint8_t *buf) { struct ld_state *ls; struct ld_output *lo; uint32_t p, s, l, g, got; int32_t a, v; ls = &ld->ld_state; lo = ld->ld_output; assert(lo != NULL); l = lsb->lsb_plt_off; p = lre->lre_offset + is->is_output->os_addr + is->is_reloff; got = ld->ld_got->is_output->os_addr; s = (uint32_t) lsb->lsb_value; READ_32(buf + lre->lre_offset, a); switch (lre->lre_type) { case R_386_NONE: break; case R_386_32: v = s + a; WRITE_32(buf + lre->lre_offset, v); break; case R_386_PC32: if (lsb->lsb_plt) v = l + a - p; else v = s + a - p; WRITE_32(buf + lre->lre_offset, v); break; case R_386_PLT32: if (!ls->ls_ignore_next_plt) { v = l + a - p; WRITE_32(buf + lre->lre_offset, v); } else ls->ls_ignore_next_plt = 0; break; case R_386_GOT32: g = _got_offset(ld, lsb); v = g + a; WRITE_32(buf + lre->lre_offset, v); break; case R_386_GOTOFF: v = s + a - got; WRITE_32(buf + lre->lre_offset, v); break; case R_386_GOTPC: v = got + a - p; WRITE_32(buf + lre->lre_offset, v); break; default: ld_fatal(ld, "Relocation %d not supported", lre->lre_type); break; } }
static void _process_options(struct ld *ld, int key, char *arg) { struct ld_state *ls; assert(ld != NULL); ls = &ld->ld_state; switch (key) { case 'b': ls->ls_itgt = elftc_bfd_find_target(arg); if (ls->ls_itgt == NULL) ld_fatal(ld, "invalid BFD target `%s'", arg); break; case 'd': ld->ld_common_alloc = 1; break; case 'e': _copy_optarg(ld, &ld->ld_entry, arg); break; case 'h': _copy_optarg(ld, &ld->ld_soname, arg); break; case 'I': _copy_optarg(ld, &ld->ld_interp, arg); break; case 'l': ld_path_search_library(ld, arg); break; case 'L': ld_path_add(ld, arg); break; case 'M': ld->ld_print_linkmap = 1; break; case 'o': _copy_optarg(ld, &ld->ld_output_file, arg); break; case 'q': ld->ld_emit_reloc = 1; break; case 'r': ld->ld_reloc = 1; break; case 'T': ld_script_parse(arg); break; case 'u': ld_symbols_add_extern(ld, arg); break; case 'v': case 'V': _print_version(ld); break; case '(': ls->ls_group_level++; if (ls->ls_group_level > LD_MAX_NESTED_GROUP) ld_fatal(ld, "too many nested archive groups"); break; case ')': ls->ls_group_level--; break; case KEY_AS_NEEDED: ls->ls_as_needed = 1; break; case KEY_DYNAMIC: ls->ls_static = 0; break; case KEY_EH_FRAME_HDR: ld->ld_ehframe_hdr = 1; break; case KEY_GC_SECTIONS: ld->ld_gc = 1; break; case KEY_NO_AS_NEEDED: ls->ls_as_needed = 0; break; case KEY_NO_DEFINE_COMMON: ld->ld_common_no_alloc = 1; break; case KEY_NO_GC_SECTIONS: ld->ld_gc = 0; break; case KEY_NO_PRINT_GC_SECTIONS: ld->ld_gc_print = 0; break; case KEY_NO_WHOLE_ARCHIVE: ls->ls_whole_archive = 0; break; case KEY_OFORMAT: ld_output_format(ld, arg, arg, arg); break; case KEY_PIE: ld->ld_exec = 0; ld->ld_pie = 1; ld->ld_dynamic_link = 1; break; case KEY_PRINT_GC_SECTIONS: ld->ld_gc_print = 1; break; case KEY_SHARED: ld->ld_exec = 0; ld->ld_dso = 1; ld->ld_dynamic_link = 1; break; case KEY_STATIC: ls->ls_static = 1; break; case KEY_WHOLE_ARCHIVE: ls->ls_whole_archive = 1; break; case KEY_FILE: ld_file_add(ld, arg, LFT_UNKNOWN); break; case KEY_VERSION_SCRIPT: ld_script_parse(arg); break; case KEY_Z_EXEC_STACK: ld->ld_gen_gnustack = 1; ld->ld_stack_exec_set = 1; ld->ld_stack_exec = 1; break; case KEY_Z_NO_EXEC_STACK: ld->ld_gen_gnustack = 1; ld->ld_stack_exec_set = 1; ld->ld_stack_exec = 0; break; default: break; } }
void ld_options_parse(struct ld* ld, int argc, char **argv) { enum ld_dash d; char *p, *p0, *oli; int ac, ac0; ac = 1; while (ac < argc) { p = argv[ac]; if (*p != '-' || p[1] == '\0') { _process_options(ld, KEY_FILE, p); ac++; continue; } if (*++p == '-') { if (p[1] == '\0') { /* Option --. Ignore the rest of options. */ return; } p++; d = TWO_DASH; } else { d = ONE_DASH; if (*p == 'B' || *p == 'z') { ac0 = ac; if (*(p0 = p + 1) == '\0') p0 = argv[++ac0]; ac = _parse_long_options(ld, *p == 'B' ? ld_opts_B : ld_opts_z, ac0, argc, argv, p0, d); if (ac > 0) continue; ld_fatal(ld, "unrecognized options -%c: %s", *p, p0); } } ac0 = _parse_long_options(ld, ld_opts, ac, argc, argv, p, d); if (ac0 > 0) { ac = ac0; continue; } if (d == TWO_DASH) ld_fatal(ld, "unrecognized option %s", p); /* * Search short options. */ while (*p != '\0') { if ((oli = strchr(ld_short_opts, *p)) == NULL) ld_fatal(ld, "unrecognized option -%c", *p); if (*++oli != ':') { _process_options(ld, *p++, NULL); continue; } if (p[1] != '\0') _process_options(ld, *p, &p[1]); else if (oli[1] != ':') { if (++ac >= argc) ld_fatal(ld, "require arg for" " option -%c", *p); _process_options(ld, *p, argv[ac]); } break; } ac++; } }