X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-s390.c;h=f74497aa85573caa91c0c0aacb71ded6bb6e3cd6;hb=4288405d5ec2c68c7e9d8d68a090c6c9ff3825d1;hp=325012794478d552f9638be043c03f431ede025f;hpb=3739860c11a9cfcdaa4d5d204ea3536784de7bb3;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-s390.c b/gas/config/tc-s390.c index 3250127944..f74497aa85 100644 --- a/gas/config/tc-s390.c +++ b/gas/config/tc-s390.c @@ -1,5 +1,5 @@ /* tc-s390.c -- Assemble for the S390 - Copyright (C) 2000-2015 Free Software Foundation, Inc. + Copyright (C) 2000-2019 Free Software Foundation, Inc. Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). This file is part of GAS, the GNU Assembler. @@ -22,7 +22,6 @@ #include "as.h" #include "safe-ctype.h" #include "subsegs.h" -#include "struc-symbol.h" #include "dwarf2dbg.h" #include "dw2gencfi.h" @@ -33,7 +32,7 @@ #ifndef DEFAULT_ARCH #define DEFAULT_ARCH "s390" #endif -static char *default_arch = DEFAULT_ARCH; +static const char *default_arch = DEFAULT_ARCH; /* Either 32 or 64, selects file format. */ static int s390_arch_size = 0; @@ -41,6 +40,10 @@ static int s390_arch_size = 0; Since with S/390 a newer CPU always supports everything from its predecessors this will accept every valid asm input. */ static unsigned int current_cpu = S390_OPCODE_MAXCPU - 1; +/* All facilities are enabled by default. */ +static unsigned int current_flags = S390_INSTR_FLAG_FACILITY_MASK; +/* The mode mask default is picked in init_default_arch depending on + the current cpu. */ static unsigned int current_mode_mask = 0; /* Set to TRUE if the highgprs flag in the ELF header needs to be set @@ -168,11 +171,11 @@ register_name (expressionS *expressionP) else return FALSE; - c = get_symbol_end (); + c = get_symbol_name (&name); reg_number = reg_name_search (name); /* Put back the delimiting char. */ - *input_line_pointer = c; + (void) restore_line_pointer (c); /* Look to see if it's in the register table. */ if (reg_number >= 0) @@ -254,41 +257,142 @@ s390_target_format (void) return s390_arch_size == 64 ? "elf64-s390" : "elf32-s390"; } -/* Map a CPU string as given with -march= or .machine to the - respective enum s390_opcode_cpu_val value. 0xffffffff is returned - in case of an error. */ +/* Map a cpu string ARG as given with -march= or .machine to the respective + enum s390_opcode_cpu_val value. If ALLOW_EXTENSIONS is TRUE, the cpu name + can be followed by a list of cpu facility flags each beginning with the + character '+'. The active cpu flags are returned through *RET_FLAGS. + In case of an error, S390_OPCODE_MAXCPU is returned. */ static unsigned int -s390_parse_cpu (char *arg) +s390_parse_cpu (const char * arg, + unsigned int * ret_flags, + bfd_boolean allow_extensions) { - if (strcmp (arg, "g5") == 0) - return S390_OPCODE_G5; - else if (strcmp (arg, "g6") == 0) - return S390_OPCODE_G6; - else if (strcmp (arg, "z900") == 0) - return S390_OPCODE_Z900; - else if (strcmp (arg, "z990") == 0) - return S390_OPCODE_Z990; - else if (strcmp (arg, "z9-109") == 0) - return S390_OPCODE_Z9_109; - else if (strcmp (arg, "z9-ec") == 0) - return S390_OPCODE_Z9_EC; - else if (strcmp (arg, "z10") == 0) - return S390_OPCODE_Z10; - else if (strcmp (arg, "z196") == 0) - return S390_OPCODE_Z196; - else if (strcmp (arg, "zEC12") == 0) - return S390_OPCODE_ZEC12; - else if (strcmp (arg, "z13") == 0) - return S390_OPCODE_Z13; - else if (strcmp (arg, "all") == 0) - return S390_OPCODE_MAXCPU - 1; + static struct + { + const char * name; + unsigned int name_len; + const char * alt_name; + unsigned int alt_name_len; + unsigned int flags; + } cpu_table[S390_OPCODE_MAXCPU] = + { + { STRING_COMMA_LEN ("g5"), STRING_COMMA_LEN ("arch3"), 0 }, + { STRING_COMMA_LEN ("g6"), STRING_COMMA_LEN (""), 0 }, + { STRING_COMMA_LEN ("z900"), STRING_COMMA_LEN ("arch5"), 0 }, + { STRING_COMMA_LEN ("z990"), STRING_COMMA_LEN ("arch6"), 0 }, + { STRING_COMMA_LEN ("z9-109"), STRING_COMMA_LEN (""), 0 }, + { STRING_COMMA_LEN ("z9-ec"), STRING_COMMA_LEN ("arch7"), 0 }, + { STRING_COMMA_LEN ("z10"), STRING_COMMA_LEN ("arch8"), 0 }, + { STRING_COMMA_LEN ("z196"), STRING_COMMA_LEN ("arch9"), 0 }, + { STRING_COMMA_LEN ("zEC12"), STRING_COMMA_LEN ("arch10"), + S390_INSTR_FLAG_HTM }, + { STRING_COMMA_LEN ("z13"), STRING_COMMA_LEN ("arch11"), + S390_INSTR_FLAG_HTM | S390_INSTR_FLAG_VX }, + { STRING_COMMA_LEN ("z14"), STRING_COMMA_LEN ("arch12"), + S390_INSTR_FLAG_HTM | S390_INSTR_FLAG_VX }, + { STRING_COMMA_LEN (""), STRING_COMMA_LEN ("arch13"), + S390_INSTR_FLAG_HTM | S390_INSTR_FLAG_VX } + }; + static struct + { + const char * name; + unsigned int mask; + bfd_boolean on; + } cpu_flags[] = + { + { "htm", S390_INSTR_FLAG_HTM, TRUE }, + { "nohtm", S390_INSTR_FLAG_HTM, FALSE }, + { "vx", S390_INSTR_FLAG_VX, TRUE }, + { "novx", S390_INSTR_FLAG_VX, FALSE } + }; + unsigned int icpu; + char *ilp_bak; + + icpu = S390_OPCODE_MAXCPU; + if (strncmp (arg, "all", 3) == 0 && (arg[3] == 0 || arg[3] == '+')) + { + icpu = S390_OPCODE_MAXCPU - 1; + arg += 3; + } else - return -1; + { + for (icpu = 0; icpu < S390_OPCODE_MAXCPU; icpu++) + { + unsigned int l, l_alt; + + l = cpu_table[icpu].name_len; + + if (strncmp (arg, cpu_table[icpu].name, l) == 0 + && (arg[l] == 0 || arg[l] == '+')) + { + arg += l; + break; + } + + l_alt = cpu_table[icpu].alt_name_len; + + if (l_alt > 0 + && strncmp (arg, cpu_table[icpu].alt_name, l_alt) == 0 + && (arg[l_alt] == 0 || arg[l_alt] == '+')) + { + arg += l_alt; + break; + } + } + } + + if (icpu == S390_OPCODE_MAXCPU) + return S390_OPCODE_MAXCPU; + + ilp_bak = input_line_pointer; + if (icpu != S390_OPCODE_MAXCPU) + { + input_line_pointer = (char *) arg; + *ret_flags = (cpu_table[icpu].flags & S390_INSTR_FLAG_FACILITY_MASK); + + while (*input_line_pointer == '+' && allow_extensions) + { + unsigned int iflag; + char *sym; + char c; + + input_line_pointer++; + c = get_symbol_name (&sym); + for (iflag = 0; iflag < ARRAY_SIZE (cpu_flags); iflag++) + { + if (strcmp (sym, cpu_flags[iflag].name) == 0) + { + if (cpu_flags[iflag].on) + *ret_flags |= cpu_flags[iflag].mask; + else + *ret_flags &= ~cpu_flags[iflag].mask; + break; + } + } + if (iflag == ARRAY_SIZE (cpu_flags)) + as_bad (_("no such machine extension `%s'"), sym - 1); + *input_line_pointer = c; + if (iflag == ARRAY_SIZE (cpu_flags)) + break; + } + } + + SKIP_WHITESPACE (); + + if (*input_line_pointer != 0 && *input_line_pointer != '\n') + { + as_bad (_("junk at end of machine string, first unrecognized character" + " is `%c'"), *input_line_pointer); + icpu = S390_OPCODE_MAXCPU; + } + input_line_pointer = ilp_bak; + + return icpu; } int -md_parse_option (int c, char *arg) +md_parse_option (int c, const char *arg) { switch (c) { @@ -323,9 +427,8 @@ md_parse_option (int c, char *arg) else if (arg != NULL && strncmp (arg, "arch=", 5) == 0) { - current_cpu = s390_parse_cpu (arg + 5); - - if (current_cpu == (unsigned int)-1) + current_cpu = s390_parse_cpu (arg + 5, ¤t_flags, FALSE); + if (current_cpu == S390_OPCODE_MAXCPU) { as_bad (_("invalid switch -m%s"), arg); return 0; @@ -402,6 +505,8 @@ s390_setup_opcodes (void) op_end = s390_opcodes + s390_num_opcodes; for (op = s390_opcodes; op < op_end; op++) { + int use_opcode; + while (op < op_end - 1 && strcmp(op->name, op[1].name) == 0) { if (op->min_cpu <= current_cpu && (op->modes & current_mode_mask)) @@ -409,7 +514,24 @@ s390_setup_opcodes (void) op++; } - if (op->min_cpu <= current_cpu && (op->modes & current_mode_mask)) + if ((op->modes & current_mode_mask) == 0) + use_opcode = 0; + else if ((op->flags & S390_INSTR_FLAG_FACILITY_MASK) == 0) + { + /* Opcodes that do not belong to a specific facility are enabled if + present in the selected cpu. */ + use_opcode = (op->min_cpu <= current_cpu); + } + else + { + unsigned int f; + + /* Opcodes of a specific facility are enabled if the facility is + enabled. Note: only some facilities are represented as flags. */ + f = (op->flags & S390_INSTR_FLAG_FACILITY_MASK); + use_opcode = ((f & current_flags) == f); + } + if (use_opcode) { retval = hash_insert (s390_opcode_hash, op->name, (void *) op); if (retval != (const char *) NULL) @@ -422,7 +544,7 @@ s390_setup_opcodes (void) while (op < op_end - 1 && strcmp (op->name, op[1].name) == 0) op++; - } + } if (dup_insn) abort (); @@ -484,7 +606,7 @@ static void s390_insert_operand (unsigned char *insn, const struct s390_operand *operand, offsetT val, - char *file, + const char *file, unsigned int line) { addressT uval; @@ -607,7 +729,7 @@ s390_insert_operand (unsigned char *insn, struct map_tls { - char *string; + const char *string; int length; bfd_reloc_code_real_type reloc; }; @@ -682,7 +804,7 @@ elf_suffix_type; struct map_bfd { - char *string; + const char *string; int length; elf_suffix_type suffix; }; @@ -810,6 +932,7 @@ s390_exp_compare (expressionS *exp1, expressionS *exp2) case O_big: as_bad (_("Can't handle O_big in s390_exp_compare")); + return 0; case O_symbol: /* X_add_symbol & X_add_number must be equal. */ case O_symbol_rva: @@ -846,7 +969,7 @@ s390_exp_compare (expressionS *exp1, expressionS *exp2) } } -/* Test for @lit and if its present make an entry in the literal pool and +/* Test for @lit and if it's present make an entry in the literal pool and modify the current expression to be an offset into the literal pool. */ static elf_suffix_type s390_lit_suffix (char **str_p, expressionS *exp_p, elf_suffix_type suffix) @@ -934,7 +1057,7 @@ s390_lit_suffix (char **str_p, expressionS *exp_p, elf_suffix_type suffix) } else { - lpe = (struct s390_lpe *) xmalloc (sizeof (struct s390_lpe)); + lpe = XNEW (struct s390_lpe); } lpe->ex = *exp_p; @@ -976,7 +1099,7 @@ s390_lit_suffix (char **str_p, expressionS *exp_p, elf_suffix_type suffix) } /* Now change exp_p to the offset into the literal pool. - Thats the expression: .L^Ax^By-.L^Ax */ + That's the expression: .L^Ax^By-.L^Ax */ exp_p->X_add_symbol = lpe->sym; exp_p->X_op_symbol = lp_sym; exp_p->X_op = O_subtract; @@ -1084,7 +1207,9 @@ s390_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long */) { size = bfd_get_reloc_size (reloc_howto); if (size > nbytes) - as_bad (_("%s relocations do not fit in %d bytes"), + as_bad (ngettext ("%s relocations do not fit in %d byte", + "%s relocations do not fit in %d bytes", + nbytes), reloc_howto->name, nbytes); where = frag_more (nbytes); md_number_to_chars (where, 0, size); @@ -1105,6 +1230,24 @@ s390_elf_cons (int nbytes /* 1=.byte, 2=.word, 4=.long */) demand_empty_rest_of_line (); } +/* Return true if all remaining operands in the opcode with + OPCODE_FLAGS can be skipped. */ +static bfd_boolean +skip_optargs_p (unsigned int opcode_flags, const unsigned char *opindex_ptr) +{ + if ((opcode_flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2)) + && opindex_ptr[0] != '\0' + && opindex_ptr[1] == '\0') + return TRUE; + + if ((opcode_flags & S390_INSTR_FLAG_OPTPARM2) + && opindex_ptr[0] != '\0' + && opindex_ptr[1] != '\0' + && opindex_ptr[2] == '\0') + return TRUE; + return FALSE; +} + /* We need to keep a list of fixups. We can't simply generate them as we go, because that would require us to first create the frag, and that would screw up references to ``.''. */ @@ -1148,7 +1291,8 @@ md_gather_operands (char *str, operand = s390_operands + *opindex_ptr; - if ((opcode->flags & S390_INSTR_FLAG_OPTPARM) && *str == '\0') + if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2)) + && *str == '\0') { /* Optional parameters might need to be ORed with a value so calling s390_insert_operand is needed. */ @@ -1182,19 +1326,6 @@ md_gather_operands (char *str, as_bad (_("illegal operand")); else if (ex.X_op == O_absent) { - /* No operands, check if all operands can be skipped. */ - while (*opindex_ptr != 0 && operand->flags & S390_OPERAND_OPTIONAL) - { - if (operand->flags & S390_OPERAND_DISP) - { - /* An optional displacement makes the whole D(X,B) - D(L,B) or D(B) block optional. */ - do { - operand = s390_operands + *(++opindex_ptr); - } while (!(operand->flags & S390_OPERAND_BASE)); - } - operand = s390_operands + *(++opindex_ptr); - } if (opindex_ptr[0] == '\0') break; as_bad (_("missing operand")); @@ -1346,7 +1477,7 @@ md_gather_operands (char *str, if (*str != '(') { /* Check if parenthesized block can be skipped. If the next - operand is neiter an optional operand nor a base register + operand is neither an optional operand nor a base register then we have a syntax error. */ operand = s390_operands + *(++opindex_ptr); if (!(operand->flags & (S390_OPERAND_INDEX|S390_OPERAND_BASE))) @@ -1356,6 +1487,9 @@ md_gather_operands (char *str, while (!(operand->flags & S390_OPERAND_BASE)) operand = s390_operands + *(++opindex_ptr); + if (*str == '\0' && skip_optargs_p (opcode->flags, &opindex_ptr[1])) + continue; + /* If there is a next operand it must be separated by a comma. */ if (opindex_ptr[1] != '\0') { @@ -1364,9 +1498,7 @@ md_gather_operands (char *str, while (opindex_ptr[1] != '\0') { operand = s390_operands + *(++opindex_ptr); - if (operand->flags & S390_OPERAND_OPTIONAL) - continue; - as_bad (_("syntax error; expected ,")); + as_bad (_("syntax error; expected ','")); break; } } @@ -1396,10 +1528,14 @@ md_gather_operands (char *str, } else if (operand->flags & S390_OPERAND_BASE) { - /* After the base register the parenthesed block ends. */ + /* After the base register the parenthesised block ends. */ if (*str++ != ')') as_bad (_("syntax error; missing ')' after base register")); skip_optional = 0; + + if (*str == '\0' && skip_optargs_p (opcode->flags, &opindex_ptr[1])) + continue; + /* If there is a next operand it must be separated by a comma. */ if (opindex_ptr[1] != '\0') { @@ -1408,9 +1544,7 @@ md_gather_operands (char *str, while (opindex_ptr[1] != '\0') { operand = s390_operands + *(++opindex_ptr); - if (operand->flags & S390_OPERAND_OPTIONAL) - continue; - as_bad (_("syntax error; expected ,")); + as_bad (_("syntax error; expected ','")); break; } } @@ -1431,7 +1565,7 @@ md_gather_operands (char *str, str++; } - if ((opcode->flags & S390_INSTR_FLAG_OPTPARM) && *str == '\0') + if (*str == '\0' && skip_optargs_p (opcode->flags, &opindex_ptr[1])) continue; /* If there is a next operand it must be separated by a comma. */ @@ -1442,9 +1576,7 @@ md_gather_operands (char *str, while (opindex_ptr[1] != '\0') { operand = s390_operands + *(++opindex_ptr); - if (operand->flags & S390_OPERAND_OPTIONAL) - continue; - as_bad (_("syntax error; expected ,")); + as_bad (_("syntax error; expected ','")); break; } } @@ -1532,6 +1664,9 @@ md_gather_operands (char *str, || fixups[i].reloc == BFD_RELOC_390_GOT20 || fixups[i].reloc == BFD_RELOC_390_GOT16) fixP->fx_no_overflow = 1; + + if (operand->flags & S390_OPERAND_PCREL) + fixP->fx_pcrel_adjust = operand->shift / 8; } else fix_new_exp (frag_now, f - frag_now->fr_literal, 4, &fixups[i].exp, @@ -1723,7 +1858,7 @@ s390_literals (int ignore ATTRIBUTE_UNUSED) /* Emit symbol for start of literal pool. */ S_SET_SEGMENT (lp_sym, now_seg); S_SET_VALUE (lp_sym, (valueT) frag_now_fix ()); - lp_sym->sy_frag = frag_now; + symbol_set_frag (lp_sym, frag_now); while (lpe_list) { @@ -1731,7 +1866,7 @@ s390_literals (int ignore ATTRIBUTE_UNUSED) lpe_list = lpe_list->next; S_SET_SEGMENT (lpe->sym, now_seg); S_SET_VALUE (lpe->sym, (valueT) frag_now_fix ()); - lpe->sym->sy_frag = frag_now; + symbol_set_frag (lpe->sym, frag_now); /* Emit literal pool entry. */ if (lpe->reloc != BFD_RELOC_UNUSED) @@ -1742,7 +1877,9 @@ s390_literals (int ignore ATTRIBUTE_UNUSED) char *where; if (size > lpe->nbytes) - as_bad (_("%s relocations do not fit in %d bytes"), + as_bad (ngettext ("%s relocations do not fit in %d byte", + "%s relocations do not fit in %d bytes", + lpe->nbytes), reloc_howto->name, lpe->nbytes); where = frag_more (lpe->nbytes); md_number_to_chars (where, 0, size); @@ -1771,6 +1908,8 @@ s390_literals (int ignore ATTRIBUTE_UNUSED) lpe_count = 0; } +#define MAX_HISTORY 100 + /* The .machine pseudo op allows to switch to a different CPU level in the asm listing. The current CPU setting can be stored on a stack with .machine push and restored with .machine pop. */ @@ -1779,8 +1918,11 @@ static void s390_machine (int ignore ATTRIBUTE_UNUSED) { char *cpu_string; -#define MAX_HISTORY 100 - static unsigned int *cpu_history; + static struct cpu_history + { + unsigned int cpu; + unsigned int flags; + } *cpu_history; static int curr_hist; SKIP_WHITESPACE (); @@ -1793,41 +1935,67 @@ s390_machine (int ignore ATTRIBUTE_UNUSED) else { char c; + cpu_string = input_line_pointer; - c = get_symbol_end (); + do + { + char * str; + + c = get_symbol_name (&str); + c = restore_line_pointer (c); + if (c == '+') + ++ input_line_pointer; + } + while (c == '+'); + + c = *input_line_pointer; + *input_line_pointer = 0; cpu_string = xstrdup (cpu_string); - *input_line_pointer = c; + (void) restore_line_pointer (c); } if (cpu_string != NULL) { - unsigned int old_cpu = current_cpu; - unsigned int new_cpu; + unsigned int new_cpu = current_cpu; + unsigned int new_flags = current_flags; if (strcmp (cpu_string, "push") == 0) { if (cpu_history == NULL) - cpu_history = xmalloc (MAX_HISTORY * sizeof (*cpu_history)); + cpu_history = XNEWVEC (struct cpu_history, MAX_HISTORY); if (curr_hist >= MAX_HISTORY) as_bad (_(".machine stack overflow")); else - cpu_history[curr_hist++] = current_cpu; + { + cpu_history[curr_hist].cpu = current_cpu; + cpu_history[curr_hist].flags = current_flags; + curr_hist++; + } } else if (strcmp (cpu_string, "pop") == 0) { if (curr_hist <= 0) as_bad (_(".machine stack underflow")); else - current_cpu = cpu_history[--curr_hist]; + { + curr_hist--; + new_cpu = cpu_history[curr_hist].cpu; + new_flags = cpu_history[curr_hist].flags; + } } - else if ((new_cpu = s390_parse_cpu (cpu_string)) != (unsigned int)-1) - current_cpu = new_cpu; else + new_cpu = s390_parse_cpu (cpu_string, &new_flags, TRUE); + + if (new_cpu == S390_OPCODE_MAXCPU) as_bad (_("invalid machine `%s'"), cpu_string); - if (current_cpu != old_cpu) - s390_setup_opcodes (); + if (new_cpu != current_cpu || new_flags != current_flags) + { + current_cpu = new_cpu; + current_flags = new_flags; + s390_setup_opcodes (); + } } demand_empty_rest_of_line (); @@ -1842,25 +2010,18 @@ static void s390_machinemode (int ignore ATTRIBUTE_UNUSED) { char *mode_string; -#define MAX_HISTORY 100 static unsigned int *mode_history; static int curr_hist; SKIP_WHITESPACE (); - if (*input_line_pointer == '"') - { - int len; - mode_string = demand_copy_C_string (&len); - } - else - { - char c; - mode_string = input_line_pointer; - c = get_symbol_end (); - mode_string = xstrdup (mode_string); - *input_line_pointer = c; - } + { + char c; + + c = get_symbol_name (&mode_string); + mode_string = xstrdup (mode_string); + (void) restore_line_pointer (c); + } if (mode_string != NULL) { @@ -1873,7 +2034,7 @@ s390_machinemode (int ignore ATTRIBUTE_UNUSED) if (strcmp (mode_string, "push") == 0) { if (mode_history == NULL) - mode_history = xmalloc (MAX_HISTORY * sizeof (*mode_history)); + mode_history = XNEWVEC (unsigned int, MAX_HISTORY); if (curr_hist >= MAX_HISTORY) as_bad (_(".machinemode stack overflow")); @@ -1900,7 +2061,7 @@ s390_machinemode (int ignore ATTRIBUTE_UNUSED) else if (strcmp (mode_string, "zarch_nohighgprs") == 0) current_mode_mask = 1 << S390_OPCODE_ZARCH; else - as_bad (_("invalid machine `%s'"), mode_string); + as_bad (_("invalid machine mode `%s'"), mode_string); } if (current_mode_mask != old_mode_mask) @@ -1910,7 +2071,9 @@ s390_machinemode (int ignore ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } -char * +#undef MAX_HISTORY + +const char * md_atof (int type, char *litp, int *sizep) { return ieee_md_atof (type, litp, sizep, TRUE); @@ -1923,7 +2086,7 @@ md_section_align (asection *seg, valueT addr) { int align = bfd_get_section_alignment (stdoutput, seg); - return ((addr + (1 << align) - 1) & (-1 << align)); + return ((addr + (1 << align) - 1) & -(1 << align)); } /* We don't have any form of relaxing. */ @@ -1982,9 +2145,11 @@ md_pcrel_from_section (fixS *fixp, segT sec ATTRIBUTE_UNUSED) int tc_s390_fix_adjustable (fixS *fixP) { - /* Don't adjust references to merge sections. */ - if ((S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0) + /* Don't adjust pc-relative references to merge sections. */ + if (fixP->fx_pcrel + && (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0) return 0; + /* adjust_reloc_syms doesn't know about the GOT. */ if ( fixP->fx_r_type == BFD_RELOC_16_GOTOFF || fixP->fx_r_type == BFD_RELOC_32_GOTOFF @@ -2144,7 +2309,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) } else if (operand->bits == 20 && operand->shift == 20) { - fixP->fx_size = 2; + fixP->fx_size = 4; fixP->fx_where += 2; fixP->fx_r_type = BFD_RELOC_390_20; } @@ -2160,6 +2325,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) fixP->fx_size = 2; fixP->fx_where += 1; fixP->fx_offset += 1; + fixP->fx_pcrel_adjust = 1; fixP->fx_r_type = BFD_RELOC_390_PC12DBL; } else if (operand->bits == 16 && operand->shift == 16) @@ -2170,16 +2336,27 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { fixP->fx_r_type = BFD_RELOC_390_PC16DBL; fixP->fx_offset += 2; + fixP->fx_pcrel_adjust = 2; } else fixP->fx_r_type = BFD_RELOC_16; } + else if (operand->bits == 16 && operand->shift == 32 + && (operand->flags & S390_OPERAND_PCREL)) + { + fixP->fx_size = 2; + fixP->fx_where += 4; + fixP->fx_offset += 4; + fixP->fx_pcrel_adjust = 4; + fixP->fx_r_type = BFD_RELOC_390_PC16DBL; + } else if (operand->bits == 24 && operand->shift == 24 && (operand->flags & S390_OPERAND_PCREL)) { fixP->fx_size = 3; fixP->fx_where += 3; fixP->fx_offset += 3; + fixP->fx_pcrel_adjust = 3; fixP->fx_r_type = BFD_RELOC_390_PC24DBL; } else if (operand->bits == 32 && operand->shift == 16 @@ -2188,11 +2365,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) fixP->fx_size = 4; fixP->fx_where += 2; fixP->fx_offset += 2; + fixP->fx_pcrel_adjust = 2; fixP->fx_r_type = BFD_RELOC_390_PC32DBL; } else { - char *sfile; + const char *sfile; unsigned int sline; /* Use expr_symbol_where to see if this is an expression @@ -2223,7 +2401,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_390_PC12DBL: case BFD_RELOC_390_PLT12DBL: if (fixP->fx_pcrel) - value++; + value += fixP->fx_pcrel_adjust; if (fixP->fx_done) { @@ -2274,14 +2452,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) break; case BFD_RELOC_390_PC16DBL: case BFD_RELOC_390_PLT16DBL: - value += 2; + value += fixP->fx_pcrel_adjust; if (fixP->fx_done) md_number_to_chars (where, (offsetT) value >> 1, 2); break; case BFD_RELOC_390_PC24DBL: case BFD_RELOC_390_PLT24DBL: - value += 3; + value += fixP->fx_pcrel_adjust; if (fixP->fx_done) { unsigned int mop; @@ -2319,7 +2497,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_390_GOTPCDBL: case BFD_RELOC_390_GOTENT: case BFD_RELOC_390_GOTPLTENT: - value += 2; + value += fixP->fx_pcrel_adjust; if (fixP->fx_done) md_number_to_chars (where, (offsetT) value >> 1, 4); break; @@ -2424,8 +2602,8 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) code = BFD_RELOC_390_GOTPCDBL; } - reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc = XNEW (arelent); + reloc->sym_ptr_ptr = XNEW (asymbol *); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; reloc->howto = bfd_reloc_type_lookup (stdoutput, code);