X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-sh.c;h=275415aeb90812551b9def18d53f16a82d447e7e;hb=069f40e56f8ac85845312a4366afff828b026b7a;hp=836289629550190659d72a7a9f8810a34a9ad6bf;hpb=0d10e18267c6476627a1881c24bb6e364368f74a;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c index 8362896295..275415aeb9 100644 --- a/gas/config/tc-sh.c +++ b/gas/config/tc-sh.c @@ -34,7 +34,6 @@ #endif #include "dwarf2dbg.h" -struct dwarf2_line_info debug_line; const char comment_chars[] = "!"; const char line_separator_chars[] = ";"; @@ -51,6 +50,12 @@ static void s_uacons PARAMS ((int)); static sh_opcode_info *find_cooked_opcode PARAMS ((char **)); static unsigned int assemble_ppi PARAMS ((char *, sh_opcode_info *)); +#ifdef OBJ_ELF +static void sh_elf_cons PARAMS ((int)); + +symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ +#endif + int shl = 0; static void @@ -69,8 +74,15 @@ little (ignore) const pseudo_typeS md_pseudo_table[] = { +#ifdef OBJ_ELF + {"long", sh_elf_cons, 4}, + {"int", sh_elf_cons, 4}, + {"word", sh_elf_cons, 2}, + {"short", sh_elf_cons, 2}, +#else {"int", cons, 4}, {"word", cons, 2}, +#endif /* OBJ_ELF */ {"form", listing_psize, 0}, {"little", little, 0}, {"heading", listing_title, 0}, @@ -110,7 +122,6 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP"; #define C(a,b) ENCODE_RELAX(a,b) -#define JREG 14 /* Register used as a temp when relaxing */ #define ENCODE_RELAX(what,length) (((what) << 4) + (length)) #define GET_WHAT(x) ((x>>4)) @@ -200,6 +211,191 @@ const relax_typeS md_relax_table[C (END, 0)] = { static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ + +#ifdef OBJ_ELF +/* Parse @got, etc. and return the desired relocation. + If we have additional arithmetic expression, then we fill in new_exp_p. */ +static bfd_reloc_code_real_type +sh_elf_suffix (str_p, exp_p, new_exp_p) + char **str_p; + expressionS *exp_p, *new_exp_p; +{ + struct map_bfd { + char *string; + int length; + bfd_reloc_code_real_type reloc; + }; + + char ident[20]; + char *str = *str_p; + char *str2; + int ch; + int len; + struct map_bfd *ptr; + +#define MAP(str,reloc) { str, sizeof (str)-1, reloc } + + static struct map_bfd mapping[] = { + MAP ("got", BFD_RELOC_32_GOT_PCREL), + MAP ("plt", BFD_RELOC_32_PLT_PCREL), + MAP ("gotoff", BFD_RELOC_32_GOTOFF), + { (char *)0, 0, BFD_RELOC_UNUSED } + }; + + if (*str++ != '@') + return BFD_RELOC_UNUSED; + + for (ch = *str, str2 = ident; + (str2 < ident + sizeof (ident) - 1 + && (isalnum (ch) || ch == '@')); + ch = *++str) + { + *str2++ = (islower (ch)) ? ch : tolower (ch); + } + + *str2 = '\0'; + len = str2 - ident; + + ch = ident[0]; + for (ptr = &mapping[0]; ptr->length > 0; ptr++) + if (ch == ptr->string[0] + && len == ptr->length + && memcmp (ident, ptr->string, ptr->length) == 0) + { + /* Now check for identifier@suffix+constant */ + if (*str == '-' || *str == '+') + { + char *orig_line = input_line_pointer; + + input_line_pointer = str; + expression (new_exp_p); + if (new_exp_p->X_op == O_constant) + { + exp_p->X_add_number += new_exp_p->X_add_number; + str = input_line_pointer; + } + if (new_exp_p->X_op == O_subtract) + str = input_line_pointer; + + if (&input_line_pointer != str_p) + input_line_pointer = orig_line; + } + + *str_p = str; + return ptr->reloc; + } + + return BFD_RELOC_UNUSED; +} + +/* The regular cons() function, that reads constants, doesn't support + suffixes such as @GOT, @GOTOFF and @PLT, that generate + machine-specific relocation types. So we must define it here. */ +/* Clobbers input_line_pointer, checks end-of-line. */ +static void +sh_elf_cons (nbytes) + register int nbytes; /* 1=.byte, 2=.word, 4=.long */ +{ + expressionS exp, new_exp; + bfd_reloc_code_real_type reloc; + const char *name; + + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + + do + { + expression (&exp); + new_exp.X_op = O_absent; + new_exp.X_add_symbol = new_exp.X_op_symbol = NULL; + /* If the _GLOBAL_OFFSET_TABLE_ symbol hasn't been found yet, + use the name of the symbol to tell whether it's the + _GLOBAL_OFFSET_TABLE_. If it has, comparing the symbols is + sufficient. */ + if (! GOT_symbol && exp.X_add_symbol) + name = S_GET_NAME (exp.X_add_symbol); + else + name = NULL; + /* Check whether this expression involves the + _GLOBAL_OFFSET_TABLE_ symbol, by itself or added to a + difference of two other symbols. */ + if (((GOT_symbol && GOT_symbol == exp.X_add_symbol) + || (! GOT_symbol && name + && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)) + && (exp.X_op == O_symbol + || (exp.X_op == O_add + && ((symbol_get_value_expression (exp.X_op_symbol)->X_op) + == O_subtract)))) + { + reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, + BFD_RELOC_32); + int size = bfd_get_reloc_size (reloc_howto); + + if (GOT_symbol == NULL) + GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); + + if (size > nbytes) + as_bad (_("%s relocations do not fit in %d bytes\n"), + reloc_howto->name, nbytes); + else + { + register char *p = frag_more ((int) nbytes); + int offset = nbytes - size; + + fix_new_exp (frag_now, p - frag_now->fr_literal + offset, + size, &exp, 0, TC_RELOC_GLOBAL_OFFSET_TABLE); + } + } + /* Check if this symbol involves one of the magic suffixes, such + as @GOT, @GOTOFF or @PLT, and determine which relocation type + to use. */ + else if ((exp.X_op == O_symbol || (exp.X_op == O_add && exp.X_op_symbol)) + && *input_line_pointer == '@' + && ((reloc = sh_elf_suffix (&input_line_pointer, &exp, &new_exp)) + != BFD_RELOC_UNUSED)) + { + reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, + reloc); + int size = bfd_get_reloc_size (reloc_howto); + + /* Force a GOT to be generated. */ + if (GOT_symbol == NULL) + GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); + + if (size > nbytes) + as_bad (_("%s relocations do not fit in %d bytes\n"), + reloc_howto->name, nbytes); + else + { + register char *p = frag_more ((int) nbytes); + int offset = nbytes - size; + + fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, + &exp, 0, reloc); + if (new_exp.X_op != O_absent) + fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, + &new_exp, 0, BFD_RELOC_32); + } + } + else + emit_expr (&exp, (unsigned int) nbytes); + } + while (*input_line_pointer++ == ','); + + input_line_pointer--; /* Put terminator back into stream. */ + if (*input_line_pointer == '#' || *input_line_pointer == '!') + { + while (! is_end_of_line[(unsigned char) *input_line_pointer++]); + } + else + demand_empty_rest_of_line (); +} +#endif /* OBJ_ELF */ + + /* This function is called once, at assembler startup time. This should set up all the tables, etc that the MD part of the assembler needs. */ @@ -266,13 +462,16 @@ parse_reg (src, mode, reg) int *mode; int *reg; { + char l0 = tolower (src[0]); + char l1 = l0 ? tolower (src[1]) : 0; + /* We use ! IDENT_CHAR for the next character after the register name, to make sure that we won't accidentally recognize a symbol name such as 'sram' or sr_ram as being a reference to the register 'sr'. */ - if (src[0] == 'r') + if (l0 == 'r') { - if (src[1] == '1') + if (l1 == '1') { if (src[2] >= '0' && src[2] <= '5' && ! IDENT_CHAR ((unsigned char) src[3])) @@ -282,36 +481,36 @@ parse_reg (src, mode, reg) return 3; } } - if (src[1] >= '0' && src[1] <= '9' + if (l1 >= '0' && l1 <= '9' && ! IDENT_CHAR ((unsigned char) src[2])) { *mode = A_REG_N; - *reg = (src[1] - '0'); + *reg = (l1 - '0'); return 2; } - if (src[1] >= '0' && src[1] <= '7' && strncmp (&src[2], "_bank", 5) == 0 + if (l1 >= '0' && l1 <= '7' && strncasecmp (&src[2], "_bank", 5) == 0 && ! IDENT_CHAR ((unsigned char) src[7])) { *mode = A_REG_B; - *reg = (src[1] - '0'); + *reg = (l1 - '0'); return 7; } - if (src[1] == 'e' && ! IDENT_CHAR ((unsigned char) src[2])) + if (l1 == 'e' && ! IDENT_CHAR ((unsigned char) src[2])) { *mode = A_RE; return 2; } - if (src[1] == 's' && ! IDENT_CHAR ((unsigned char) src[2])) + if (l1 == 's' && ! IDENT_CHAR ((unsigned char) src[2])) { *mode = A_RS; return 2; } } - if (src[0] == 'a') + if (l0 == 'a') { - if (src[1] == '0') + if (l1 == '0') { if (! IDENT_CHAR ((unsigned char) src[2])) { @@ -319,14 +518,14 @@ parse_reg (src, mode, reg) *reg = A_A0_NUM; return 2; } - if (src[2] == 'g' && ! IDENT_CHAR ((unsigned char) src[3])) + if (tolower (src[2]) == 'g' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = DSP_REG_N; *reg = A_A0G_NUM; return 3; } } - if (src[1] == '1') + if (l1 == '1') { if (! IDENT_CHAR ((unsigned char) src[2])) { @@ -334,7 +533,7 @@ parse_reg (src, mode, reg) *reg = A_A1_NUM; return 2; } - if (src[2] == 'g' && ! IDENT_CHAR ((unsigned char) src[3])) + if (tolower (src[2]) == 'g' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = DSP_REG_N; *reg = A_A1G_NUM; @@ -342,24 +541,24 @@ parse_reg (src, mode, reg) } } - if (src[1] == 'x' && src[2] >= '0' && src[2] <= '1' + if (l1 == 'x' && src[2] >= '0' && src[2] <= '1' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = A_REG_N; - *reg = 4 + (src[1] - '0'); + *reg = 4 + (l1 - '0'); return 3; } - if (src[1] == 'y' && src[2] >= '0' && src[2] <= '1' + if (l1 == 'y' && src[2] >= '0' && src[2] <= '1' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = A_REG_N; - *reg = 6 + (src[1] - '0'); + *reg = 6 + (l1 - '0'); return 3; } - if (src[1] == 's' && src[2] >= '0' && src[2] <= '3' + if (l1 == 's' && src[2] >= '0' && src[2] <= '3' && ! IDENT_CHAR ((unsigned char) src[3])) { - int n = src[1] - '0'; + int n = l1 - '0'; *mode = A_REG_N; *reg = n | ((~n & 2) << 1); @@ -367,21 +566,21 @@ parse_reg (src, mode, reg) } } - if (src[0] == 'i' && src[1] && ! IDENT_CHAR ((unsigned char) src[3])) + if (l0 == 'i' && l1 && ! IDENT_CHAR ((unsigned char) src[3])) { - if (src[1] == 's') + if (l1 == 's') { *mode = A_REG_N; *reg = 8; return 2; } - if (src[1] == 'x') + if (l1 == 'x') { *mode = A_REG_N; *reg = 8; return 2; } - if (src[1] == 'y') + if (l1 == 'y') { *mode = A_REG_N; *reg = 9; @@ -389,105 +588,105 @@ parse_reg (src, mode, reg) } } - if (src[0] == 'x' && src[1] >= '0' && src[1] <= '1' + if (l0 == 'x' && l1 >= '0' && l1 <= '1' && ! IDENT_CHAR ((unsigned char) src[2])) { *mode = DSP_REG_N; - *reg = A_X0_NUM + src[1] - '0'; + *reg = A_X0_NUM + l1 - '0'; return 2; } - if (src[0] == 'y' && src[1] >= '0' && src[1] <= '1' + if (l0 == 'y' && l1 >= '0' && l1 <= '1' && ! IDENT_CHAR ((unsigned char) src[2])) { *mode = DSP_REG_N; - *reg = A_Y0_NUM + src[1] - '0'; + *reg = A_Y0_NUM + l1 - '0'; return 2; } - if (src[0] == 'm' && src[1] >= '0' && src[1] <= '1' + if (l0 == 'm' && l1 >= '0' && l1 <= '1' && ! IDENT_CHAR ((unsigned char) src[2])) { *mode = DSP_REG_N; - *reg = src[1] == '0' ? A_M0_NUM : A_M1_NUM; + *reg = l1 == '0' ? A_M0_NUM : A_M1_NUM; return 2; } - if (src[0] == 's' - && src[1] == 's' - && src[2] == 'r' && ! IDENT_CHAR ((unsigned char) src[3])) + if (l0 == 's' + && l1 == 's' + && tolower (src[2]) == 'r' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = A_SSR; return 3; } - if (src[0] == 's' && src[1] == 'p' && src[2] == 'c' + if (l0 == 's' && l1 == 'p' && tolower (src[2]) == 'c' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = A_SPC; return 3; } - if (src[0] == 's' && src[1] == 'g' && src[2] == 'r' + if (l0 == 's' && l1 == 'g' && tolower (src[2]) == 'r' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = A_SGR; return 3; } - if (src[0] == 'd' && src[1] == 's' && src[2] == 'r' + if (l0 == 'd' && l1 == 's' && tolower (src[2]) == 'r' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = A_DSR; return 3; } - if (src[0] == 'd' && src[1] == 'b' && src[2] == 'r' + if (l0 == 'd' && l1 == 'b' && tolower (src[2]) == 'r' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = A_DBR; return 3; } - if (src[0] == 's' && src[1] == 'r' && ! IDENT_CHAR ((unsigned char) src[2])) + if (l0 == 's' && l1 == 'r' && ! IDENT_CHAR ((unsigned char) src[2])) { *mode = A_SR; return 2; } - if (src[0] == 's' && src[1] == 'p' && ! IDENT_CHAR ((unsigned char) src[2])) + if (l0 == 's' && l1 == 'p' && ! IDENT_CHAR ((unsigned char) src[2])) { *mode = A_REG_N; *reg = 15; return 2; } - if (src[0] == 'p' && src[1] == 'r' && ! IDENT_CHAR ((unsigned char) src[2])) + if (l0 == 'p' && l1 == 'r' && ! IDENT_CHAR ((unsigned char) src[2])) { *mode = A_PR; return 2; } - if (src[0] == 'p' && src[1] == 'c' && ! IDENT_CHAR ((unsigned char) src[2])) + if (l0 == 'p' && l1 == 'c' && ! IDENT_CHAR ((unsigned char) src[2])) { /* Don't use A_DISP_PC here - that would accept stuff like 'mova pc,r0' and use an uninitialized immediate. */ *mode = A_PC; return 2; } - if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r' + if (l0 == 'g' && l1 == 'b' && tolower (src[2]) == 'r' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = A_GBR; return 3; } - if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r' + if (l0 == 'v' && l1 == 'b' && tolower (src[2]) == 'r' && ! IDENT_CHAR ((unsigned char) src[3])) { *mode = A_VBR; return 3; } - if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c' + if (l0 == 'm' && l1 == 'a' && tolower (src[2]) == 'c' && ! IDENT_CHAR ((unsigned char) src[4])) { if (src[3] == 'l') @@ -501,13 +700,13 @@ parse_reg (src, mode, reg) return 4; } } - if (src[0] == 'm' && src[1] == 'o' && src[2] == 'd' + if (l0 == 'm' && l1 == 'o' && tolower (src[2]) == 'd' && ! IDENT_CHAR ((unsigned char) src[4])) { *mode = A_MOD; return 3; } - if (src[0] == 'f' && src[1] == 'r') + if (l0 == 'f' && l1 == 'r') { if (src[2] == '1') { @@ -527,7 +726,7 @@ parse_reg (src, mode, reg) return 3; } } - if (src[0] == 'd' && src[1] == 'r') + if (l0 == 'd' && l1 == 'r') { if (src[2] == '1') { @@ -547,7 +746,7 @@ parse_reg (src, mode, reg) return 3; } } - if (src[0] == 'x' && src[1] == 'd') + if (l0 == 'x' && l1 == 'd') { if (src[2] == '1') { @@ -567,7 +766,7 @@ parse_reg (src, mode, reg) return 3; } } - if (src[0] == 'f' && src[1] == 'v') + if (l0 == 'f' && l1 == 'v') { if (src[2] == '1'&& src[3] == '2' && ! IDENT_CHAR ((unsigned char) src[4])) { @@ -583,22 +782,25 @@ parse_reg (src, mode, reg) return 3; } } - if (src[0] == 'f' && src[1] == 'p' && src[2] == 'u' && src[3] == 'l' + if (l0 == 'f' && l1 == 'p' && tolower (src[2]) == 'u' + && tolower (src[3]) == 'l' && ! IDENT_CHAR ((unsigned char) src[4])) { *mode = FPUL_N; return 4; } - if (src[0] == 'f' && src[1] == 'p' && src[2] == 's' && src[3] == 'c' - && src[4] == 'r' && ! IDENT_CHAR ((unsigned char) src[5])) + if (l0 == 'f' && l1 == 'p' && tolower (src[2]) == 's' + && tolower (src[3]) == 'c' + && tolower (src[4]) == 'r' && ! IDENT_CHAR ((unsigned char) src[5])) { *mode = FPSCR_N; return 5; } - if (src[0] == 'x' && src[1] == 'm' && src[2] == 't' && src[3] == 'r' - && src[4] == 'x' && ! IDENT_CHAR ((unsigned char) src[5])) + if (l0 == 'x' && l1 == 'm' && tolower (src[2]) == 't' + && tolower (src[3]) == 'r' + && tolower (src[4]) == 'x' && ! IDENT_CHAR ((unsigned char) src[5])) { *mode = XMTRX_M4; return 5; @@ -1665,7 +1867,7 @@ md_assemble (str) unsigned char *op_end; sh_operand_info operand[3]; sh_opcode_info *opcode; - unsigned int size; + unsigned int size = 0; opcode = find_cooked_opcode (&str); op_end = str; @@ -1732,23 +1934,8 @@ md_assemble (str) } } } - - if (debug_type == DEBUG_DWARF2) - { - bfd_vma addr; - - /* First update the notion of the current source line. */ - dwarf2_where (&debug_line); - - /* We want the offset of the start of this instruction within the - the current frag. may be used later */ - addr = frag_now->fr_address + frag_now_fix () - size; - - - /* And record the information. */ - dwarf2_gen_line_info (addr, &debug_line); - } + dwarf2_emit_insn (size); } /* This routine is called each time a label definition is seen. It @@ -1795,6 +1982,24 @@ symbolS * md_undefined_symbol (name) char *name; { +#ifdef OBJ_ELF + /* Under ELF we need to default _GLOBAL_OFFSET_TABLE. Otherwise we + have no need to default values of symbols. */ + if (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0) + { + if (!GOT_symbol) + { + if (symbol_find (name)) + as_bad ("GOT already in the symbol table"); + + GOT_symbol = symbol_new (name, undefined_section, + (valueT)0, & zero_address_frag); + } + + return GOT_symbol; + } +#endif /* OBJ_ELF */ + return 0; } @@ -2192,58 +2397,19 @@ md_convert_frag (headers, seg, fragP) case C (UNCOND_JUMP, UNCOND32): case C (UNCOND_JUMP, UNDEF_WORD_DISP): if (fragP->fr_symbol == NULL) - as_bad (_("at 0x%lx, displacement overflows 12-bit field"), - (unsigned long) fragP->fr_address); + as_bad_where (fragP->fr_file, fragP->fr_line, + _("displacement overflows 12-bit field")); else if (S_IS_DEFINED (fragP->fr_symbol)) - as_bad (_("at 0x%lx, displacement to defined symbol %s overflows 12-bit field"), - (unsigned long) fragP->fr_address, - S_GET_NAME (fragP->fr_symbol)); + as_bad_where (fragP->fr_file, fragP->fr_line, + _("displacement to defined symbol %s overflows 12-bit field"), + S_GET_NAME (fragP->fr_symbol)); else - as_bad (_("at 0x%lx, displacement to undefined symbol %s overflows 12-bit field"), - (unsigned long) fragP->fr_address, - S_GET_NAME (fragP->fr_symbol)); - -#if 0 - /* This code works, but generates poor code and the compiler - should never produce a sequence that requires it to be used. */ - - /* A jump wont fit in 12 bits, make code which looks like - bra foo - mov.w @(0, PC), r14 - .long disp - foo: bra @r14 - */ - int t = buffer[0] & 0x10; - - buffer[highbyte ] = 0xa0; /* branch over move and disp */ - buffer[lowbyte ] = 3; - buffer[highbyte + 2] = 0xd0 | JREG; /* Build mov insn */ - buffer[lowbyte + 2] = 0x00; - - buffer[highbyte + 4] = 0; /* space for 32 bit jump disp */ - buffer[lowbyte + 4] = 0; - buffer[highbyte + 6] = 0; - buffer[lowbyte + 6] = 0; - - buffer[highbyte + 8] = 0x40 | JREG; /* Build jmp @JREG */ - buffer[lowbyte + 8] = t ? 0xb : 0x2b; - - buffer[highbyte + 10] = 0x20; /* build nop */ - buffer[lowbyte + 10] = 0x0b; - - /* Make reloc for the long disp. */ - fix_new (fragP, - fragP->fr_fix + 4, - 4, - fragP->fr_symbol, - fragP->fr_offset, - 0, - BFD_RELOC_32); - fragP->fr_fix += UNCOND32_LENGTH; + as_bad_where (fragP->fr_file, fragP->fr_line, + _("displacement to undefined symbol %s overflows 12-bit field"), + S_GET_NAME (fragP->fr_symbol)); + /* Stabilize this frag, so we don't trip an assert. */ + fragP->fr_fix += fragP->fr_var; fragP->fr_var = 0; - donerelax = 1; -#endif - break; case C (COND_JUMP, COND12): @@ -2316,59 +2482,19 @@ md_convert_frag (headers, seg, fragP) case C (COND_JUMP, UNDEF_WORD_DISP): case C (COND_JUMP_DELAY, UNDEF_WORD_DISP): if (fragP->fr_symbol == NULL) - as_bad (_("at 0x%lx, displacement overflows 8-bit field"), - (unsigned long) fragP->fr_address); + as_bad_where (fragP->fr_file, fragP->fr_line, + _("displacement overflows 8-bit field")); else if (S_IS_DEFINED (fragP->fr_symbol)) - as_bad (_("at 0x%lx, displacement to defined symbol %s overflows 8-bit field "), - (unsigned long) fragP->fr_address, - S_GET_NAME (fragP->fr_symbol)); + as_bad_where (fragP->fr_file, fragP->fr_line, + _("displacement to defined symbol %s overflows 8-bit field"), + S_GET_NAME (fragP->fr_symbol)); else - as_bad (_("at 0x%lx, displacement to undefined symbol %s overflows 8-bit field "), - (unsigned long) fragP->fr_address, - S_GET_NAME (fragP->fr_symbol)); - -#if 0 - /* This code works, but generates poor code, and the compiler - should never produce a sequence that requires it to be used. */ - - /* A bcond won't fit and it won't go into a 12 bit - displacement either, the code sequence looks like: - b!cond foop - mov.w @(n, PC), r14 - jmp @r14 - nop - .long where - foop: - */ - - buffer[0] ^= 0x2; /* Toggle T/F bit */ -#define JREG 14 - buffer[1] = 5; /* branch over mov, jump, nop and ptr */ - buffer[2] = 0xd0 | JREG; /* Build mov insn */ - buffer[3] = 0x2; - buffer[4] = 0x40 | JREG; /* Build jmp @JREG */ - buffer[5] = 0x0b; - buffer[6] = 0x20; /* build nop */ - buffer[7] = 0x0b; - buffer[8] = 0; /* space for 32 bit jump disp */ - buffer[9] = 0; - buffer[10] = 0; - buffer[11] = 0; - buffer[12] = 0; - buffer[13] = 0; - /* Make reloc for the long disp */ - fix_new (fragP, - fragP->fr_fix + 8, - 4, - fragP->fr_symbol, - fragP->fr_offset, - 0, - BFD_RELOC_32); - fragP->fr_fix += COND32_LENGTH; + as_bad_where (fragP->fr_file, fragP->fr_line, + _("displacement to undefined symbol %s overflows 8-bit field "), + S_GET_NAME (fragP->fr_symbol)); + /* Stabilize this frag, so we don't trip an assert. */ + fragP->fr_fix += fragP->fr_var; fragP->fr_var = 0; - donerelax = 1; -#endif - break; default: @@ -2385,7 +2511,7 @@ md_convert_frag (headers, seg, fragP) valueT md_section_align (seg, size) - segT seg; + segT seg ATTRIBUTE_UNUSED; valueT size; { #ifdef BFD_ASSEMBLER @@ -2456,7 +2582,7 @@ sh_cons_align (nbytes) return; } - p = frag_var (rs_align_code, 1, 1, (relax_substateT) 0, + p = frag_var (rs_align_test, 1, 1, (relax_substateT) 0, (symbolS *) NULL, (offsetT) nalign, (char *) NULL); record_alignment (now_seg, nalign); @@ -2470,17 +2596,47 @@ void sh_handle_align (frag) fragS *frag; { + int bytes = frag->fr_next->fr_address - frag->fr_address - frag->fr_fix; + + if (frag->fr_type == rs_align_code) + { + static const unsigned char big_nop_pattern[] = { 0x00, 0x09 }; + static const unsigned char little_nop_pattern[] = { 0x09, 0x00 }; + + char *p = frag->fr_literal + frag->fr_fix; + + if (bytes & 1) + { + *p++ = 0; + bytes--; + frag->fr_fix += 1; + } + + if (target_big_endian) + { + memcpy (p, big_nop_pattern, sizeof big_nop_pattern); + frag->fr_var = sizeof big_nop_pattern; + } + else + { + memcpy (p, little_nop_pattern, sizeof little_nop_pattern); + frag->fr_var = sizeof little_nop_pattern; + } + } + else if (frag->fr_type == rs_align_test) + { + if (bytes != 0) + as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data")); + } + if (sh_relax - && frag->fr_type == rs_align + && (frag->fr_type == rs_align + || frag->fr_type == rs_align_code) && frag->fr_address + frag->fr_fix > 0 && frag->fr_offset > 1 && now_seg != bss_section) fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0, BFD_RELOC_SH_ALIGN); - - if (frag->fr_type == rs_align_code - && frag->fr_next->fr_address - frag->fr_address - frag->fr_fix != 0) - as_warn_where (frag->fr_file, frag->fr_line, _("misaligned data")); } /* This macro decides whether a particular reloc is an entry in a @@ -2544,6 +2700,20 @@ sh_fix_adjustable (fixP) if (fixP->fx_addsy == NULL) return 1; + if (fixP->fx_r_type == BFD_RELOC_SH_PCDISP8BY2 + || fixP->fx_r_type == BFD_RELOC_SH_PCDISP12BY2 + || fixP->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY2 + || fixP->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY4 + || fixP->fx_r_type == BFD_RELOC_8_PCREL + || fixP->fx_r_type == BFD_RELOC_SH_SWITCH16 + || fixP->fx_r_type == BFD_RELOC_SH_SWITCH32) + return 1; + + if (! TC_RELOC_RTSYM_LOC_FIXUP (fixP) + || fixP->fx_r_type == BFD_RELOC_32_GOTOFF + || fixP->fx_r_type == BFD_RELOC_RVA) + return 0; + /* We need the symbol name for the VTABLE entries */ if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) @@ -2605,11 +2775,49 @@ md_apply_fix (fixP, val) int shift; #ifdef BFD_ASSEMBLER + /* A difference between two symbols, the second of which is in the + current section, is transformed in a PC-relative relocation to + the other symbol. We have to adjust the relocation type here. */ + if (fixP->fx_pcrel) + { + switch (fixP->fx_r_type) + { + default: + break; + + case BFD_RELOC_32: + fixP->fx_r_type = BFD_RELOC_32_PCREL; + break; + + /* Currently, we only support 32-bit PCREL relocations. + We'd need a new reloc type to handle 16_PCREL, and + 8_PCREL is already taken for R_SH_SWITCH8, which + apparently does something completely different than what + we need. FIXME. */ + case BFD_RELOC_16: + bfd_set_error (bfd_error_bad_value); + return false; + + case BFD_RELOC_8: + bfd_set_error (bfd_error_bad_value); + return false; + } + } + /* The function adjust_reloc_syms won't convert a reloc against a weak symbol into a reloc against a section, but bfd_install_relocation will screw up if the symbol is defined, so we have to adjust val here - to avoid the screw up later. */ - if (fixP->fx_addsy != NULL + to avoid the screw up later. + + For ordinary relocs, this does not happen for ELF, since for ELF, + bfd_install_relocation uses the "special function" field of the + howto, and does not execute the code that needs to be undone, as long + as the special function does not return bfd_reloc_continue. + It can happen for GOT- and PLT-type relocs the way they are + described in elf32-sh.c as they use bfd_elf_generic_reloc, but it + doesn't matter here since those relocs don't use VAL; see below. */ + if (OUTPUT_FLAVOR != bfd_target_elf_flavour + && fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy)) val -= S_GET_VALUE (fixP->fx_addsy); #endif @@ -2708,13 +2916,14 @@ md_apply_fix (fixP, val) case BFD_RELOC_SH_PCDISP12BY2: val /= 2; - if (val < -0x800 || val >= 0x7ff) + if (val < -0x800 || val > 0x7ff) as_bad_where (fixP->fx_file, fixP->fx_line, _("pcrel too far")); buf[lowbyte] = val & 0xff; buf[highbyte] |= (val >> 8) & 0xf; break; case BFD_RELOC_32: + case BFD_RELOC_32_PCREL: md_number_to_chars (buf, val, 4); break; @@ -2747,6 +2956,43 @@ md_apply_fix (fixP, val) return; #endif +#ifdef OBJ_ELF + case BFD_RELOC_32_PLT_PCREL: + /* Make the jump instruction point to the address of the operand. At + runtime we merely add the offset to the actual PLT entry. */ + *valp = 0xfffffffc; + break; + + case BFD_RELOC_SH_GOTPC: + /* This is tough to explain. We end up with this one if we have + operands that look like "_GLOBAL_OFFSET_TABLE_+[.-.L284]". + The goal here is to obtain the absolute address of the GOT, + and it is strongly preferable from a performance point of + view to avoid using a runtime relocation for this. There are + cases where you have something like: + + .long _GLOBAL_OFFSET_TABLE_+[.-.L66] + + and here no correction would be required. Internally in the + assembler we treat operands of this form as not being pcrel + since the '.' is explicitly mentioned, and I wonder whether + it would simplify matters to do it this way. Who knows. In + earlier versions of the PIC patches, the pcrel_adjust field + was used to store the correction, but since the expression is + not pcrel, I felt it would be confusing to do it this way. */ + *valp -= 1; + md_number_to_chars (buf, val, 4); + break; + + case BFD_RELOC_32_GOT_PCREL: + *valp = 0; /* Fully resolved at runtime. No addend. */ + md_number_to_chars (buf, 0, 4); + break; + + case BFD_RELOC_32_GOTOFF: + break; +#endif + default: abort (); } @@ -2866,36 +3112,6 @@ tc_coff_sizemachdep (frag) #endif /* OBJ_COFF */ -/* When we align the .text section, insert the correct NOP pattern. */ - -int -sh_do_align (n, fill, len, max) - int n; - const char *fill; - int len ATTRIBUTE_UNUSED; - int max; -{ - if (fill == NULL - && subseg_text_p (now_seg) - && n > 1) - { - static const unsigned char big_nop_pattern[] = { 0x00, 0x09 }; - static const unsigned char little_nop_pattern[] = { 0x09, 0x00 }; - - /* First align to a 2 byte boundary, in case there is an odd - .byte. */ - frag_align (1, 0, 0); - if (target_big_endian) - frag_align_pattern (n, big_nop_pattern, sizeof big_nop_pattern, max); - else - frag_align_pattern (n, little_nop_pattern, sizeof little_nop_pattern, - max); - return 1; - } - - return 0; -} - #ifndef BFD_ASSEMBLER #ifdef OBJ_COFF @@ -3098,6 +3314,8 @@ tc_gen_reloc (section, fixp) } else if (fixp->fx_pcrel) rel->addend = fixp->fx_addnumber; + else if (r_type == BFD_RELOC_32 || r_type == BFD_RELOC_32_GOTOFF) + rel->addend = fixp->fx_addnumber; else rel->addend = 0; @@ -3116,10 +3334,3 @@ tc_gen_reloc (section, fixp) } #endif /* BFD_ASSEMBLER */ - -void -sh_finalize () -{ - if (debug_type == DEBUG_DWARF2) - dwarf2_finish (); -}