133965Sjdp/* GAS interface for targets using CGEN: Cpu tools GENerator. 2218822Sdim Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 3218822Sdim 2006 Free Software Foundation, Inc. 433965Sjdp 5130561Sobrien This file is part of GAS, the GNU Assembler. 633965Sjdp 7130561Sobrien GAS is free software; you can redistribute it and/or modify 8130561Sobrien it under the terms of the GNU General Public License as published by 9130561Sobrien the Free Software Foundation; either version 2, or (at your option) 10130561Sobrien any later version. 1133965Sjdp 12130561Sobrien GAS is distributed in the hope that it will be useful, 13130561Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 14130561Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15130561Sobrien GNU General Public License for more details. 1633965Sjdp 17130561Sobrien You should have received a copy of the GNU General Public License 18130561Sobrien along with GAS; see the file COPYING. If not, write to the Free Software 19218822Sdim Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2033965Sjdp 2138889Sjdp#include <setjmp.h> 22218822Sdim#include "as.h" 2338889Sjdp#include "symcat.h" 2460484Sobrien#include "cgen-desc.h" 2533965Sjdp#include "subsegs.h" 2660484Sobrien#include "cgen.h" 2785815Sobrien#include "dwarf2dbg.h" 2833965Sjdp 29218822Sdim#include "symbols.h" 30218822Sdim#include "struc-symbol.h" 31218822Sdim 32218822Sdim#ifdef OBJ_COMPLEX_RELC 33218822Sdimstatic expressionS * make_right_shifted_expr 34218822Sdim (expressionS *, const int, const int); 35218822Sdim 36218822Sdimstatic unsigned long gas_cgen_encode_addend 37218822Sdim (const unsigned long, const unsigned long, const unsigned long, \ 38218822Sdim const unsigned long, const unsigned long, const unsigned long, \ 39218822Sdim const unsigned long); 40218822Sdim 41218822Sdimstatic char * weak_operand_overflow_check 42218822Sdim (const expressionS *, const CGEN_OPERAND *); 43218822Sdim 44218822Sdimstatic void queue_fixup_recursively 45218822Sdim (const int, const int, expressionS *, \ 46218822Sdim const CGEN_MAYBE_MULTI_IFLD *, const int, const int); 47218822Sdim 48218822Sdimstatic int rightshift = 0; 49218822Sdim#endif 50130561Sobrienstatic void queue_fixup (int, int, expressionS *); 5189857Sobrien 5260484Sobrien/* Opcode table descriptor, must be set by md_begin. */ 5360484Sobrien 5460484SobrienCGEN_CPU_DESC gas_cgen_cpu_desc; 5560484Sobrien 5633965Sjdp/* Callback to insert a register into the symbol table. 5733965Sjdp A target may choose to let GAS parse the registers. 5833965Sjdp ??? Not currently used. */ 5933965Sjdp 6033965Sjdpvoid 6133965Sjdpcgen_asm_record_register (name, number) 6285815Sobrien char *name; 6360484Sobrien int number; 6433965Sjdp{ 6533965Sjdp /* Use symbol_create here instead of symbol_new so we don't try to 6633965Sjdp output registers into the object file's symbol table. */ 6733965Sjdp symbol_table_insert (symbol_create (name, reg_section, 6885815Sobrien number, &zero_address_frag)); 6933965Sjdp} 7033965Sjdp 7133965Sjdp/* We need to keep a list of fixups. We can't simply generate them as 7233965Sjdp we go, because that would require us to first create the frag, and 7333965Sjdp that would screw up references to ``.''. 7433965Sjdp 7533965Sjdp This is used by cpu's with simple operands. It keeps knowledge of what 7633965Sjdp an `expressionS' is and what a `fixup' is out of CGEN which for the time 7733965Sjdp being is preferable. 7833965Sjdp 7933965Sjdp OPINDEX is the index in the operand table. 8033965Sjdp OPINFO is something the caller chooses to help in reloc determination. */ 8133965Sjdp 82130561Sobrienstruct fixup 83130561Sobrien{ 8460484Sobrien int opindex; 8560484Sobrien int opinfo; 8633965Sjdp expressionS exp; 87218822Sdim struct cgen_maybe_multi_ifield * field; 88218822Sdim int msb_field_p; 8933965Sjdp}; 9033965Sjdp 9185815Sobrienstatic struct fixup fixups[GAS_CGEN_MAX_FIXUPS]; 9260484Sobrienstatic int num_fixups; 9333965Sjdp 9433965Sjdp/* Prepare to parse an instruction. 9533965Sjdp ??? May wish to make this static and delete calls in md_assemble. */ 9633965Sjdp 9733965Sjdpvoid 9860484Sobriengas_cgen_init_parse () 9933965Sjdp{ 10033965Sjdp num_fixups = 0; 10133965Sjdp} 10233965Sjdp 10333965Sjdp/* Queue a fixup. */ 10433965Sjdp 10538889Sjdpstatic void 10660484Sobrienqueue_fixup (opindex, opinfo, expP) 10738889Sjdp int opindex; 10885815Sobrien int opinfo; 10938889Sjdp expressionS * expP; 11033965Sjdp{ 11133965Sjdp /* We need to generate a fixup for this expression. */ 11260484Sobrien if (num_fixups >= GAS_CGEN_MAX_FIXUPS) 11360484Sobrien as_fatal (_("too many fixups")); 11485815Sobrien fixups[num_fixups].exp = *expP; 11533965Sjdp fixups[num_fixups].opindex = opindex; 11638889Sjdp fixups[num_fixups].opinfo = opinfo; 11738889Sjdp ++ num_fixups; 11833965Sjdp} 11933965Sjdp 12089857Sobrien/* The following functions allow fixup chains to be stored, retrieved, 12189857Sobrien and swapped. They are a generalization of a pre-existing scheme 12289857Sobrien for storing, restoring and swapping fixup chains that was used by 12389857Sobrien the m32r port. The functionality is essentially the same, only 12489857Sobrien instead of only being able to store a single fixup chain, an entire 12589857Sobrien array of fixup chains can be stored. It is the user's responsibility 12689857Sobrien to keep track of how many fixup chains have been stored and which 12789857Sobrien elements of the array they are in. 12838889Sjdp 129104834Sobrien The algorithms used are the same as in the old scheme. Other than the 130104834Sobrien "array-ness" of the whole thing, the functionality is identical to the 13189857Sobrien old scheme. 13260484Sobrien 13389857Sobrien gas_cgen_initialize_saved_fixups_array(): 13489857Sobrien Sets num_fixups_in_chain to 0 for each element. Call this from 13589857Sobrien md_begin() if you plan to use these functions and you want the 136130561Sobrien fixup count in each element to be set to 0 initially. This is 13789857Sobrien not necessary, but it's included just in case. It performs 13889857Sobrien the same function for each element in the array of fixup chains 13989857Sobrien that gas_init_parse() performs for the current fixups. 14089857Sobrien 14189857Sobrien gas_cgen_save_fixups (element): 14289857Sobrien element - element number of the array you wish to store the fixups 14389857Sobrien to. No mechanism is built in for tracking what element 14489857Sobrien was last stored to. 14589857Sobrien 14689857Sobrien gas_cgen_restore_fixups (element): 14789857Sobrien element - element number of the array you wish to restore the fixups 14889857Sobrien from. 14989857Sobrien 15089857Sobrien gas_cgen_swap_fixups(int element): 15189857Sobrien element - swap the current fixups with those in this element number. 15289857Sobrien*/ 15389857Sobrien 154130561Sobrienstruct saved_fixups 155130561Sobrien{ 15689857Sobrien struct fixup fixup_chain[GAS_CGEN_MAX_FIXUPS]; 15789857Sobrien int num_fixups_in_chain; 15889857Sobrien}; 15989857Sobrien 16089857Sobrienstatic struct saved_fixups stored_fixups[MAX_SAVED_FIXUP_CHAINS]; 16189857Sobrien 16238889Sjdpvoid 16389857Sobriengas_cgen_initialize_saved_fixups_array () 16438889Sjdp{ 16589857Sobrien int i = 0; 16685815Sobrien 16789857Sobrien while (i < MAX_SAVED_FIXUP_CHAINS) 16889857Sobrien stored_fixups[i++].num_fixups_in_chain = 0; 16989857Sobrien} 17038889Sjdp 17189857Sobrienvoid 17289857Sobriengas_cgen_save_fixups (i) 17389857Sobrien int i; 17489857Sobrien{ 17589857Sobrien if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS) 17689857Sobrien { 17789857Sobrien as_fatal ("index into stored_fixups[] out of bounds"); 17889857Sobrien return; 17989857Sobrien } 18089857Sobrien 18189857Sobrien stored_fixups[i].num_fixups_in_chain = num_fixups; 18289857Sobrien memcpy (stored_fixups[i].fixup_chain, fixups, 18389857Sobrien sizeof (fixups[0]) * num_fixups); 18438889Sjdp num_fixups = 0; 18538889Sjdp} 18638889Sjdp 18738889Sjdpvoid 18889857Sobriengas_cgen_restore_fixups (i) 18989857Sobrien int i; 19038889Sjdp{ 19189857Sobrien if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS) 19289857Sobrien { 19389857Sobrien as_fatal ("index into stored_fixups[] out of bounds"); 19489857Sobrien return; 19589857Sobrien } 19685815Sobrien 19789857Sobrien num_fixups = stored_fixups[i].num_fixups_in_chain; 198104834Sobrien memcpy (fixups, stored_fixups[i].fixup_chain, 19989857Sobrien (sizeof (stored_fixups[i].fixup_chain[0])) * num_fixups); 20089857Sobrien stored_fixups[i].num_fixups_in_chain = 0; 20138889Sjdp} 20238889Sjdp 20338889Sjdpvoid 20489857Sobriengas_cgen_swap_fixups (i) 20589857Sobrien int i; 20638889Sjdp{ 20789857Sobrien if (i < 0 || i >= MAX_SAVED_FIXUP_CHAINS) 20889857Sobrien { 20989857Sobrien as_fatal ("index into stored_fixups[] out of bounds"); 21089857Sobrien return; 21189857Sobrien } 21238889Sjdp 21338889Sjdp if (num_fixups == 0) 21489857Sobrien gas_cgen_restore_fixups (i); 21589857Sobrien 21689857Sobrien else if (stored_fixups[i].num_fixups_in_chain == 0) 21789857Sobrien gas_cgen_save_fixups (i); 21889857Sobrien 21938889Sjdp else 22038889Sjdp { 22189857Sobrien int tmp; 22289857Sobrien struct fixup tmp_fixup; 22389857Sobrien 22489857Sobrien tmp = stored_fixups[i].num_fixups_in_chain; 22589857Sobrien stored_fixups[i].num_fixups_in_chain = num_fixups; 22638889Sjdp num_fixups = tmp; 22785815Sobrien 22860484Sobrien for (tmp = GAS_CGEN_MAX_FIXUPS; tmp--;) 22938889Sjdp { 23089857Sobrien tmp_fixup = stored_fixups[i].fixup_chain [tmp]; 23189857Sobrien stored_fixups[i].fixup_chain[tmp] = fixups [tmp]; 23289857Sobrien fixups [tmp] = tmp_fixup; 23338889Sjdp } 23438889Sjdp } 23538889Sjdp} 23638889Sjdp 23733965Sjdp/* Default routine to record a fixup. 23833965Sjdp This is a cover function to fix_new. 23933965Sjdp It exists because we record INSN with the fixup. 24033965Sjdp 24133965Sjdp FRAG and WHERE are their respective arguments to fix_new_exp. 24233965Sjdp LENGTH is in bits. 24333965Sjdp OPINFO is something the caller chooses to help in reloc determination. 24433965Sjdp 24533965Sjdp At this point we do not use a bfd_reloc_code_real_type for 24633965Sjdp operands residing in the insn, but instead just use the 24733965Sjdp operand index. This lets us easily handle fixups for any 248218822Sdim operand type. We pick a BFD reloc type in md_apply_fix. */ 24933965Sjdp 25033965SjdpfixS * 25160484Sobriengas_cgen_record_fixup (frag, where, insn, length, operand, opinfo, symbol, offset) 25238889Sjdp fragS * frag; 25338889Sjdp int where; 25438889Sjdp const CGEN_INSN * insn; 25538889Sjdp int length; 25638889Sjdp const CGEN_OPERAND * operand; 25738889Sjdp int opinfo; 25838889Sjdp symbolS * symbol; 25938889Sjdp offsetT offset; 26033965Sjdp{ 26185815Sobrien fixS *fixP; 26233965Sjdp 26333965Sjdp /* It may seem strange to use operand->attrs and not insn->attrs here, 26433965Sjdp but it is the operand that has a pc relative relocation. */ 26533965Sjdp fixP = fix_new (frag, where, length / 8, symbol, offset, 26660484Sobrien CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR), 26760484Sobrien (bfd_reloc_code_real_type) 26860484Sobrien ((int) BFD_RELOC_UNUSED 26960484Sobrien + (int) operand->type)); 27060484Sobrien fixP->fx_cgen.insn = insn; 27160484Sobrien fixP->fx_cgen.opinfo = opinfo; 272218822Sdim fixP->fx_cgen.field = NULL; 273218822Sdim fixP->fx_cgen.msb_field_p = 0; 27433965Sjdp 27533965Sjdp return fixP; 27633965Sjdp} 27733965Sjdp 27833965Sjdp/* Default routine to record a fixup given an expression. 27933965Sjdp This is a cover function to fix_new_exp. 28033965Sjdp It exists because we record INSN with the fixup. 28133965Sjdp 28233965Sjdp FRAG and WHERE are their respective arguments to fix_new_exp. 28333965Sjdp LENGTH is in bits. 28433965Sjdp OPINFO is something the caller chooses to help in reloc determination. 28533965Sjdp 28633965Sjdp At this point we do not use a bfd_reloc_code_real_type for 28733965Sjdp operands residing in the insn, but instead just use the 28833965Sjdp operand index. This lets us easily handle fixups for any 289218822Sdim operand type. We pick a BFD reloc type in md_apply_fix. */ 29033965Sjdp 29133965SjdpfixS * 29260484Sobriengas_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) 29338889Sjdp fragS * frag; 29438889Sjdp int where; 29538889Sjdp const CGEN_INSN * insn; 29638889Sjdp int length; 29738889Sjdp const CGEN_OPERAND * operand; 29838889Sjdp int opinfo; 29938889Sjdp expressionS * exp; 30033965Sjdp{ 30185815Sobrien fixS *fixP; 30233965Sjdp 30333965Sjdp /* It may seem strange to use operand->attrs and not insn->attrs here, 30433965Sjdp but it is the operand that has a pc relative relocation. */ 30533965Sjdp fixP = fix_new_exp (frag, where, length / 8, exp, 30660484Sobrien CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR), 30760484Sobrien (bfd_reloc_code_real_type) 30860484Sobrien ((int) BFD_RELOC_UNUSED 30960484Sobrien + (int) operand->type)); 31060484Sobrien fixP->fx_cgen.insn = insn; 31160484Sobrien fixP->fx_cgen.opinfo = opinfo; 312218822Sdim fixP->fx_cgen.field = NULL; 313218822Sdim fixP->fx_cgen.msb_field_p = 0; 31433965Sjdp 31533965Sjdp return fixP; 31633965Sjdp} 31733965Sjdp 318218822Sdim#ifdef OBJ_COMPLEX_RELC 319218822Sdimstatic symbolS * 320218822Sdimexpr_build_binary (operatorT op, symbolS * s1, symbolS * s2) 321218822Sdim{ 322218822Sdim expressionS e; 323218822Sdim 324218822Sdim e.X_op = op; 325218822Sdim e.X_add_symbol = s1; 326218822Sdim e.X_op_symbol = s2; 327218822Sdim e.X_add_number = 0; 328218822Sdim return make_expr_symbol (& e); 329218822Sdim} 330218822Sdim#endif 331218822Sdim 33238889Sjdp/* Used for communication between the next two procedures. */ 33338889Sjdpstatic jmp_buf expr_jmp_buf; 33485815Sobrienstatic int expr_jmp_buf_p; 33538889Sjdp 33633965Sjdp/* Callback for cgen interface. Parse the expression at *STRP. 33733965Sjdp The result is an error message or NULL for success (in which case 33833965Sjdp *STRP is advanced past the parsed text). 33933965Sjdp WANT is an indication of what the caller is looking for. 34033965Sjdp If WANT == CGEN_ASM_PARSE_INIT the caller is beginning to try to match 34133965Sjdp a table entry with the insn, reset the queued fixups counter. 34233965Sjdp An enum cgen_parse_operand_result is stored in RESULTP. 34333965Sjdp OPINDEX is the operand's table entry index. 34433965Sjdp OPINFO is something the caller chooses to help in reloc determination. 34533965Sjdp The resulting value is stored in VALUEP. */ 34633965Sjdp 34733965Sjdpconst char * 34860484Sobriengas_cgen_parse_operand (cd, want, strP, opindex, opinfo, resultP, valueP) 349218822Sdim 350218822Sdim#ifdef OBJ_COMPLEX_RELC 351218822Sdim CGEN_CPU_DESC cd; 352218822Sdim#else 35385815Sobrien CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; 354218822Sdim#endif 35560484Sobrien enum cgen_parse_operand_type want; 35685815Sobrien const char **strP; 35760484Sobrien int opindex; 35860484Sobrien int opinfo; 35985815Sobrien enum cgen_parse_operand_result *resultP; 36085815Sobrien bfd_vma *valueP; 36133965Sjdp{ 36238889Sjdp#ifdef __STDC__ 36360484Sobrien /* These are volatile to survive the setjmp. */ 36460484Sobrien char * volatile hold; 36538889Sjdp enum cgen_parse_operand_result * volatile resultP_1; 366218822Sdim volatile int opinfo_1; 36738889Sjdp#else 36885815Sobrien static char *hold; 36985815Sobrien static enum cgen_parse_operand_result *resultP_1; 370218822Sdim int opinfo_1; 37138889Sjdp#endif 37289857Sobrien const char *errmsg; 37360484Sobrien expressionS exp; 37433965Sjdp 375218822Sdim#ifdef OBJ_COMPLEX_RELC 376218822Sdim volatile int signed_p = 0; 377218822Sdim symbolS * stmp = NULL; 378218822Sdim bfd_reloc_code_real_type reloc_type; 379218822Sdim const CGEN_OPERAND * operand; 380218822Sdim fixS dummy_fixup; 381218822Sdim#endif 38233965Sjdp if (want == CGEN_PARSE_OPERAND_INIT) 38333965Sjdp { 38460484Sobrien gas_cgen_init_parse (); 38533965Sjdp return NULL; 38633965Sjdp } 38733965Sjdp 38838889Sjdp resultP_1 = resultP; 38933965Sjdp hold = input_line_pointer; 39085815Sobrien input_line_pointer = (char *) *strP; 391218822Sdim opinfo_1 = opinfo; 39238889Sjdp 39338889Sjdp /* We rely on md_operand to longjmp back to us. 39460484Sobrien This is done via gas_cgen_md_operand. */ 39538889Sjdp if (setjmp (expr_jmp_buf) != 0) 39638889Sjdp { 39785815Sobrien expr_jmp_buf_p = 0; 39838889Sjdp input_line_pointer = (char *) hold; 39985815Sobrien *resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR; 40089857Sobrien return _("illegal operand"); 40138889Sjdp } 40238889Sjdp 40385815Sobrien expr_jmp_buf_p = 1; 40485815Sobrien expression (&exp); 40585815Sobrien expr_jmp_buf_p = 0; 40689857Sobrien errmsg = NULL; 40738889Sjdp 40885815Sobrien *strP = input_line_pointer; 40933965Sjdp input_line_pointer = hold; 41033965Sjdp 411218822Sdim#ifdef TC_CGEN_PARSE_FIX_EXP 412218822Sdim opinfo_1 = TC_CGEN_PARSE_FIX_EXP (opinfo_1, & exp); 413218822Sdim#endif 414218822Sdim 41533965Sjdp /* FIXME: Need to check `want'. */ 41633965Sjdp 41733965Sjdp switch (exp.X_op) 41833965Sjdp { 41985815Sobrien case O_illegal: 42060484Sobrien errmsg = _("illegal operand"); 42185815Sobrien *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; 42233965Sjdp break; 42385815Sobrien case O_absent: 42460484Sobrien errmsg = _("missing operand"); 42585815Sobrien *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; 42633965Sjdp break; 42785815Sobrien case O_constant: 428218822Sdim if (want == CGEN_PARSE_OPERAND_SYMBOLIC) 429218822Sdim goto de_fault; 43085815Sobrien *valueP = exp.X_add_number; 43185815Sobrien *resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER; 43233965Sjdp break; 43385815Sobrien case O_register: 43485815Sobrien *valueP = exp.X_add_number; 43585815Sobrien *resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER; 43633965Sjdp break; 437218822Sdim de_fault: 43885815Sobrien default: 439218822Sdim#ifdef OBJ_COMPLEX_RELC 440218822Sdim /* Look up operand, check to see if there's an obvious 441218822Sdim overflow (this helps disambiguate some insn parses). */ 442218822Sdim operand = cgen_operand_lookup_by_num (cd, opindex); 443218822Sdim errmsg = weak_operand_overflow_check (& exp, operand); 444218822Sdim 445218822Sdim if (! errmsg) 446218822Sdim { 447218822Sdim /* Fragment the expression as necessary, and queue a reloc. */ 448218822Sdim memset (& dummy_fixup, 0, sizeof (fixS)); 449218822Sdim 450218822Sdim reloc_type = md_cgen_lookup_reloc (0, operand, & dummy_fixup); 451218822Sdim 452218822Sdim if (exp.X_op == O_symbol 453218822Sdim && reloc_type == BFD_RELOC_RELC 454218822Sdim && exp.X_add_symbol->sy_value.X_op == O_constant 455218822Sdim && exp.X_add_symbol->bsym->section != expr_section 456218822Sdim && exp.X_add_symbol->bsym->section != absolute_section 457218822Sdim && exp.X_add_symbol->bsym->section != undefined_section) 458218822Sdim { 459218822Sdim /* Local labels will have been (eagerly) turned into constants 460218822Sdim by now, due to the inappropriately deep insight of the 461218822Sdim expression parser. Unfortunately make_expr_symbol 462218822Sdim prematurely dives into the symbol evaluator, and in this 463218822Sdim case it gets a bad answer, so we manually create the 464218822Sdim expression symbol we want here. */ 465218822Sdim stmp = symbol_create (FAKE_LABEL_NAME, expr_section, 0, 466218822Sdim & zero_address_frag); 467218822Sdim symbol_set_value_expression (stmp, & exp); 468218822Sdim } 469218822Sdim else 470218822Sdim stmp = make_expr_symbol (& exp); 471218822Sdim 472218822Sdim /* If this is a pc-relative RELC operand, we 473218822Sdim need to subtract "." from the expression. */ 474218822Sdim if (reloc_type == BFD_RELOC_RELC 475218822Sdim && CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR)) 476218822Sdim stmp = expr_build_binary (O_subtract, stmp, expr_build_dot ()); 477218822Sdim 478218822Sdim /* FIXME: this is not a perfect heuristic for figuring out 479218822Sdim whether an operand is signed: it only works when the operand 480218822Sdim is an immediate. it's not terribly likely that any other 481218822Sdim values will be signed relocs, but it's possible. */ 482218822Sdim if (operand && (operand->hw_type == HW_H_SINT)) 483218822Sdim signed_p = 1; 484218822Sdim 485218822Sdim if (stmp->bsym && (stmp->bsym->section == expr_section)) 486218822Sdim { 487218822Sdim if (signed_p) 488218822Sdim stmp->bsym->flags |= BSF_SRELC; 489218822Sdim else 490218822Sdim stmp->bsym->flags |= BSF_RELC; 491218822Sdim } 492218822Sdim 493218822Sdim /* Now package it all up for the fixup emitter. */ 494218822Sdim exp.X_op = O_symbol; 495218822Sdim exp.X_op_symbol = 0; 496218822Sdim exp.X_add_symbol = stmp; 497218822Sdim exp.X_add_number = 0; 498218822Sdim 499218822Sdim /* Re-init rightshift quantity, just in case. */ 500218822Sdim rightshift = operand->length; 501218822Sdim queue_fixup_recursively (opindex, opinfo_1, & exp, 502218822Sdim (reloc_type == BFD_RELOC_RELC) ? 503218822Sdim & (operand->index_fields) : 0, 504218822Sdim signed_p, -1); 505218822Sdim } 506218822Sdim * resultP = errmsg 507218822Sdim ? CGEN_PARSE_OPERAND_RESULT_ERROR 508218822Sdim : CGEN_PARSE_OPERAND_RESULT_QUEUED; 50985815Sobrien *valueP = 0; 510218822Sdim#else 511218822Sdim queue_fixup (opindex, opinfo_1, &exp); 512218822Sdim *valueP = 0; 51385815Sobrien *resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED; 514218822Sdim#endif 51533965Sjdp break; 51633965Sjdp } 51733965Sjdp 51833965Sjdp return errmsg; 51933965Sjdp} 52033965Sjdp 52138889Sjdp/* md_operand handler to catch unrecognized expressions and halt the 52238889Sjdp parsing process so the next entry can be tried. 52338889Sjdp 52438889Sjdp ??? This could be done differently by adding code to `expression'. */ 52538889Sjdp 52638889Sjdpvoid 52760484Sobriengas_cgen_md_operand (expressionP) 52885815Sobrien expressionS *expressionP ATTRIBUTE_UNUSED; 52938889Sjdp{ 53085815Sobrien /* Don't longjmp if we're not called from within cgen_parse_operand(). */ 53185815Sobrien if (expr_jmp_buf_p) 53285815Sobrien longjmp (expr_jmp_buf, 1); 53338889Sjdp} 53438889Sjdp 53533965Sjdp/* Finish assembling instruction INSN. 53633965Sjdp BUF contains what we've built up so far. 53738889Sjdp LENGTH is the size of the insn in bits. 53860484Sobrien RELAX_P is non-zero if relaxable insns should be emitted as such. 53960484Sobrien Otherwise they're emitted in non-relaxable forms. 54060484Sobrien The "result" is stored in RESULT if non-NULL. */ 54133965Sjdp 54260484Sobrienvoid 54360484Sobriengas_cgen_finish_insn (insn, buf, length, relax_p, result) 54485815Sobrien const CGEN_INSN *insn; 54560484Sobrien CGEN_INSN_BYTES_PTR buf; 54660484Sobrien unsigned int length; 54760484Sobrien int relax_p; 54885815Sobrien finished_insnS *result; 54933965Sjdp{ 55060484Sobrien int i; 55160484Sobrien int relax_operand; 55285815Sobrien char *f; 55333965Sjdp unsigned int byte_len = length / 8; 55433965Sjdp 55533965Sjdp /* ??? Target foo issues various warnings here, so one might want to provide 55633965Sjdp a hook here. However, our caller is defined in tc-foo.c so there 55733965Sjdp shouldn't be a need for a hook. */ 55860484Sobrien 55933965Sjdp /* Write out the instruction. 56033965Sjdp It is important to fetch enough space in one call to `frag_more'. 56133965Sjdp We use (f - frag_now->fr_literal) to compute where we are and we 56233965Sjdp don't want frag_now to change between calls. 56333965Sjdp 56433965Sjdp Relaxable instructions: We need to ensure we allocate enough 56533965Sjdp space for the largest insn. */ 56633965Sjdp 567130561Sobrien if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED)) 56885815Sobrien /* These currently shouldn't get here. */ 56985815Sobrien abort (); 57033965Sjdp 57133965Sjdp /* Is there a relaxable insn with the relaxable operand needing a fixup? */ 57233965Sjdp 57333965Sjdp relax_operand = -1; 57460484Sobrien if (relax_p && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXABLE)) 57533965Sjdp { 57633965Sjdp /* Scan the fixups for the operand affected by relaxing 57733965Sjdp (i.e. the branch address). */ 57833965Sjdp 57985815Sobrien for (i = 0; i < num_fixups; ++i) 58033965Sjdp { 58160484Sobrien if (CGEN_OPERAND_ATTR_VALUE (cgen_operand_lookup_by_num (gas_cgen_cpu_desc, fixups[i].opindex), 58260484Sobrien CGEN_OPERAND_RELAX)) 58333965Sjdp { 58433965Sjdp relax_operand = i; 58533965Sjdp break; 58633965Sjdp } 58733965Sjdp } 58833965Sjdp } 58933965Sjdp 59033965Sjdp if (relax_operand != -1) 59133965Sjdp { 59260484Sobrien int max_len; 59385815Sobrien fragS *old_frag; 59485815Sobrien expressionS *exp; 59585815Sobrien symbolS *sym; 59685815Sobrien offsetT off; 59733965Sjdp 59833965Sjdp#ifdef TC_CGEN_MAX_RELAX 59933965Sjdp max_len = TC_CGEN_MAX_RELAX (insn, byte_len); 60033965Sjdp#else 60133965Sjdp max_len = CGEN_MAX_INSN_SIZE; 60233965Sjdp#endif 60333965Sjdp /* Ensure variable part and fixed part are in same fragment. */ 60433965Sjdp /* FIXME: Having to do this seems like a hack. */ 60533965Sjdp frag_grow (max_len); 60660484Sobrien 60733965Sjdp /* Allocate space for the fixed part. */ 60833965Sjdp f = frag_more (byte_len); 60960484Sobrien 61033965Sjdp /* Create a relaxable fragment for this instruction. */ 61133965Sjdp old_frag = frag_now; 61238889Sjdp 61385815Sobrien exp = &fixups[relax_operand].exp; 61485815Sobrien sym = exp->X_add_symbol; 61585815Sobrien off = exp->X_add_number; 61685815Sobrien if (exp->X_op != O_constant && exp->X_op != O_symbol) 61785815Sobrien { 61885815Sobrien /* Handle complex expressions. */ 61985815Sobrien sym = make_expr_symbol (exp); 62085815Sobrien off = 0; 62185815Sobrien } 62285815Sobrien 62333965Sjdp frag_var (rs_machine_dependent, 62433965Sjdp max_len - byte_len /* max chars */, 62533965Sjdp 0 /* variable part already allocated */, 62633965Sjdp /* FIXME: When we machine generate the relax table, 62733965Sjdp machine generate a macro to compute subtype. */ 62833965Sjdp 1 /* subtype */, 62985815Sobrien sym, 63085815Sobrien off, 63133965Sjdp f); 63260484Sobrien 63333965Sjdp /* Record the operand number with the fragment so md_convert_frag 63460484Sobrien can use gas_cgen_md_record_fixup to record the appropriate reloc. */ 63538889Sjdp old_frag->fr_cgen.insn = insn; 63638889Sjdp old_frag->fr_cgen.opindex = fixups[relax_operand].opindex; 63738889Sjdp old_frag->fr_cgen.opinfo = fixups[relax_operand].opinfo; 63860484Sobrien if (result) 63960484Sobrien result->frag = old_frag; 64033965Sjdp } 64133965Sjdp else 64260484Sobrien { 64360484Sobrien f = frag_more (byte_len); 64460484Sobrien if (result) 64560484Sobrien result->frag = frag_now; 64660484Sobrien } 64733965Sjdp 64833965Sjdp /* If we're recording insns as numbers (rather than a string of bytes), 64933965Sjdp target byte order handling is deferred until now. */ 65060484Sobrien#if CGEN_INT_INSN_P 651218822Sdim cgen_put_insn_value (gas_cgen_cpu_desc, (unsigned char *) f, length, *buf); 65233965Sjdp#else 65333965Sjdp memcpy (f, buf, byte_len); 65433965Sjdp#endif 65533965Sjdp 65685815Sobrien /* Emit DWARF2 debugging information. */ 65785815Sobrien dwarf2_emit_insn (byte_len); 65885815Sobrien 65933965Sjdp /* Create any fixups. */ 66033965Sjdp for (i = 0; i < num_fixups; ++i) 66133965Sjdp { 66260484Sobrien fixS *fixP; 66360484Sobrien const CGEN_OPERAND *operand = 66460484Sobrien cgen_operand_lookup_by_num (gas_cgen_cpu_desc, fixups[i].opindex); 66560484Sobrien 66633965Sjdp /* Don't create fixups for these. That's done during relaxation. 667130561Sobrien We don't need to test for CGEN_INSN_RELAXED as they can't get here 66833965Sjdp (see above). */ 66960484Sobrien if (relax_p 67060484Sobrien && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXABLE) 67160484Sobrien && CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_RELAX)) 67233965Sjdp continue; 67333965Sjdp 67433965Sjdp#ifndef md_cgen_record_fixup_exp 67560484Sobrien#define md_cgen_record_fixup_exp gas_cgen_record_fixup_exp 67633965Sjdp#endif 67733965Sjdp 67885815Sobrien fixP = md_cgen_record_fixup_exp (frag_now, f - frag_now->fr_literal, 67985815Sobrien insn, length, operand, 68085815Sobrien fixups[i].opinfo, 68185815Sobrien &fixups[i].exp); 682218822Sdim fixP->fx_cgen.field = fixups[i].field; 683218822Sdim fixP->fx_cgen.msb_field_p = fixups[i].msb_field_p; 68485815Sobrien if (result) 68585815Sobrien result->fixups[i] = fixP; 68633965Sjdp } 68738889Sjdp 68860484Sobrien if (result) 68960484Sobrien { 69060484Sobrien result->num_fixups = num_fixups; 69160484Sobrien result->addr = f; 69260484Sobrien } 69333965Sjdp} 69433965Sjdp 695218822Sdim#ifdef OBJ_COMPLEX_RELC 696218822Sdim/* Queue many fixups, recursively. If the field is a multi-ifield, 697218822Sdim repeatedly queue its sub-parts, right shifted to fit into the field (we 698218822Sdim assume here multi-fields represent a left-to-right, MSB0-LSB0 699218822Sdim reading). */ 700218822Sdim 701218822Sdimstatic void 702218822Sdimqueue_fixup_recursively (const int opindex, 703218822Sdim const int opinfo, 704218822Sdim expressionS * expP, 705218822Sdim const CGEN_MAYBE_MULTI_IFLD * field, 706218822Sdim const int signed_p, 707218822Sdim const int part_of_multi) 708218822Sdim{ 709218822Sdim if (field && field->count) 710218822Sdim { 711218822Sdim int i; 712218822Sdim 713218822Sdim for (i = 0; i < field->count; ++ i) 714218822Sdim queue_fixup_recursively (opindex, opinfo, expP, 715218822Sdim & (field->val.multi[i]), signed_p, i); 716218822Sdim } 717218822Sdim else 718218822Sdim { 719218822Sdim expressionS * new_exp = expP; 720218822Sdim 721218822Sdim#ifdef DEBUG 722218822Sdim printf ("queueing fixup for field %s\n", 723218822Sdim (field ? field->val.leaf->name : "??")); 724218822Sdim print_symbol_value (expP->X_add_symbol); 725218822Sdim#endif 726218822Sdim if (field && part_of_multi != -1) 727218822Sdim { 728218822Sdim rightshift -= field->val.leaf->length; 729218822Sdim 730218822Sdim /* Shift reloc value by number of bits remaining after this 731218822Sdim field. */ 732218822Sdim if (rightshift) 733218822Sdim new_exp = make_right_shifted_expr (expP, rightshift, signed_p); 734218822Sdim } 735218822Sdim 736218822Sdim /* Truncate reloc values to length, *after* leftmost one. */ 737218822Sdim fixups[num_fixups].msb_field_p = (part_of_multi <= 0); 738218822Sdim fixups[num_fixups].field = (CGEN_MAYBE_MULTI_IFLD *) field; 739218822Sdim 740218822Sdim queue_fixup (opindex, opinfo, new_exp); 741218822Sdim } 742218822Sdim} 743218822Sdim 744218822Sdim/* Encode the self-describing RELC reloc format's addend. */ 745218822Sdim 746218822Sdimstatic unsigned long 747218822Sdimgas_cgen_encode_addend (const unsigned long start, /* in bits */ 748218822Sdim const unsigned long len, /* in bits */ 749218822Sdim const unsigned long oplen, /* in bits */ 750218822Sdim const unsigned long wordsz, /* in bytes */ 751218822Sdim const unsigned long chunksz, /* in bytes */ 752218822Sdim const unsigned long signed_p, 753218822Sdim const unsigned long trunc_p) 754218822Sdim{ 755218822Sdim unsigned long res = 0L; 756218822Sdim 757218822Sdim res |= start & 0x3F; 758218822Sdim res |= (oplen & 0x3F) << 6; 759218822Sdim res |= (len & 0x3F) << 12; 760218822Sdim res |= (wordsz & 0xF) << 18; 761218822Sdim res |= (chunksz & 0xF) << 22; 762218822Sdim res |= (CGEN_INSN_LSB0_P ? 1 : 0) << 27; 763218822Sdim res |= signed_p << 28; 764218822Sdim res |= trunc_p << 29; 765218822Sdim 766218822Sdim return res; 767218822Sdim} 768218822Sdim 769218822Sdim/* Purpose: make a weak check that the expression doesn't overflow the 770218822Sdim operand it's to be inserted into. 771218822Sdim 772218822Sdim Rationale: some insns used to use %operators to disambiguate during a 773218822Sdim parse. when these %operators are translated to expressions by the macro 774218822Sdim expander, the ambiguity returns. we attempt to disambiguate by field 775218822Sdim size. 776218822Sdim 777218822Sdim Method: check to see if the expression's top node is an O_and operator, 778218822Sdim and the mask is larger than the operand length. This would be an 779218822Sdim overflow, so signal it by returning an error string. Any other case is 780218822Sdim ambiguous, so we assume it's OK and return NULL. */ 781218822Sdim 782218822Sdimstatic char * 783218822Sdimweak_operand_overflow_check (const expressionS * exp, 784218822Sdim const CGEN_OPERAND * operand) 785218822Sdim{ 786218822Sdim const unsigned long len = operand->length; 787218822Sdim unsigned long mask; 788218822Sdim unsigned long opmask = (((1L << (len - 1)) - 1) << 1) | 1; 789218822Sdim 790218822Sdim if (!exp) 791218822Sdim return NULL; 792218822Sdim 793218822Sdim if (exp->X_op != O_bit_and) 794218822Sdim { 795218822Sdim /* Check for implicit overflow flag. */ 796218822Sdim if (CGEN_OPERAND_ATTR_VALUE 797218822Sdim (operand, CGEN_OPERAND_RELOC_IMPLIES_OVERFLOW)) 798218822Sdim return _("a reloc on this operand implies an overflow"); 799218822Sdim return NULL; 800218822Sdim } 801218822Sdim 802218822Sdim mask = exp->X_add_number; 803218822Sdim 804218822Sdim if (exp->X_add_symbol && 805218822Sdim exp->X_add_symbol->sy_value.X_op == O_constant) 806218822Sdim mask |= exp->X_add_symbol->sy_value.X_add_number; 807218822Sdim 808218822Sdim if (exp->X_op_symbol && 809218822Sdim exp->X_op_symbol->sy_value.X_op == O_constant) 810218822Sdim mask |= exp->X_op_symbol->sy_value.X_add_number; 811218822Sdim 812218822Sdim /* Want to know if mask covers more bits than opmask. 813218822Sdim this is the same as asking if mask has any bits not in opmask, 814218822Sdim or whether (mask & ~opmask) is nonzero. */ 815218822Sdim if (mask && (mask & ~opmask)) 816218822Sdim { 817218822Sdim#ifdef DEBUG 818218822Sdim printf ("overflow: (mask = %8.8x, ~opmask = %8.8x, AND = %8.8x)\n", 819218822Sdim mask, ~opmask, (mask & ~opmask)); 820218822Sdim#endif 821218822Sdim return _("operand mask overflow"); 822218822Sdim } 823218822Sdim 824218822Sdim return NULL; 825218822Sdim} 826218822Sdim 827218822Sdim 828218822Sdimstatic expressionS * 829218822Sdimmake_right_shifted_expr (expressionS * exp, 830218822Sdim const int amount, 831218822Sdim const int signed_p) 832218822Sdim{ 833218822Sdim symbolS * stmp = 0; 834218822Sdim expressionS * new_exp; 835218822Sdim 836218822Sdim stmp = expr_build_binary (O_right_shift, 837218822Sdim make_expr_symbol (exp), 838218822Sdim expr_build_uconstant (amount)); 839218822Sdim 840218822Sdim if (signed_p) 841218822Sdim stmp->bsym->flags |= BSF_SRELC; 842218822Sdim else 843218822Sdim stmp->bsym->flags |= BSF_RELC; 844218822Sdim 845218822Sdim /* Then wrap that in a "symbol expr" for good measure. */ 846218822Sdim new_exp = xmalloc (sizeof (expressionS)); 847218822Sdim memset (new_exp, 0, sizeof (expressionS)); 848218822Sdim new_exp->X_op = O_symbol; 849218822Sdim new_exp->X_op_symbol = 0; 850218822Sdim new_exp->X_add_symbol = stmp; 851218822Sdim new_exp->X_add_number = 0; 852218822Sdim 853218822Sdim return new_exp; 854218822Sdim} 855218822Sdim#endif 85633965Sjdp/* Apply a fixup to the object code. This is called for all the 85733965Sjdp fixups we generated by the call to fix_new_exp, above. In the call 85833965Sjdp above we used a reloc code which was the largest legal reloc code 85933965Sjdp plus the operand index. Here we undo that to recover the operand 86033965Sjdp index. At this point all symbol values should be fully resolved, 86133965Sjdp and we attempt to completely resolve the reloc. If we can not do 86233965Sjdp that, we determine the correct reloc code and put it back in the fixup. */ 86333965Sjdp 86433965Sjdp/* FIXME: This function handles some of the fixups and bfd_install_relocation 86533965Sjdp handles the rest. bfd_install_relocation (or some other bfd function) 86633965Sjdp should handle them all. */ 86733965Sjdp 86889857Sobrienvoid 869218822Sdimgas_cgen_md_apply_fix (fixP, valP, seg) 87038889Sjdp fixS * fixP; 87189857Sobrien valueT * valP; 87285815Sobrien segT seg ATTRIBUTE_UNUSED; 87333965Sjdp{ 87485815Sobrien char *where = fixP->fx_frag->fr_literal + fixP->fx_where; 87589857Sobrien valueT value = * valP; 87685815Sobrien /* Canonical name, since used a lot. */ 87760484Sobrien CGEN_CPU_DESC cd = gas_cgen_cpu_desc; 87885815Sobrien 87933965Sjdp if (fixP->fx_addsy == (symbolS *) NULL) 88089857Sobrien fixP->fx_done = 1; 88189857Sobrien 882130561Sobrien /* We don't actually support subtracting a symbol. */ 883130561Sobrien if (fixP->fx_subsy != (symbolS *) NULL) 884130561Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); 88589857Sobrien 88633965Sjdp if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) 88733965Sjdp { 88860484Sobrien int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; 88960484Sobrien const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex); 89060484Sobrien const char *errmsg; 89133965Sjdp bfd_reloc_code_real_type reloc_type; 89260484Sobrien CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd)); 89360484Sobrien const CGEN_INSN *insn = fixP->fx_cgen.insn; 894218822Sdim int start; 895218822Sdim int length; 896218822Sdim int signed_p = 0; 89733965Sjdp 898218822Sdim if (fixP->fx_cgen.field) 899218822Sdim { 900218822Sdim /* Use the twisty little pointer path 901218822Sdim back to the ifield if it exists. */ 902218822Sdim start = fixP->fx_cgen.field->val.leaf->start; 903218822Sdim length = fixP->fx_cgen.field->val.leaf->length; 904218822Sdim } 905218822Sdim else 906218822Sdim { 907218822Sdim /* Or the far less useful operand-size guesstimate. */ 908218822Sdim start = operand->start; 909218822Sdim length = operand->length; 910218822Sdim } 911218822Sdim 912218822Sdim /* FIXME: this is not a perfect heuristic for figuring out 913218822Sdim whether an operand is signed: it only works when the operand 914218822Sdim is an immediate. it's not terribly likely that any other 915218822Sdim values will be signed relocs, but it's possible. */ 916218822Sdim if (operand && (operand->hw_type == HW_H_SINT)) 917218822Sdim signed_p = 1; 918218822Sdim 91933965Sjdp /* If the reloc has been fully resolved finish the operand here. */ 92033965Sjdp /* FIXME: This duplicates the capabilities of code in BFD. */ 92133965Sjdp if (fixP->fx_done 92233965Sjdp /* FIXME: If partial_inplace isn't set bfd_install_relocation won't 92333965Sjdp finish the job. Testing for pcrel is a temporary hack. */ 92433965Sjdp || fixP->fx_pcrel) 92533965Sjdp { 92660484Sobrien CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn)); 92760484Sobrien CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value); 92860484Sobrien 92960484Sobrien#if CGEN_INT_INSN_P 93060484Sobrien { 93160484Sobrien CGEN_INSN_INT insn_value = 932218822Sdim cgen_get_insn_value (cd, (unsigned char *) where, 933218822Sdim CGEN_INSN_BITSIZE (insn)); 93460484Sobrien 93585815Sobrien /* ??? 0 is passed for `pc'. */ 93660484Sobrien errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields, 93760484Sobrien &insn_value, (bfd_vma) 0); 938218822Sdim cgen_put_insn_value (cd, (unsigned char *) where, 939218822Sdim CGEN_INSN_BITSIZE (insn), insn_value); 94060484Sobrien } 94160484Sobrien#else 94285815Sobrien /* ??? 0 is passed for `pc'. */ 943218822Sdim errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields, 944218822Sdim (unsigned char *) where, 94585815Sobrien (bfd_vma) 0); 94660484Sobrien#endif 94733965Sjdp if (errmsg) 94860484Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg); 94933965Sjdp } 95033965Sjdp 95133965Sjdp if (fixP->fx_done) 95289857Sobrien return; 95333965Sjdp 95433965Sjdp /* The operand isn't fully resolved. Determine a BFD reloc value 95533965Sjdp based on the operand information and leave it to 95633965Sjdp bfd_install_relocation. Note that this doesn't work when 95733965Sjdp partial_inplace == false. */ 95833965Sjdp 95960484Sobrien reloc_type = md_cgen_lookup_reloc (insn, operand, fixP); 960218822Sdim#ifdef OBJ_COMPLEX_RELC 961218822Sdim if (reloc_type == BFD_RELOC_RELC) 962218822Sdim { 963218822Sdim /* Change addend to "self-describing" form, 964218822Sdim for BFD to handle in the linker. */ 965218822Sdim value = gas_cgen_encode_addend (start, operand->length, 966218822Sdim length, fixP->fx_size, 967218822Sdim cd->insn_chunk_bitsize / 8, 968218822Sdim signed_p, 969218822Sdim ! (fixP->fx_cgen.msb_field_p)); 970218822Sdim } 971218822Sdim#endif 97289857Sobrien 97333965Sjdp if (reloc_type != BFD_RELOC_NONE) 97489857Sobrien fixP->fx_r_type = reloc_type; 97533965Sjdp else 97633965Sjdp { 97733965Sjdp as_bad_where (fixP->fx_file, fixP->fx_line, 97860484Sobrien _("unresolved expression that must be resolved")); 97933965Sjdp fixP->fx_done = 1; 98089857Sobrien return; 98133965Sjdp } 98233965Sjdp } 98333965Sjdp else if (fixP->fx_done) 98433965Sjdp { 98533965Sjdp /* We're finished with this fixup. Install it because 98633965Sjdp bfd_install_relocation won't be called to do it. */ 98733965Sjdp switch (fixP->fx_r_type) 98833965Sjdp { 98933965Sjdp case BFD_RELOC_8: 99033965Sjdp md_number_to_chars (where, value, 1); 99133965Sjdp break; 99233965Sjdp case BFD_RELOC_16: 99333965Sjdp md_number_to_chars (where, value, 2); 99433965Sjdp break; 99533965Sjdp case BFD_RELOC_32: 99633965Sjdp md_number_to_chars (where, value, 4); 99733965Sjdp break; 99885815Sobrien case BFD_RELOC_64: 99985815Sobrien md_number_to_chars (where, value, 8); 100085815Sobrien break; 100133965Sjdp default: 100260484Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 100360484Sobrien _("internal error: can't install fix for reloc type %d (`%s')"), 100460484Sobrien fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type)); 100560484Sobrien break; 100633965Sjdp } 100733965Sjdp } 100889857Sobrien /* else 100989857Sobrien bfd_install_relocation will be called to finish things up. */ 101033965Sjdp 101133965Sjdp /* Tuck `value' away for use by tc_gen_reloc. 101233965Sjdp See the comment describing fx_addnumber in write.h. 101333965Sjdp This field is misnamed (or misused :-). */ 101433965Sjdp fixP->fx_addnumber = value; 101533965Sjdp} 101633965Sjdp 101733965Sjdp/* Translate internal representation of relocation info to BFD target format. 101833965Sjdp 101933965Sjdp FIXME: To what extent can we get all relevant targets to use this? */ 102033965Sjdp 102133965Sjdparelent * 102260484Sobriengas_cgen_tc_gen_reloc (section, fixP) 102385815Sobrien asection * section ATTRIBUTE_UNUSED; 102438889Sjdp fixS * fixP; 102533965Sjdp{ 102685815Sobrien arelent *reloc; 102760484Sobrien reloc = (arelent *) xmalloc (sizeof (arelent)); 102833965Sjdp 102933965Sjdp reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); 103033965Sjdp if (reloc->howto == (reloc_howto_type *) NULL) 103133965Sjdp { 103233965Sjdp as_bad_where (fixP->fx_file, fixP->fx_line, 103385815Sobrien _("relocation is not supported")); 103433965Sjdp return NULL; 103533965Sjdp } 103633965Sjdp 103733965Sjdp assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); 103833965Sjdp 103960484Sobrien reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); 104060484Sobrien *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); 104133965Sjdp 104285815Sobrien /* Use fx_offset for these cases. */ 104385815Sobrien if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY 104460484Sobrien || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT) 104585815Sobrien reloc->addend = fixP->fx_offset; 104660484Sobrien else 104785815Sobrien reloc->addend = fixP->fx_addnumber; 104860484Sobrien 104960484Sobrien reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; 105033965Sjdp return reloc; 105133965Sjdp} 1052130561Sobrien 1053130561Sobrien/* Perform any cgen specific initialisation. 1054130561Sobrien Called after gas_cgen_cpu_desc has been created. */ 1055130561Sobrien 1056130561Sobrienvoid 1057130561Sobriengas_cgen_begin () 1058130561Sobrien{ 1059130561Sobrien if (flag_signed_overflow_ok) 1060130561Sobrien cgen_set_signed_overflow_ok (gas_cgen_cpu_desc); 1061130561Sobrien else 1062130561Sobrien cgen_clear_signed_overflow_ok (gas_cgen_cpu_desc); 1063130561Sobrien} 1064218822Sdim 1065