From: Mark Eichin Date: Mon, 12 Jul 1993 19:42:32 +0000 (+0000) Subject: fix definitions of md_create_long_jump, md_create_short_jump, X-Git-Tag: gdb-4_18~18335 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=025b0302439df01169c7d9cb06493bbb53c7ce6b;p=external%2Fbinutils.git fix definitions of md_create_long_jump, md_create_short_jump, md_number_to_chars, and md_section_align to correctly use valueT and addressT --- diff --git a/gas/config/tc-h8300.c b/gas/config/tc-h8300.c index 316b5c1..62aa3fd 100644 --- a/gas/config/tc-h8300.c +++ b/gas/config/tc-h8300.c @@ -1,24 +1,24 @@ /* tc-h8300.c -- Assemble code for the Hitachi H8/300 Copyright (C) 1991, 1992 Free Software Foundation. - + This file is part of GAS, the GNU Assembler. - + GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - + GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* +/* Written By Steve Chamberlain sac@cygnus.com */ @@ -26,12 +26,16 @@ #include #include "as.h" #include "bfd.h" +#define DEFINE_TABLE +#define h8_opcodes ops #include "opcode/h8300.h" #include -#include "listing.h" -char comment_chars[] = { ';',0 }; -char line_separator_chars[] = { '$' ,0}; +const char comment_chars[] = +{';', 0}; +const char line_separator_chars[] = +{'$', 0}; +const char line_comment_chars[] = "#"; /* This table describes all the machine specific pseudo-ops the assembler has to support. The fields are: @@ -40,30 +44,56 @@ char line_separator_chars[] = { '$' ,0}; Integer arg to pass to the function */ -void cons(); +void cons (); + +int Hmode; +#define PSIZE (Hmode ? L_32 : L_16) +#define DMODE (L_16) +#define DSYMMODE (Hmode ? L_24 : L_16) +int bsize = L_8; /* default branch displacement */ + + +void +h8300hmode () +{ + Hmode = 1; +} + + +void +sbranch (size) + int size; +{ + bsize = size; +} -const pseudo_typeS md_pseudo_table[] = +const pseudo_typeS md_pseudo_table[] = { -{ "int", cons, 2 }, -{ "data.b", cons, 1 }, -{ "data.w", cons, 2 }, -{ "data.l", cons, 4 }, -{ "form", listing_psize, 0 }, -{ "heading", listing_title, 0}, -{ "import", s_ignore, 0}, -{ "page", listing_eject, 0}, -{ "program", s_ignore, 0}, -{ 0,0,0 } + + {"h8300h", h8300hmode, 0}, + {"sbranch", sbranch, L_8}, + {"lbranch", sbranch, L_16}, + + {"int", cons, 2}, + {"data.b", cons, 1}, + {"data.w", cons, 2}, + {"data.l", cons, 4}, + {"form", listing_psize, 0}, + {"heading", listing_title, 0}, + {"import", s_ignore, 0}, + {"page", listing_eject, 0}, + {"program", s_ignore, 0}, + {0, 0, 0} }; -int md_reloc_size ; +const int md_reloc_size; const char EXP_CHARS[] = "eE"; /* Chars that mean this number is a floating point constant */ /* As in 0f12.456 */ /* or 0d1.2345e12 */ -char FLT_CHARS[] = "rRsSfFdDxXpP"; +const char FLT_CHARS[] = "rRsSfFdDxXpP"; const relax_typeS md_relax_table[1]; @@ -71,242 +101,234 @@ const relax_typeS md_relax_table[1]; static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ - /* 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 */ -#if 0 -/* encode the size and number into the number field - xxnnnn - 00 8 bit - 01 16 bit - 10 ccr - nnnnreg number - */ -#define WORD_REG 0x10 -#define BYTE_REG 0x00 -#define CCR_REG 0x20 -struct reg_entry -{ - char *name; - char number; -}; - -struct reg_entry reg_list[] = { - "r0",WORD_REG +0, - "r1",WORD_REG +1, - "r2",WORD_REG +2, - "r3",WORD_REG +3, - "r4",WORD_REG +4, - "r5",WORD_REG +5, - "r6",WORD_REG +6, - "r7",WORD_REG +7, - "fp",WORD_REG +6, - "sp",WORD_REG +7, - "r0h",BYTE_REG + 0, - "r0l",BYTE_REG + 1, - "r1h",BYTE_REG + 2, - "r1l",BYTE_REG + 3, - "r2h",BYTE_REG + 4, - "r2l",BYTE_REG + 5, - "r3h",BYTE_REG + 6, - "r3l",BYTE_REG + 7, - "r4h",BYTE_REG + 8, - "r4l",BYTE_REG + 9, - "r5h",BYTE_REG + 10, - "r5l",BYTE_REG + 11, - "r6h",BYTE_REG + 12, - "r6l",BYTE_REG + 13, - "r7h",BYTE_REG + 14, - "r7l",BYTE_REG + 15, - "ccr",CCR_REG, - 0,0 - } -; -#endif +void +md_begin () +{ + struct h8_opcode *opcode; + const struct reg_entry *reg; + char prev_buffer[100]; + int idx = 0; + opcode_hash_control = hash_new (); + prev_buffer[0] = 0; -void md_begin () -{ - struct h8_opcode *opcode; - const struct reg_entry *reg; - char prev_buffer[100]; - int idx = 0; - - opcode_hash_control = hash_new(); - prev_buffer[0] = 0; - - for (opcode = h8_opcodes; opcode->name; opcode++) + for (opcode = h8_opcodes; opcode->name; opcode++) + { + /* Strip off any . part when inserting the opcode and only enter + unique codes into the hash table + */ + char *src = opcode->name; + unsigned int len = strlen (src); + char *dst = malloc (len + 1); + char *buffer = dst; + + opcode->size = 0; + while (*src) + { + if (*src == '.') { - /* Strip off any . part when inserting the opcode and only enter - unique codes into the hash table - */ - char *src= opcode->name; - unsigned int len = strlen(src); - char *dst = malloc(len+1); - char *buffer = dst; - opcode->size = 0; - while (*src) { - if (*src == '.') { - *dst++ = 0; - src++; - opcode->size = *src; - break; - } - *dst++ = *src++; - } - if (strcmp(buffer, prev_buffer)) - { - hash_insert(opcode_hash_control, buffer, (char *)opcode); - strcpy(prev_buffer, buffer); - idx++; - } - opcode->idx = idx; - - - /* Find the number of operands */ - opcode->noperands = 0; - while (opcode->args.nib[opcode->noperands] != E) - opcode->noperands ++; - /* Find the length of the opcode in bytes */ - opcode->length =0; - while (opcode->data.nib[opcode->length*2] != E) - opcode->length++; + src++; + opcode->size = *src; + break; } - + *dst++ = *src++; + } + *dst++ = 0; + if (strcmp (buffer, prev_buffer)) + { + hash_insert (opcode_hash_control, buffer, (char *) opcode); + strcpy (prev_buffer, buffer); + idx++; + } + opcode->idx = idx; + + + /* Find the number of operands */ + opcode->noperands = 0; + while (opcode->args.nib[opcode->noperands] != E) + opcode->noperands++; + /* Find the length of the opcode in bytes */ + opcode->length = 0; + while (opcode->data.nib[opcode->length * 2] != E) + opcode->length++; + } + } -struct h8_exp { - char *e_beg; - char *e_end; - expressionS e_exp; -}; -struct h8_op +struct h8_exp { - unsigned int dispreg; - op_type mode; - unsigned reg; - expressionS exp; + char *e_beg; + char *e_end; + expressionS e_exp; }; +int dispreg; +int opsize; /* Set when a register size is seen */ +struct h8_op +{ + op_type mode; + unsigned reg; + expressionS exp; +}; /* - parse operands + parse operands WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp r0l,r0h,..r7l,r7h @WREG @WREG+ @-WREG #const - - */ -op_type r8_sord[] = {RS8, RD8}; -op_type r16_sord[] = {RS16, RD16}; -op_type rind_sord[] = {RSIND, RDIND}; -op_type abs_sord[2] = {ABS16SRC, ABS16DST}; -op_type disp_sord[] = {DISPSRC, DISPDST}; + */ /* try and parse a reg name, returns number of chars consumed */ -int - DEFUN(parse_reg,(src, mode, reg, dst), - char *src AND - op_type *mode AND - unsigned int *reg AND - int dst) +int +parse_reg (src, mode, reg, direction) + char *src; + op_type *mode; + unsigned int *reg; + int direction; + { - if (src[0] == 's' && src[1] == 'p') - { - *mode = r16_sord[dst]; - *reg = 7; - return 2; - } - if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r') - { - *mode = CCR; - *reg = 0; - return 3; - } - if (src[0] == 'f' && src[1] == 'p') + if (src[0] == 's' && src[1] == 'p') + { + *mode = PSIZE | REG | direction; + *reg = 7; + return 2; + } + if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r') + { + *mode = CCR; + *reg = 0; + return 3; + } + if (src[0] == 'f' && src[1] == 'p') + { + *mode = PSIZE | REG | direction; + *reg = 6; + return 2; + } + if (src[0] == 'e' + && src[1] == 'r' + && src[2] >= '0' && src[2] <= '7') + { + *mode = L_32 | REG | direction; + *reg = src[2] - '0'; + if (!Hmode) + as_warn ("Reg only legal for H8/300-H"); + + return 3; + } + if (src[0] == 'e' + && src[1] >= '0' && src[1] <= '7') + { + *mode = L_16 | REG | direction; + *reg = src[1] - '0' + 8; + if (!Hmode) + as_warn ("Reg only legal for H8/300-H"); + return 2; + } + + if (src[0] == 'r') + { + if (src[1] >= '0' && src[1] <= '7') + { + if (src[2] == 'l') { - *mode = r16_sord[dst]; - *reg = 6; - return 2; + *mode = L_8 | REG | direction; + *reg = (src[1] - '0') + 8; + return 3; } - if (src[0] == 'r') + if (src[2] == 'h') { - if (src[1] >= '0' && src[1] <= '7') - { - if(src[2] == 'l') - { - *mode = r8_sord[dst]; - *reg = (src[1] - '0') + 8; - return 3; - } - if(src[2] == 'h') - { - *mode = r8_sord[dst]; - *reg = (src[1] - '0') ; - return 3; - } - *mode = r16_sord[dst]; - *reg = (src[1] - '0'); - return 2; - } + *mode = L_8 | REG | direction; + *reg = (src[1] - '0'); + return 3; } - return 0; + *mode = L_16 | REG | direction; + *reg = (src[1] - '0'); + return 2; + } + } + return 0; } char * - DEFUN(parse_exp,(s, op), - char *s AND - expressionS *op) +DEFUN (parse_exp, (s, op), + char *s AND + expressionS * op) { - char *save = input_line_pointer; - char *new; - segT seg; - input_line_pointer = s; - seg = expr(0,op); - new = input_line_pointer; - input_line_pointer = save; - if (SEG_NORMAL(seg)) - return new; - switch (seg) { - case SEG_ABSOLUTE: - case SEG_UNKNOWN: - case SEG_DIFFERENCE: - case SEG_BIG: - case SEG_REGISTER: - return new; - case SEG_ABSENT: - as_bad("Missing operand"); - return new; - default: - as_bad("Don't understand operand of type %s", segment_name (seg)); - return new; - } + char *save = input_line_pointer; + char *new; + segT seg; + + input_line_pointer = s; + seg = expr (0, op); + new = input_line_pointer; + input_line_pointer = save; + if (SEG_NORMAL (seg)) + return new; + switch (seg) + { + case SEG_ABSOLUTE: + case SEG_UNKNOWN: + case SEG_DIFFERENCE: + case SEG_BIG: + case SEG_REGISTER: + return new; + case SEG_ABSENT: + as_bad ("Missing operand"); + return new; + default: + as_bad ("Don't understand operand of type %s", segment_name (seg)); + return new; + } } static char * - DEFUN(skip_colonthing,(ptr), - char *ptr) +skip_colonthing (ptr, exp, mode) + char *ptr; + expressionS *exp; + int *mode; { - if (*ptr == ':') { - ptr++; - while (isdigit(*ptr)) - ptr++; - + if (*ptr == ':') + { + ptr++; + if (*ptr == '8') + { + ptr++; + /* ff fill any 8 bit quantity */ + exp->X_add_number |= 0xff00; } - return ptr; + else + { + *mode &= ~SIZE; + if (*ptr == '2') + { + *mode |= L_24; + } + else if (*ptr == '1') + { + *mode |= L_16; + } + while (isdigit (*ptr)) + ptr++; + } + } + return ptr; } /* The many forms of operand: - + Rn Register direct @Rn Register indirect @(exp[:16], Rn) Register indirect with displacement @@ -315,205 +337,280 @@ static char * @aa:8 absolute 8 bit @aa:16 absolute 16 bit @aa absolute 16 bit - + #xx[:size] immediate data @(exp:[8], pc) pc rel @@aa[:8] memory indirect - + */ -static void - DEFUN(get_operand,(ptr, op, dst), - char **ptr AND - struct h8_op *op AND - unsigned int dst) +char * +colonmod24 (op, src) + struct h8_op *op; + char *src; + +{ + int mode = 0; + src = skip_colonthing (src, &op->exp, &mode); + + if (!mode) + { + /* Choose a default mode */ + if (op->exp.X_add_number < -32768 + || op->exp.X_add_number > 32767) + { + if (Hmode) + mode = L_24; + else + mode = L_16; + } + else if (op->exp.X_add_symbol + || op->exp.X_subtract_symbol) + mode = DSYMMODE; + else + mode = DMODE; + } + op->mode |= mode; + return src; + +} + + +static void +get_operand (ptr, op, dst, direction) + char **ptr; + struct h8_op *op; + unsigned int dst; + { char *src = *ptr; op_type mode; - unsigned int num; - unsigned int len; + unsigned int num; + unsigned int len; unsigned int size; + op->mode = E; - - len = parse_reg(src, &op->mode, &op->reg, dst); - if (len) { - *ptr = src + len; - return ; - } - - if (*src == '@') - { - src++; - if (*src == '@') + + len = parse_reg (src, &op->mode, &op->reg, direction); + if (len) { - src++; - src = parse_exp(src,&op->exp); - src = skip_colonthing(src); - - *ptr = src; - - op->mode = MEMIND; - return; - - } - - - if (*src == '-') - { - src++; - len = parse_reg(src, &mode, &num, dst); - if (len == 0) - { - /* Oops, not a reg after all, must be ordinary exp */ - src--; - /* must be a symbol */ - op->mode = abs_sord[dst]; - *ptr = skip_colonthing(parse_exp(src, &op->exp)); - - return; - - - } - - if (mode != r16_sord[dst]) - { - as_bad("@- needs word register"); - } - op->mode = RDDEC; - op->reg = num; *ptr = src + len; return; } - if (*src == '(' && ')') + + if (*src == '@') { - /* Disp */ - src++; - src = parse_exp(src, &op->exp); - - if (*src == ')') - { - src++; - op->mode = abs_sord[dst]; - *ptr = src; - return; - } - src = skip_colonthing(src); - - if (*src != ',') - { - as_bad("expected @(exp, reg16)"); - return; - - } src++; - len = parse_reg(src, &mode, &op->reg, dst); - if (len == 0 || mode != r16_sord[dst]) - { - as_bad("expected @(exp, reg16)"); - return; - } - op->mode = disp_sord[dst]; - src += len; - src = skip_colonthing(src); - - if (*src != ')' && '(') - { - as_bad("expected @(exp, reg16)"); - return; - } - *ptr = src +1; - - return; - } - len = parse_reg(src, &mode, &num, dst); - - if(len) { - src += len; - if (*src == '+') + if (*src == '@') + { + src++; + src = parse_exp (src, &op->exp); + + src = skip_colonthing (src, &op->exp, &op->mode); + + *ptr = src; + + op->mode = MEMIND; + return; + + } + + + if (*src == '-') { src++; - if (mode != RS16) - { - as_bad("@Rn+ needs src word register"); - return; - } - op->mode = RSINC; + len = parse_reg (src, &mode, &num, direction); + if (len == 0) + { + /* Oops, not a reg after all, must be ordinary exp */ + src--; + /* must be a symbol */ + op->mode = ABS | PSIZE | direction; + *ptr = skip_colonthing (parse_exp (src, &op->exp), + &op->exp, &op->mode); + + return; + + + } + + + if ((mode & SIZE) != PSIZE) + as_bad ("Wrong size pointer register for architecture."); + op->mode = RDDEC; + op->reg = num; + *ptr = src + len; + return; + } + if (*src == '(' ) + { + /* Disp */ + src++; + + /* Start off assuming a 16 bit offset */ + + + src = parse_exp (src, &op->exp); + + src = colonmod24 (op, src); + + if (*src == ')') + { + src++; + op->mode = DISP | direction; + *ptr = src; + return; + } + + if (*src != ',') + { + as_bad ("expected @(exp, reg16)"); + return; + + } + src++; + + len = parse_reg (src, &mode, &op->reg, direction); + if (len == 0 || !(mode & REG)) + { + as_bad ("expected @(exp, reg16)"); + return; + } + op->mode |= DISP | direction; + dispreg = op->reg; + src += len; + src = skip_colonthing (src, &op->exp, &op->mode); + + if (*src != ')' && '(') + { + as_bad ("expected @(exp, reg16)"); + return; + } + *ptr = src + 1; + + return; + } + len = parse_reg (src, &mode, &num, direction); + + if (len) + { + src += len; + if (*src == '+') + { + src++; + if ((mode & SIZE) != PSIZE) + as_bad ("Wrong size pointer register for architecture."); + op->mode = RSINC; + op->reg = num; + *ptr = src; + return; + } + if ((mode & SIZE) != PSIZE) + as_bad ("Wrong size pointer register for architecture."); + + op->mode = direction | IND | PSIZE; op->reg = num; *ptr = src; + return; } - if (mode != r16_sord[dst]) + else { - as_bad("@Rn needs word register"); + /* must be a symbol */ + + op->mode = ABS | direction; + src = parse_exp (src, &op->exp); + + *ptr = colonmod24 (op, src); + return; - } - op->mode =rind_sord[dst]; - op->reg = num; - *ptr = src; - - return; - } - else - { - /* must be a symbol */ - op->mode = abs_sord[dst]; - *ptr = skip_colonthing(parse_exp(src, &op->exp)); - - return; } - } - - - if (*src == '#') { + + + if (*src == '#') + { src++; - op->mode = IMM16; - src = parse_exp(src, &op->exp); - *ptr= skip_colonthing(src); - + op->mode = IMM; + src = parse_exp (src, &op->exp); + *ptr = skip_colonthing (src, &op->exp, &op->mode); + return; } - else { - *ptr = parse_exp(src, &op->exp); - op->mode = DISP8; + else + { + src = parse_exp (src, &op->exp); + /* Trailing ':' size ? */ + if (*src == ':') + { + if (src[1] == '1' && src[2] == '6') + { + op->mode = PCREL | L_16; + src += 3; + } + else if (src[1] == '8') + { + op->mode = PCREL | L_8; + src += 2; + } + else + { + as_bad ("expect :8 or :16 here"); + } + } + else + { + op->mode = PCREL | bsize; + } + *ptr = src; } } static - char * - DEFUN(get_operands,(noperands,op_end, operand), - unsigned int noperands AND - char *op_end AND - struct h8_op *operand) +char * +DEFUN (get_operands, (noperands, op_end, operand), + unsigned int noperands AND + char *op_end AND + struct h8_op *operand) { - char *ptr = op_end; - switch (noperands) - { - case 0: - operand[0].mode = 0; - operand[1].mode = 0; - break; - - case 1: - ptr++; - get_operand(& ptr, operand +0,0); - operand[1].mode =0; - break; - - case 2: - ptr++; - get_operand(& ptr, operand +0,0); - if (*ptr == ',') ptr++; - get_operand(& ptr, operand +1, 1); - break; - - default: - abort(); - } - - - return ptr; + char *ptr = op_end; + + switch (noperands) + { + case 0: + operand[0].mode = 0; + operand[1].mode = 0; + break; + + case 1: + ptr++; + get_operand (&ptr, operand + 0, 0, SRC); + if (*ptr == ',') + { + ptr++; + get_operand (&ptr, operand + 1, 1, DST); + } + else + { + operand[1].mode = 0; + } + + break; + case 2: + ptr++; + get_operand (&ptr, operand + 0, 0, SRC); + if (*ptr == ',') + ptr++; + get_operand (&ptr, operand + 1, 1, DST); + break; + + default: + abort (); + } + + + return ptr; } /* Passed a pointer to a list of opcodes which use different @@ -521,481 +618,480 @@ static provided */ static - struct h8_opcode * - DEFUN(get_specific,(opcode, operands), - struct h8_opcode *opcode AND - struct h8_op *operands) - +struct h8_opcode * +get_specific (opcode, operands) + struct h8_opcode *opcode; + struct h8_op *operands; { - struct h8_opcode *this_try = opcode ; - int found = 0; - unsigned int noperands = opcode->noperands; - - unsigned int dispreg; - unsigned int this_index = opcode->idx; - while (this_index == opcode->idx && !found) + struct h8_opcode *this_try = opcode; + int found = 0; + + unsigned int this_index = opcode->idx; + + while (this_index == opcode->idx && !found) + { + unsigned int i; + found = 1; + + this_try = opcode++; + for (i = 0; i < this_try->noperands && found; i++) + { + op_type op = this_try->args.nib[i]; + int x = operands[i].mode; + + if ((op & (DISP | REG)) == (DISP | REG) + && ((x & DISP | REG) == (DISP | REG))) { - unsigned int i; - - this_try = opcode ++; - for (i = 0; i < noperands; i++) - { - op_type op = (this_try->args.nib[i]) & ~(B30|B31); - switch (op) - { - case Hex0: - case Hex1: - case Hex2: - case Hex3: - case Hex4: - case Hex5: - case Hex6: - case Hex7: - case Hex8: - case Hex9: - case HexA: - case HexB: - case HexC: - case HexD: - case HexE: - case HexF: - break; - case DISPSRC: - case DISPDST: - operands[0].dispreg = operands[i].reg; - case RD8: - case RS8: - case RDIND: - case RSIND: - case RD16: - case RS16: - case CCR: - case RSINC: - case RDDEC: - if (operands[i].mode != op) goto fail; - break; - case KBIT: - case IMM16: - case IMM3: - case IMM8: - if (operands[i].mode != IMM16) goto fail; - break; - case MEMIND: - if (operands[i].mode != MEMIND) goto fail; - break; - case ABS16SRC: - case ABS8SRC: - case ABS16OR8SRC: - case ABS16ORREL8SRC: - - if (operands[i].mode != ABS16SRC) goto fail; - break; - case ABS16OR8DST: - case ABS16DST: - case ABS8DST: - if (operands[i].mode != ABS16DST) goto fail; - break; - } - } - found =1; - fail: ; + dispreg = operands[i].reg; } - if (found) - return this_try; - else - return 0; + else if (op & REG) + { + if (!(x & REG)) + found = 0; + + if (x & L_P) + { + x = (x & ~L_P) | (Hmode ? L_32 : L_16); + } + if (op & L_P) + { + op = (op & ~L_P) | (Hmode ? L_32 : L_16); + } + + opsize = op & SIZE; + + /* The size of the reg is v important */ + if ((op & SIZE) != (x & SIZE)) + found = 0; + } + else if ((op & ABSJMP) && (x & ABS)) + { + operands[i].mode &= ~ABS; + operands[i].mode |= ABSJMP; + /* But it may not be 24 bits long */ + if (!Hmode) + { + operands[i].mode &= ~SIZE; + operands[i].mode |= L_16; + } + + + } + else if ((op & (KBIT | DBIT)) && (x & IMM)) + { + /* This is ok if the immediate value is sensible */ + + } + else if (op & PCREL) + { + + /* The size of the displacement is important */ + if ((op & SIZE) != (x & SIZE)) + found = 0; + + } + else if ((op & (DISP | IMM | ABS)) + && (op & (DISP | IMM | ABS)) == (x & (DISP | IMM | ABS))) + { + /* Got a diplacement,will fit if no size or same size as try */ + if ((x & SIZE) != 0 + && ((op & SIZE) != (x & SIZE))) + found = 0; + } + else if ((op & ABSMOV) && (x & ABS)) + { + /* Ok */ + } + else if ((op & MODE) != (x & MODE)) + { + found = 0; + } + + } + } + if (found) + return this_try; + else + return 0; } static void - DEFUN(check_operand,(operand, width, string), - struct h8_op *operand AND - unsigned int width AND - char *string) +DEFUN (check_operand, (operand, width, string), + struct h8_op *operand AND + unsigned int width AND + char *string) { - if (operand->exp.X_add_symbol == 0 + if (operand->exp.X_add_symbol == 0 && operand->exp.X_subtract_symbol == 0) - { - - /* No symbol involved, let's look at offset, it's dangerous if any of - the high bits are not 0 or ff's, find out by oring or anding with - the width and seeing if the answer is 0 or all fs*/ - if ((operand->exp.X_add_number & ~width) != 0 && - (operand->exp.X_add_number | width)!= (~0)) { - as_warn("operand %s0x%x out of range.", string, operand->exp.X_add_number); + + /* No symbol involved, let's look at offset, it's dangerous if any of + the high bits are not 0 or ff's, find out by oring or anding with + the width and seeing if the answer is 0 or all fs*/ + if ((operand->exp.X_add_number & ~width) != 0 && + (operand->exp.X_add_number | width) != (~0)) + { + as_warn ("operand %s0x%x out of range.", string, operand->exp.X_add_number); + } } - } - + +} + +static void +do_a_fix_imm (offset, operand, relaxing) + int offset; + struct h8_op *operand; + int relaxing; +{ + int idx; + int size; + int where; + + + char *t = operand->mode & IMM ? "#" : "@"; + + if (operand->exp.X_add_symbol == 0) + { + char *bytes = frag_now->fr_literal + offset; + switch (operand->mode & SIZE) + { + case L_3: + check_operand (operand, 0x7, t); + bytes[0] |= (operand->exp.X_add_number) << 4; + break; + case L_8: + check_operand (operand, 0xff, t); + bytes[0] = operand->exp.X_add_number; + break; + case L_16: + check_operand (operand, 0xffff, t); + bytes[0] = operand->exp.X_add_number >> 8; + bytes[1] = operand->exp.X_add_number >> 0; + break; + case L_24: + check_operand (operand, 0xffffff, t); + bytes[0] = operand->exp.X_add_number >> 16; + bytes[1] = operand->exp.X_add_number >> 8; + bytes[2] = operand->exp.X_add_number >> 0; + break; + + case L_32: + /* This should be done with bfd */ + bytes[0] = operand->exp.X_add_number >> 24; + bytes[1] = operand->exp.X_add_number >> 16; + bytes[2] = operand->exp.X_add_number >> 8; + bytes[3] = operand->exp.X_add_number >> 0; + break; + } + + } + else + { + switch (operand->mode & SIZE) + { + default: + abort (); + case L_24: + size = 4; + where = -1; + idx = relaxing ? R_MOVLB1 : R_RELLONG; + break; + + case L_32: + size = 4; + where = 0; + idx = R_RELLONG; + break; + case L_16: + size = 2; + where = 0; + idx = relaxing ? R_MOVB1 : R_RELWORD; + break; + case L_8: + size = 1; + where = 0; + idx = R_RELBYTE; + } + + + fix_new (frag_now, + offset + where, + size, + operand->exp.X_add_symbol, + operand->exp.X_subtract_symbol, + (short) (operand->exp.X_add_number), + 0, + idx); + } + } /* Now we know what sort of opcodes it is, lets build the bytes - */ -static void - DEFUN (build_bytes,(this_try, operand), - struct h8_opcode *this_try AND - struct h8_op *operand) - +static void +build_bytes (this_try, operand) + struct h8_opcode *this_try; + struct h8_op *operand; { - unsigned int i; - - char *output = frag_more(this_try->length); - char *output_ptr = output; - op_type *nibble_ptr = this_try->data.nib; - char part; - op_type c; - char high; - int nib; - top: ; - while (*nibble_ptr != E) + unsigned int i; + + char *output = frag_more (this_try->length); + char *output_ptr = output; + op_type *nibble_ptr = this_try->data.nib; + char part; + op_type c; + char high; + unsigned int nibble_count = 0; + + int immat; + int nib; + char asnibbles[30]; + char *p = asnibbles; + + if (!(this_try->inbase || Hmode)) + { + as_warn ("Opcode `%s' only available on H8/300-H", this_try->name); + } + + while (*nibble_ptr != E) + { + int d; + c = *nibble_ptr++; + + d = (c & DST) != 0; + + if (c < 16) + { + nib = c; + } + else + { + + if (c & (REG | IND | INC | DEC)) { - int nibble; - for (nibble = 0; nibble <2; nibble++) - { - c = *nibble_ptr & ~(B30|B31); - switch (c) - { - default: - abort(); - case KBIT: - switch (operand[0].exp.X_add_number) - { - case 1: - nib = 0; - break; - case 2: - nib = 8; - break; - default: - as_bad("Need #1 or #2 here"); - break; - } - /* stop it making a fix */ - operand[0].mode = 0; - break; - case 0: - case 1: - case 2: case 3: case 4: case 5: case 6: - case 7: case 8: case 9: case 10: case 11: - case 12: case 13: case 14: case 15: - nib = c; - break; - case DISPREG: - nib = operand[0].dispreg; - break; - case IMM8: - operand[0].mode = IMM8; - nib = 0; - break; - - case DISPDST: - nib = 0; - break; - case IMM3: - if (operand[0].exp.X_add_symbol == 0) { - operand[0].mode = 0; /* stop it making a fix */ - nib = (operand[0].exp.X_add_number); - } - else as_bad("can't have symbol for bit number"); - if (nib < 0 || nib > 7) - { - as_bad("Bit number out of range %d", nib); - } - - break; - - case ABS16DST: - nib = 0; - break; - case ABS8DST: - operand[1].mode = ABS8DST; - nib = 0; - break; - case ABS8SRC: - operand[0].mode = ABS8SRC; - nib = 0; - break; - case ABS16OR8DST: - operand[1].mode = c; - - nib = 0; - - break; - - case ABS16ORREL8SRC: - operand[0].mode = c; - nib=0; - break; - - case ABS16OR8SRC: - operand[0].mode = ABS16OR8SRC; - nib = 0; - break; - case DISPSRC: - operand[0].mode = ABS16SRC; - nib = 0; - break; - - case DISP8: - operand[0].mode = DISP8; - nib = 0; - break; - - case ABS16SRC: - case IMM16: - case IGNORE: - case MEMIND: - - nib=0; - break; - case RS8: - case RS16: - case RSIND: - case RSINC: - nib = operand[0].reg; - break; - - case RD8: - case RD16: - case RDDEC: - case RDIND: - nib = operand[1].reg; - break; - - case E: - abort(); - break; - } - if (*nibble_ptr & B31) { - nib |=0x8; - } - - if (nibble == 0) { - *output_ptr = nib << 4; - } - else { - *output_ptr |= nib; - output_ptr++; - } - nibble_ptr++; - } - + nib = operand[d].reg; } - - /* output any fixes */ - for (i = 0; i < 2; i++) + else if ((c & DISPREG) == (DISPREG)) { - switch (operand[i].mode) { - case 0: - break; - - case DISP8: - check_operand(operand+i, 0x7f,"@"); - - if (operand[i].exp.X_add_number & 1) { - as_warn("branch operand has odd offset (%x)\n", - operand->exp.X_add_number); - } - - fix_new(frag_now, - output - frag_now->fr_literal + 1, - 1, - operand[i].exp.X_add_symbol, - operand[i].exp.X_subtract_symbol, - operand[i].exp.X_add_number -1, - 1, - R_PCRBYTE); - break; - case IMM8: - check_operand(operand+i, 0xff,"#"); - /* If there is nothing else going on we can safely - reloc in place */ - if (operand[i].exp.X_add_symbol == 0) - { - output[1] = operand[i].exp.X_add_number; - } - else - { - fix_new(frag_now, - output - frag_now->fr_literal + 1, - 1, - operand[i].exp.X_add_symbol, - operand[i].exp.X_subtract_symbol, - operand[i].exp.X_add_number, - 0, - R_RELBYTE); - } - - break; - case MEMIND: - check_operand(operand+i, 0xff,"@@"); - fix_new(frag_now, - output - frag_now->fr_literal + 1, - 1, - operand[i].exp.X_add_symbol, - operand[i].exp.X_subtract_symbol, - operand[i].exp.X_add_number, - 0, - R_RELBYTE); - break; - case ABS8DST: - case ABS8SRC: - check_operand(operand+i, 0xff,"@"); - fix_new(frag_now, - output - frag_now->fr_literal + 1, - 1, - operand[i].exp.X_add_symbol, - operand[i].exp.X_subtract_symbol, - operand[i].exp.X_add_number, - 0, - R_RELBYTE); - break; - - case ABS16OR8SRC: - case ABS16OR8DST: - check_operand(operand+i, 0xffff,"@"); - - fix_new(frag_now, - output - frag_now->fr_literal + 2, - 2, - operand[i].exp.X_add_symbol, - operand[i].exp.X_subtract_symbol, - operand[i].exp.X_add_number, - 0, - R_MOVB1); - break; - - case ABS16ORREL8SRC: - check_operand(operand+i, 0xffff,"@"); - if (operand[i].exp.X_add_number & 1) { - as_warn("branch operand has odd offset (%x)\n", - operand->exp.X_add_number); - } - fix_new(frag_now, - output - frag_now->fr_literal + 2, - 2, - operand[i].exp.X_add_symbol, - operand[i].exp.X_subtract_symbol, - operand[i].exp.X_add_number, - 0, - R_JMP1); - break; - - - case ABS16SRC: - case ABS16DST: - case IMM16: - case DISPSRC: - case DISPDST: - check_operand(operand+i, 0xffff,"@"); - if (operand[i].exp.X_add_symbol == 0) - { - /* This should be done with bfd */ - output[3] = operand[i].exp.X_add_number & 0xff; - output[2] = operand[i].exp.X_add_number >> 8; - - } - else - { - - fix_new(frag_now, - output - frag_now->fr_literal + 2, - 2, - operand[i].exp.X_add_symbol, - operand[i].exp.X_subtract_symbol, - operand[i].exp.X_add_number, - 0, - R_RELWORD); - } - - break; - case RS8: - case RD8: - case RS16: - case RD16: - case RDDEC: - case KBIT: - case RSINC: - case RDIND: - case RSIND: - case CCR: - - break; - default: - abort(); - } + nib = dispreg; } - -} -/* - try and give an intelligent error message for common and simple to - detect errors - */ -static void - DEFUN(clever_message, (opcode, operand), - struct h8_opcode *opcode AND - struct h8_op *operand) -{ - struct h8_opcode *scan = opcode; - - /* Find out if there was more than one possible opccode */ - - if ((opcode+1)->idx != opcode->idx) - { - unsigned int argn; - - /* Only one opcode of this flavour, try and guess which operand - didn't match */ - for (argn = 0; argn < opcode->noperands; argn++) + else if (c & ABSMOV) + { + operand[d].mode &= ~ABS; + operand[d].mode |= ABSMOV; + immat = nibble_count / 2; + nib = 0; + } + else if (c & (IMM | PCREL | ABS | ABSJMP | DISP )) + { + operand[d].mode = c; + immat = nibble_count / 2; + nib = 0; + } + else if (c & IGNORE) + { + nib = 0; + } + else if (c & DBIT) + { + switch (operand[0].exp.X_add_number) + { + case 1: + nib = c; + break; + case 2: + nib = 0x8 | c; + break; + default: + as_bad ("Need #1 or #2 here"); + } + } + else if (c & KBIT) + { + switch (operand[0].exp.X_add_number) + { + case 1: + nib = 0; + break; + case 2: + nib = 8; + break; + case 4: + if (!Hmode) + as_warn ("#4 only valid in h8/300 mode."); + nib = 9; + break; + + default: + as_bad ("Need #1 or #2 here"); + break; + } + /* stop it making a fix */ + operand[0].mode = 0; + } + + if (c & B31) + { + nib |= 0x8; + } + } + nibble_count++; + + *p++ = nib; + } + + for (i = 0; i < this_try->length; i++) + { + output[i] = (asnibbles[i * 2] << 4) | asnibbles[i * 2 + 1]; + } + + /* output any fixes */ + for (i = 0; i < 2; i++) { - switch (opcode->args.nib[argn]) - { - case RD16: - if (operand[argn].mode != RD16) + int x = operand[i].mode; + + if (x & (IMM | ABS | DISP)) { - as_bad("destination operand must be 16 bit register"); - return; - + do_a_fix_imm (output - frag_now->fr_literal + immat, operand + i,0); } - break; - - case RS8: - - if (operand[argn].mode != RS8) + else if (x & PCREL) { - as_bad("source operand must be 8 bit register"); - return; + int size16 = x & L_16; + int where = size16 ? 2 : 1; + int size = size16 ? 2 : 1; + int type = size16 ? R_PCRWORD : R_PCRBYTE; + + check_operand (operand + i, size16 ? 0x7fff : 0x7f, "@"); + + if (operand[i].exp.X_add_number & 1) + { + as_warn ("branch operand has odd offset (%x)\n", + operand->exp.X_add_number); + } + + fix_new (frag_now, + output - frag_now->fr_literal + where, + size, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + (char) (operand[i].exp.X_add_number - 1), + 1, + type); } - break; - - case ABS16DST: - if (operand[argn].mode != ABS16DST) + else if (x & MEMIND) { - as_bad("destination operand must be 16bit absolute address"); - return; + + check_operand (operand + i, 0xff, "@@"); + fix_new (frag_now, + output - frag_now->fr_literal + 1, + 1, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number, + 0, + R_RELBYTE); } -break; - case RD8: - if (operand[argn].mode != RD8) + + else if (x & ABSMOV) { - as_bad("destination operand must be 8 bit register"); - return; + /* This mov is either absolute long or thru a memory loc */ + do_a_fix_imm (output - frag_now->fr_literal + immat, operand + i,1); } - break; - - - case ABS16SRC: - if (operand[argn].mode != ABS16SRC) + + else if (x & ABSJMP) { - as_bad("source operand must be 16bit absolute address"); - return; + /* This jmp may be a jump or a branch */ + + check_operand (operand + i, Hmode ? 0xfffff : 0xffff, "@"); + if (operand[i].exp.X_add_number & 1) + { + as_warn ("branch operand has odd offset (%x)\n", + operand->exp.X_add_number); + } + fix_new (frag_now, + output - frag_now->fr_literal, + 4, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + (short) (operand[i].exp.X_add_number), + 0, + R_JMPL1); } - break; - - } } - } - as_bad("invalid operands"); + +} + +/* + try and give an intelligent error message for common and simple to + detect errors + */ + +static void +DEFUN (clever_message, (opcode, operand), + struct h8_opcode *opcode AND + struct h8_op *operand) +{ + struct h8_opcode *scan = opcode; + + /* Find out if there was more than one possible opccode */ + + if ((opcode + 1)->idx != opcode->idx) + { + unsigned int argn; + + /* Only one opcode of this flavour, try and guess which operand + didn't match */ + for (argn = 0; argn < opcode->noperands; argn++) + { + switch (opcode->args.nib[argn]) + { + case RD16: + if (operand[argn].mode != RD16) + { + as_bad ("destination operand must be 16 bit register"); + return; + + } + break; + + case RS8: + + if (operand[argn].mode != RS8) + { + as_bad ("source operand must be 8 bit register"); + return; + } + break; + + case ABS16DST: + if (operand[argn].mode != ABS16DST) + { + as_bad ("destination operand must be 16bit absolute address"); + return; + } + break; + case RD8: + if (operand[argn].mode != RD8) + { + as_bad ("destination operand must be 8 bit register"); + return; + } + break; + + + case ABS16SRC: + if (operand[argn].mode != ABS16SRC) + { + as_bad ("source operand must be 16bit absolute address"); + return; + } + break; + + } + } + } + as_bad ("invalid operands"); } /* This is the guts of the machine-dependent assembler. STR points to a @@ -1005,106 +1101,111 @@ break; -void - DEFUN(md_assemble,(str), - char *str) +void +DEFUN (md_assemble, (str), + char *str) { - char *op_start; - char *op_end; - unsigned int i; - struct h8_op operand[2]; - struct h8_opcode * opcode; - struct h8_opcode * prev_opcode; - - char *dot = 0; - char c; - /* Drop leading whitespace */ - while (*str == ' ') - str++; - - /* find the op code end */ - for (op_start = op_end = str; - *op_end != 0 && *op_end != ' '; - op_end ++) - { - if (*op_end == '.') { - dot = op_end+1; - *op_end = 0; - op_end+=2; - break; - } - } - - ; - - if (op_end == op_start) - { - as_bad("can't find opcode "); - } - c = *op_end; - - *op_end = 0; - - opcode = (struct h8_opcode *) hash_find(opcode_hash_control, - op_start); - - if (opcode == NULL) - { - as_bad("unknown opcode"); - return; - } - - - input_line_pointer = get_operands(opcode->noperands, op_end, - operand); - *op_end = c; - prev_opcode = opcode; - - opcode = get_specific(opcode, operand); - - if (opcode == 0) - { - /* Couldn't find an opcode which matched the operands */ - char *where =frag_more(2); - where[0] = 0x0; - where[1] = 0x0; - clever_message(prev_opcode, operand); - - return; - } - if (opcode->size && dot) - { - if (opcode->size != *dot) - { - as_warn("mismatch between opcode size and operand size"); - } - } - - build_bytes(opcode, operand); - + char *op_start; + char *op_end; + unsigned int i; + struct h8_op operand[2]; + struct h8_opcode *opcode; + struct h8_opcode *prev_opcode; + + char *dot = 0; + char c; + + /* Drop leading whitespace */ + while (*str == ' ') + str++; + + /* find the op code end */ + for (op_start = op_end = str; + *op_end != 0 && *op_end != ' '; + op_end++) + { + if (*op_end == '.') + { + dot = op_end + 1; + *op_end = 0; + op_end += 2; + break; + } + } + + ; + + if (op_end == op_start) + { + as_bad ("can't find opcode "); + } + c = *op_end; + + *op_end = 0; + + opcode = (struct h8_opcode *) hash_find (opcode_hash_control, + op_start); + + if (opcode == NULL) + { + as_bad ("unknown opcode"); + return; + } + + + input_line_pointer = get_operands (opcode->noperands, op_end, + operand); + *op_end = c; + prev_opcode = opcode; + + opcode = get_specific (opcode, operand); + + if (opcode == 0) + { + /* Couldn't find an opcode which matched the operands */ + char *where = frag_more (2); + + where[0] = 0x0; + where[1] = 0x0; + clever_message (prev_opcode, operand); + + return; + } + if (opcode->size && dot) + { + if (opcode->size != *dot) + { + as_warn ("mismatch between opcode size and operand size"); + } + } + + build_bytes (opcode, operand); + } -void - DEFUN(tc_crawl_symbol_chain, (headers), - object_headers *headers) +void +DEFUN (tc_crawl_symbol_chain, (headers), + object_headers * headers) { - printf("call to tc_crawl_symbol_chain \n"); + printf ("call to tc_crawl_symbol_chain \n"); } -symbolS *DEFUN(md_undefined_symbol,(name), - char *name) +symbolS * +DEFUN (md_undefined_symbol, (name), + char *name) { - return 0; + return 0; } -void - DEFUN(tc_headers_hook,(headers), - object_headers *headers) +void +DEFUN (tc_headers_hook, (headers), + object_headers * headers) { - printf("call to tc_headers_hook \n"); + printf ("call to tc_headers_hook \n"); } + void - DEFUN_VOID(md_end) +DEFUN_VOID (md_end) { } @@ -1117,212 +1218,250 @@ void emitted is stored in *sizeP . An error message is returned, or NULL on OK. */ char * - md_atof(type,litP,sizeP) -char type; -char *litP; -int *sizeP; +md_atof (type, litP, sizeP) + char type; + char *litP; + int *sizeP; { - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - char *atof_ieee(); - - switch(type) { - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; - - case 'x': - case 'X': - prec = 6; - break; - - case 'p': - case 'P': - prec = 6; - break; - - default: - *sizeP=0; - return "Bad call to MD_ATOF()"; - } - t=atof_ieee(input_line_pointer,type,words); - if(t) - input_line_pointer=t; - - *sizeP=prec * sizeof(LITTLENUM_TYPE); - for(wordP=words;prec--;) { - md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE)); - litP+=sizeof(LITTLENUM_TYPE); - } - return ""; /* Someone should teach Dean about null pointers */ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + char *atof_ieee (); + + switch (type) + { + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + + case 'x': + case 'X': + prec = 6; + break; + + case 'p': + case 'P': + prec = 6; + break; + + default: + *sizeP = 0; + return "Bad call to MD_ATOF()"; + } + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + + *sizeP = prec * sizeof (LITTLENUM_TYPE); + for (wordP = words; prec--;) + { + md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + return ""; } int - md_parse_option(argP, cntP, vecP) -char **argP; -int *cntP; -char ***vecP; +md_parse_option (argP, cntP, vecP) + char **argP; + int *cntP; + char ***vecP; { - return 0; - + return 0; + } int md_short_jump_size; -void tc_aout_fix_to_chars () { printf("call to tc_aout_fix_to_chars \n"); - abort(); } -void md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) -char *ptr; -long from_addr; -long to_addr; -fragS *frag; -symbolS *to_symbol; +void +tc_aout_fix_to_chars () +{ + printf ("call to tc_aout_fix_to_chars \n"); + abort (); +} + +void +md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr; + addressT to_addr; + fragS *frag; + symbolS *to_symbol; { - as_fatal("failed sanity check."); + as_fatal ("failed sanity check."); } void - md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol) -char *ptr; -long from_addr, to_addr; -fragS *frag; -symbolS *to_symbol; +md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; { - as_fatal("failed sanity check."); + as_fatal ("failed sanity check."); } void - md_convert_frag(headers, fragP) -object_headers *headers; -fragS * fragP; +md_convert_frag (headers, fragP) + object_headers *headers; + fragS *fragP; -{ printf("call to md_convert_frag \n"); abort(); } +{ + printf ("call to md_convert_frag \n"); + abort (); +} -long - DEFUN(md_section_align,(seg, size), - segT seg AND - long size) +valueT +DEFUN (md_section_align, (seg, size), + segT seg AND + valueT size) { - return((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); - + return ((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); + } void - md_apply_fix(fixP, val) -fixS *fixP; -long val; +md_apply_fix (fixP, val) + fixS *fixP; + long val; { - char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; - - switch(fixP->fx_size) { - case 1: - *buf++=val; - break; - case 2: - *buf++=(val>>8); - *buf++=val; - break; - case 4: - *buf++=(val>>24); - *buf++=(val>>16); - *buf++=(val>>8); - *buf++=val; - break; - default: - abort(); - - } + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + + switch (fixP->fx_size) + { + case 1: + *buf++ = val; + break; + case 2: + *buf++ = (val >> 8); + *buf++ = val; + break; + case 4: + *buf++ = (val >> 24); + *buf++ = (val >> 16); + *buf++ = (val >> 8); + *buf++ = val; + break; + default: + abort (); + + } } -void DEFUN(md_operand, (expressionP),expressionS *expressionP) -{ } +void +DEFUN (md_operand, (expressionP), expressionS * expressionP) +{ +} -int md_long_jump_size; +int md_long_jump_size; int - md_estimate_size_before_relax(fragP, segment_type) -register fragS *fragP; -register segT segment_type; -{ - printf("call tomd_estimate_size_before_relax \n"); abort(); } +md_estimate_size_before_relax (fragP, segment_type) + register fragS *fragP; + register segT segment_type; +{ + printf ("call tomd_estimate_size_before_relax \n"); + abort (); +} + /* Put number into target byte order */ -void DEFUN(md_number_to_chars,(ptr, use, nbytes), - char *ptr AND - long use AND - int nbytes) +void +DEFUN (md_number_to_chars, (ptr, use, nbytes), + char *ptr AND + valueT use AND + int nbytes) { - switch (nbytes) { - case 4: *ptr++ = (use >> 24) & 0xff; - case 3: *ptr++ = (use >> 16) & 0xff; - case 2: *ptr++ = (use >> 8) & 0xff; - case 1: *ptr++ = (use >> 0) & 0xff; - break; - default: - abort(); - } + switch (nbytes) + { + case 4: + *ptr++ = (use >> 24) & 0xff; + case 3: + *ptr++ = (use >> 16) & 0xff; + case 2: + *ptr++ = (use >> 8) & 0xff; + case 1: + *ptr++ = (use >> 0) & 0xff; + break; + default: + abort (); + } +} +long +md_pcrel_from (fixP) + fixS *fixP; +{ + abort (); } -long md_pcrel_from(fixP) -fixS *fixP; { abort(); } -void tc_coff_symbol_emit_hook() { } +void +tc_coff_symbol_emit_hook () +{ +} -void tc_reloc_mangle(fix_ptr, intr, base) -fixS *fix_ptr; -struct internal_reloc *intr; -bfd_vma base; +void +tc_reloc_mangle (fix_ptr, intr, base) + fixS *fix_ptr; + struct internal_reloc *intr; + bfd_vma base; { - symbolS *symbol_ptr; - - symbol_ptr = fix_ptr->fx_addsy; - - /* If this relocation is attached to a symbol then it's ok - to output it */ - if (fix_ptr->fx_r_type == RELOC_32) { - /* cons likes to create reloc32's whatever the size of the reloc.. - */ - switch (fix_ptr->fx_size) - { - - case 2: - intr->r_type = R_RELWORD; - break; - case 1: - intr->r_type = R_RELBYTE; - break; - default: - abort(); - - } - - } - else { - intr->r_type = fix_ptr->fx_r_type; + symbolS *symbol_ptr; + + symbol_ptr = fix_ptr->fx_addsy; + + /* If this relocation is attached to a symbol then it's ok + to output it */ + if (fix_ptr->fx_r_type == RELOC_32) + { + /* cons likes to create reloc32's whatever the size of the reloc.. + */ + switch (fix_ptr->fx_size) + { + + case 2: + intr->r_type = R_RELWORD; + break; + case 1: + intr->r_type = R_RELBYTE; + break; + default: + abort (); + } - - intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where +base; - intr->r_offset = fix_ptr->fx_offset; - - if (symbol_ptr) - intr->r_symndx = symbol_ptr->sy_number; - else - intr->r_symndx = -1; - - + + } + else + { + intr->r_type = fix_ptr->fx_r_type; + } + + intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where + base; + intr->r_offset = fix_ptr->fx_offset; + + if (symbol_ptr) + intr->r_symndx = symbol_ptr->sy_number; + else + intr->r_symndx = -1; + + +} + +tc_coff_sizemachdep () +{ + abort (); } /* end of tc-h8300.c */ diff --git a/gas/config/tc-h8500.c b/gas/config/tc-h8500.c index f64a8b6..baf4cb3 100644 --- a/gas/config/tc-h8500.c +++ b/gas/config/tc-h8500.c @@ -1244,8 +1244,8 @@ tc_aout_fix_to_chars () void md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) char *ptr; - long from_addr; - long to_addr; + addressT from_addr; + addressT to_addr; fragS *frag; symbolS *to_symbol; { @@ -1255,7 +1255,7 @@ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) void md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) char *ptr; - long from_addr, to_addr; + addressT from_addr, to_addr; fragS *frag; symbolS *to_symbol; { @@ -1402,10 +1402,10 @@ md_convert_frag (headers, fragP) } -long +valueT DEFUN (md_section_align, (seg, size), segT seg AND - long size) + valueT size) { return ((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); @@ -1506,7 +1506,7 @@ md_estimate_size_before_relax (fragP, segment_type) void md_number_to_chars (ptr, use, nbytes) char *ptr; - long use; + valueT use; int nbytes; { switch (nbytes) diff --git a/gas/config/tc-hppa.c b/gas/config/tc-hppa.c new file mode 100644 index 0000000..581a0bf --- /dev/null +++ b/gas/config/tc-hppa.c @@ -0,0 +1,6941 @@ +/* tc-hppa.c -- Assemble for the PA + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* + HP PA-RISC support was contributed by the Center for Software Science + at the University of Utah. + */ + +#include +#include + +#include "as.h" +#include "subsegs.h" + +/* #include "../bfd/libhppa.h" */ +/* + * Unwind table and descriptor. + */ + +struct unwind_desc + { + unsigned int cannot_unwind:1; + unsigned int millicode:1; + unsigned int millicode_save_rest:1; + unsigned int region_desc:2; + unsigned int save_sr:2; + unsigned int entry_fr:4; /* number saved */ + unsigned int entry_gr:5; /* number saved */ + unsigned int args_stored:1; + unsigned int call_fr:5; + unsigned int call_gr:5; + unsigned int save_sp:1; + unsigned int save_rp:1; + unsigned int save_rp_in_frame:1; + unsigned int extn_ptr_defined:1; + unsigned int cleanup_defined:1; + + unsigned int hpe_interrupt_marker:1; + unsigned int hpux_interrupt_marker:1; + unsigned int reserved:3; + unsigned int frame_size:27; + }; + +typedef struct unwind_desc unwind_descS; + +struct unwind_table + { + unsigned int start_offset; /* starting offset (from SR4) of applicable region */ + unsigned int end_offset; /* ending offset (from SR4) of applicable region */ + unwind_descS descriptor; + }; + +typedef struct unwind_table unwind_tableS; + +/* + * This structure is used by the .callinfo, .enter, .leave pseudo-ops to + * control the entry and exit code they generate. It is also used in + * creation of the correct stack unwind descriptors. + * + * The fields in structure roughly correspond to the arguments available on the + * .callinfo pseudo-op. + */ + +struct call_info + { + int frame; + int entry_sr; + int makes_calls; + int hpux_int; + unwind_tableS ci_unwind; /* the unwind descriptor we are building */ + symbolS *start_symbol; /* name of function (used in relocation info) */ + symbolS *end_symbol; /* temporary symbol used to mark the */ + /* end of the function (used in */ + /* relocation info) */ + fragS *start_frag; /* frag associated w/ start of this function */ + fragS *end_frag; /* frag associated w/ end of this function */ + fragS *start_offset_frag; /* frag for start offset of this descriptor */ + int start_frag_where; /* where in start_offset_frag is start_offset */ + fixS *start_fix; /* fixup for the start_offset */ + fragS *end_offset_frag; /* frag for start offset of this descriptor */ + int end_frag_where; /* where in end_offset_frag is end_offset */ + fixS *end_fix; /* fixup for the end_offset */ + struct call_info *ci_next; /* the next call_info structure */ + }; + +typedef struct call_info call_infoS; + +call_infoS *last_call_info; +call_infoS *call_info_root; +call_descS last_call_desc; + +/* A structure used during assembly of individual instructions */ + +struct pa_it + { + char *error; + unsigned long opcode; + /* symbol_dictS *nlistp; *//*** used to be: struct nlist *nlistp; */ + asymbol *nlistp; + expressionS exp; + int pcrel; + FP_Operand_Format fpof1; /* Floating Point Operand Format, operand 1 */ + FP_Operand_Format fpof2; /* Floating Point Operand Format, operand 2 */ + /* (used only for class 1 instructions -- */ + /* the conversion instructions) */ +#ifdef OBJ_SOM + long field_selector; + unsigned int reloc; + int code; + long arg_reloc; + unwind_descS unwind; +#endif +#ifdef OBJ_ELF + elf32_hppa_reloc_type reloc; + long field_selector; + int format; + long arg_reloc; + unwind_descS unwind; +#endif + }; + +extern struct pa_it the_insn; + +/* careful, this file includes data *declarations* */ +#include "opcode/hppa.h" + +void md_begin (); +void md_end (); +void md_number_to_chars (); +void md_assemble (); +char *md_atof (); +void md_convert_frag (); +void md_create_short_jump (); +void md_create_long_jump (); +int md_estimate_size_before_relax (); +void md_number_to_imm (); +void md_number_to_disp (); +void md_number_to_field (); +void md_ri_to_chars (); +void emit_relocations (); +static void pa_ip (); + +const relax_typeS md_relax_table[] = +{0}; +/* handle of the OPCODE hash table */ +static struct hash_control *op_hash = NULL; + +int md_short_jump_size = 4; +int md_long_jump_size = 4; + +/* This array holds the chars that always start a comment. If the + pre-processor is disabled, these aren't very useful */ +const char comment_chars[] = ";"; /* JF removed '|' from comment_chars */ + +const pseudo_typeS + md_pseudo_table[] = +{ + {"align", s_align_bytes, 0}, /* .align 4 means .align to 4-byte boundary */ + {"ALIGN", s_align_bytes, 0}, /* .align 4 means .align to 4-byte boundary */ + {"block", pa_block, 1}, + {"BLOCK", pa_block, 1}, + {"blockz", pa_block, 0}, + {"BLOCKZ", pa_block, 0}, + {"byte", pa_cons, 1}, + {"BYTE", pa_cons, 1}, + {"call", pa_call, 0}, + {"CALL", pa_call, 0}, + {"callinfo", pa_callinfo, 0}, + {"CALLINFO", pa_callinfo, 0}, + {"code", pa_code, 0}, + {"CODE", pa_code, 0}, + {"comm", pa_comm, 0}, + {"COMM", pa_comm, 0}, + {"copyright", pa_copyright, 0}, + {"COPYRIGHT", pa_copyright, 0}, + {"data", pa_data, 0}, + {"DATA", pa_data, 0}, + {"desc", pa_desc, 0}, + {"DESC", pa_desc, 0}, + {"double", pa_float_cons, 'd'}, + {"DOUBLE", pa_float_cons, 'd'}, + {"end", pa_end, 0}, + {"END", pa_end, 0}, + {"enter", pa_enter, 0}, + {"ENTER", pa_enter, 0}, + {"entry", pa_entry, 0}, + {"ENTRY", pa_entry, 0}, + {"equ", pa_equ, 0}, + {"EQU", pa_equ, 0}, + {"exit", pa_exit, 0}, + {"EXIT", pa_exit, 0}, + {"export", pa_export, 0}, + {"EXPORT", pa_export, 0}, + {"fill", pa_fill, 0}, + {"FILL", pa_fill, 0}, + {"float", pa_float_cons, 'f'}, + {"FLOAT", pa_float_cons, 'f'}, + {"half", pa_cons, 2}, + {"HALF", pa_cons, 2}, + {"import", pa_import, 0}, + {"IMPORT", pa_import, 0}, + {"int", pa_cons, 4}, + {"INT", pa_cons, 4}, + {"label", pa_label, 0}, + {"LABEL", pa_label, 0}, + {"lcomm", pa_lcomm, 0}, + {"LCOMM", pa_lcomm, 0}, + {"leave", pa_leave, 0}, + {"LEAVE", pa_leave, 0}, + {"long", pa_cons, 4}, + {"LONG", pa_cons, 4}, + {"lsym", pa_lsym, 0}, + {"LSYM", pa_lsym, 0}, + {"octa", pa_big_cons, 16}, + {"OCTA", pa_big_cons, 16}, + {"org", pa_origin, 0}, + {"ORG", pa_origin, 0}, + {"origin", pa_origin, 0}, + {"ORIGIN", pa_origin, 0}, + {"proc", pa_proc, 0}, + {"PROC", pa_proc, 0}, + {"procend", pa_procend, 0}, + {"PROCEND", pa_procend, 0}, + {"quad", pa_big_cons, 8}, + {"QUAD", pa_big_cons, 8}, + {"reg", pa_equ, 1}, /* very similar to .equ */ + {"REG", pa_equ, 1}, /* very similar to .equ */ + {"short", pa_cons, 2}, + {"SHORT", pa_cons, 2}, + {"single", pa_float_cons, 'f'}, + {"SINGLE", pa_float_cons, 'f'}, + {"space", pa_space, 0}, + {"SPACE", pa_space, 0}, + {"spnum", pa_spnum, 0}, + {"SPNUM", pa_spnum, 0}, + {"string", pa_stringer, 0}, + {"STRING", pa_stringer, 0}, + {"stringz", pa_stringer, 1}, + {"STRINGZ", pa_stringer, 1}, + {"subspa", pa_subspace, 0}, + {"SUBSPA", pa_subspace, 0}, + {"text", pa_text, 0}, + {"TEXT", pa_text, 0}, + {"version", pa_version, 0}, + {"VERSION", pa_version, 0}, + {"word", pa_cons, 4}, + {"WORD", pa_cons, 4}, + {NULL, 0, 0} +}; + +/* This array holds the chars that only start a comment at the beginning of + a line. If the line seems to have the form '# 123 filename' + .line and .file directives will appear in the pre-processed output */ +/* Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. */ +/* Also note that '/*' will always start a comment */ +const char line_comment_chars[] = "#"; + +const char line_separator_chars[] = "!"; + +/* Chars that can be used to separate mant from exp in floating point nums */ +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant */ +/* As in 0f12.456 */ +/* or 0d1.2345e12 */ +const char FLT_CHARS[] = "rRsSfFdDxXpP"; + +/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be + changed in read.c . Ideally it shouldn't have to know about it at all, + but nothing is ideal around here. + */ + +static unsigned char octal[256]; +#ifndef isoctal +#define isoctal(c) octal[c] +#endif +static unsigned char toHex[256]; + +struct pa_it set_insn; /* this structure is defined above */ + +/* SKV 12/22/92. Added prev_insn, prev_fix, and initialized the_insn + so that we can recognize instruction sequences such as (ldil, ble) + and generate the appropriate fixups. */ + +struct pa_it the_insn = +{ + NULL, /* error */ + 0, /* opcode */ + NULL, /* nlistp */ + { + NULL, /* exp.X_add_symbol */ + NULL, /* exp.X_subtract_symbol */ + 0, /* exp.X_add_number */ + NULL /* exp.asection */ + }, + 0, /* pcrel */ + 0, /* fpof1 */ + 0, /* fpof2 */ + 0, /* reloc */ + 0, /* field_selector */ + 0, /* code */ + 0, /* arg_reloc */ + { /* unwind */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + } +}; + +#ifdef OBJ_ELF + +struct pa_it prev_insn; +char prev_str[10] = ""; +fixS *prev_fix = NULL; +fixS *curr_fix = NULL; + +#endif /* OBJ_ELF */ + +#ifdef __STDC__ +void print_insn (struct pa_it *insn); +#else +void print_insn (); +#endif +char *expr_end; + +symbolS *label_symbolP; /* the last label symbol encountered */ +/* saved here in case a .equ is encountered */ +int label_symbol_defined; + +int callinfo_found; /* T if a .callinfo appeared within the current */ +/* procedure definition and F otherwise */ + +int within_entry_exit; /* T if the assembler is currently within a */ +/* .entry/.exit pair and F otherwise */ + +int exit_processing_complete; /* T is the assembler has completed exit */ +/* processing for the current procedure */ +/* and F otherwise */ + +int within_procedure; /* T if the assembler is currently within a */ +/* a procedure definition and F otherwise */ + +void ignore_rest_of_line (); /* a useful function in read.c */ + +/* default space and subspace dictionaries */ + +#define GDB_SYMBOLS GDB_SYMBOLS_SUBSPACE_NAME +#define GDB_STRINGS GDB_STRINGS_SUBSPACE_NAME + +#if defined(OBJ_ELF) +struct default_subspace_dict pa_def_subspaces[] = +{ + {"$CODE$", 0, 1, 0, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, ".text", SUBSEG_CODE}, + {"$DATA$", 0, 1, 0, 0, 0, 0, 24, 0x1f, 0, 8, 1, 1, ".data", SUBSEG_DATA}, + {"$LIT$", 0, 1, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, ".text", SUBSEG_LIT}, + {"$BSS$", 0, 1, 0, 0, 0, 1, 80, 0x1f, 0, 8, 1, 1, ".bss", SUBSEG_BSS}, + {"$UNWIND$", 0, 1, 0, 0, 0, 0, 64, 0x2c, 0, 4, 0, 0, ".hppa_unwind", SUBSEG_UNWIND}, + {GDB_STRINGS, 0, 0, 0, 0, 0, 0, 254, 0x1f, 0, 4, 0, 2, ".stabstr", SUBSEG_GDB_STRINGS}, + {GDB_SYMBOLS, 0, 0, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 2, ".stab", SUBSEG_GDB_SYMBOLS}, + {NULL, 0, 1, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0} +}; + +struct default_space_dict pa_def_spaces[] = +{ + {"$TEXT$", 0, 1, 0, 0, 8, ASEC_NULL, ".text"}, + {"$PRIVATE$", 0, 1, 0, 0, 16, ASEC_NULL, ".data"}, + {GDB_DEBUG_SPACE_NAME, 0, 0, 0, 0, 255, ASEC_NULL, ".stab"}, + {NULL, 0, 0, 0, 0, 0, ASEC_NULL, NULL} +}; +#else +struct default_subspace_dict pa_def_subspaces[] = +{ + {"$CODE$", 0, 1, 0, 0, 0, 0, 24, 0x2c, 0, 8, 0, SEG_TEXT, SUBSEG_CODE}, + {"$DATA$", 0, 1, 0, 0, 0, 0, 24, 0x1f, 0, 8, 1, SEG_DATA, SUBSEG_DATA}, + {"$LIT$", 0, 1, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, SEG_TEXT, SUBSEG_LIT}, + {"$BSS$", 0, 1, 0, 0, 0, 1, 80, 0x1f, 0, 8, 1, SEG_DATA, SUBSEG_BSS}, + {"$UNWIND$", 0, 1, 0, 0, 0, 0, 64, 0x2c, 0, 4, 0, SEG_TEXT, SUBSEG_UNWIND}, + {GDB_STRINGS, 0, 0, 0, 0, 0, 0, 254, 0x1f, 0, 4, 0, SEG_GDB, SUBSEG_GDB_STRINGS + }, + {GDB_SYMBOLS, 0, 0, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, SEG_GDB, SUBSEG_GDB_SYMBOLS + }, + {NULL, 0, 1, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, SEG_GOOF, 0} +}; + +struct default_space_dict pa_def_spaces[] = +{ + {"$TEXT$", 0, 1, 0, 0, 8, SEG_TEXT}, + {"$PRIVATE$", 0, 1, 0, 0, 16, SEG_DATA}, + {GDB_DEBUG_SPACE_NAME, 0, 0, 0, 0, 255, SEG_GDB}, + {NULL, 0, 0, 0, 0, 0, SEG_GOOF} +}; +#endif + +#ifdef USG +#define bcmp(b1,b2,n) memcmp((b1),(b2),(n)) +#define index strchr +#endif + +#ifndef FALSE +#define FALSE (0) +#define TRUE (!FALSE) +#endif /* no FALSE yet */ + +/* + Support for keeping track of the most recent label in each + space. + */ + +/* + PA_PSEUDO_OP_MOVES_PC + + A predicate that returns true if the pseudo-operation or + assembly directive results in a movement in the current + location. All instructions cause movement in the current + location. + */ + +static const char *movers[] = +{ +/* these entries from 'static pseudo_typeS potable[]' in pa-read.c */ + "ascii", "asciz", + "byte", + "comm", + "data", "desc", "double", + "fill", "float", + "globl", + "half", + "int", + "lcomm", "long", "lsym", + "octa", "org", + "quad", + "short", "single", + "text", + "word", +/* these entries from 'pseudo_typeS md_pseudo_table[]' in pa-aux.c */ + "block", "blockz", + "code", "copyright", + "equ", + "origin", + "reg", /* very similar to .equ */ + "string", "stringz", + "version", + NULL /* end sentinel */ +}; + +int +pa_pseudo_op_moves_pc (name) + char *name; +{ + int i = 0; + while (movers[i]) + { + if (strcmp (name, movers[i++]) == 0) + return 1; + } + + return 0; +} + +/* + Support for keeping track of the most recent label in each + space. + */ + +/* XXX: NOTE: label_symbolS is defined in pa.h */ + +label_symbolS *label_symbols_rootP = NULL; + +/* + PA_GET_LABEL + + Returns a pointer to the label_symbolS for the current space. + */ + +label_symbolS * +pa_get_label () +{ + label_symbolS *lssP; + space_dict_chainS *now_sdcP = pa_segment_to_space (now_seg); + + for (lssP = label_symbols_rootP; lssP; lssP = lssP->lss_next) + { + if (now_sdcP == lssP->lss_space && lssP->lss_label) + return lssP; + } + + return (label_symbolS *) NULL; +} + +/* + PA_LABEL_IS_DEFINED + + A predicate to determine whether a useable label is defined in + the current space. + */ + +int +pa_label_is_defined () +{ + return (int) pa_get_label (); +} + +/* + PA_DEFINE_LABEL + + Defines a label for the current space. If one is already defined, + this function will replace it with the new label. + */ + +void +pa_define_label (symbolP) + symbolS *symbolP; +{ + label_symbolS *lssP = pa_get_label (); + space_dict_chainS *now_sdcP = pa_segment_to_space (now_seg); + + if (lssP) + { + lssP->lss_label = symbolP; + } + else + { + lssP = (label_symbolS *) xmalloc (sizeof (label_symbolS)); + lssP->lss_label = symbolP; + lssP->lss_space = now_sdcP; + lssP->lss_next = (label_symbolS *) NULL; + + if (label_symbols_rootP) + { + lssP->lss_next = label_symbols_rootP; + } + label_symbols_rootP = lssP; + } +} + +/* + PA_UNDEFINE_LABEL + + Removes a label definition for the current space. + If there is no label_symbolS entry, then no action is taken. + */ + +void +pa_undefine_label () +{ + label_symbolS *lssP; + label_symbolS *prevP = (label_symbolS *) NULL; + space_dict_chainS *now_sdcP = pa_segment_to_space (now_seg); + + for (lssP = label_symbols_rootP; lssP; lssP = lssP->lss_next) + { + if (now_sdcP == lssP->lss_space && lssP->lss_label) + { + if (prevP) + prevP->lss_next = lssP->lss_next; + else + label_symbols_rootP = lssP->lss_next; + + free (lssP); + break; + } + prevP = lssP; + } +} + +/* end of label symbol support. */ + + +/* An HPPA-specific version of fix_new. This is required because the HPPA */ +/* code needs to keep track of some extra stuff. Each call to fix_new_hppa */ +/* results in the creation of an instance of an hppa_fixS. An hppa_fixS */ +/* stores the extra information along with a pointer to the original fixS. */ + +typedef struct hppa_fix_struct + { + fixS *fx_fixP; + int fx_r_field; + int fx_r_type; + int fx_r_format; + long fx_arg_reloc; + call_infoS *fx_call_infop; + char fx_unwind[8]; + struct hppa_fix_struct *fx_next; + } hppa_fixS; + +hppa_fixS *hppa_fix_root = NULL; + +void +fix_new_hppa (frag, where, size, add_symbol, sub_symbol, offset, pcrel, + r_type, r_field, r_format, arg_reloc, unwind_desc) + fragS *frag; /* Which frag? */ + int where; /* Where in that frag? */ + short int size; /* 1, 2 or 4 usually. */ + symbolS *add_symbol; /* X_add_symbol. */ + symbolS *sub_symbol; /* X_subtract_symbol. */ + long offset; /* X_add_number. */ + int pcrel; /* TRUE if PC-relative relocation. */ +#ifdef BFD_ASSEMBLER + bfd_reloc_code_real_type r_type; /* Relocation type */ +#else + int r_type; /* Relocation type */ +#endif + long r_field; /* F, R, L, etc */ + int r_format; /* 11,12,14,17,21,32, etc */ + long arg_reloc; + char *unwind_desc; +{ + fixS *new_fix = fix_new (frag, where, size, + add_symbol, sub_symbol, + offset, pcrel, r_type); + + hppa_fixS *hppa_fix = (hppa_fixS *) obstack_alloc (¬es, sizeof (hppa_fixS)); + + hppa_fix->fx_fixP = new_fix; + hppa_fix->fx_r_field = r_field; + hppa_fix->fx_r_format = r_format; + hppa_fix->fx_arg_reloc = arg_reloc; + hppa_fix->fx_next = (hppa_fixS *) 0; + hppa_fix->fx_call_infop = last_call_info; + if (unwind_desc) + bcopy (unwind_desc, hppa_fix->fx_unwind, 8); + + if (hppa_fix_root) + hppa_fix->fx_next = hppa_fix_root; + + hppa_fix_root = hppa_fix; + + /* SKV 12/22/92. Added prev_insn, prev_fix, and initialized the_insn + so that we can recognize instruction sequences such as (ldil, ble) + and generate the appropriate fixups. */ + +#ifdef OBJ_ELF + + curr_fix = new_fix; + +#endif /* OBJ_ELF */ +} + +/* Parse a .byte, .word, .long expression for the HPPA. Called by + cons via the TC_PARSE_CONS_EXPRESSION macro. */ + +static int hppa_field_selector; + +void +parse_cons_expression_hppa (exp) + expressionS *exp; +{ + hppa_field_selector = pa_chk_field_selector (&input_line_pointer); + expression (&exp); +} + +/* This fix_new is called by cons via TC_CONS_FIX_NEW. + hppa_field_selector is set by the parse_cons_expression_hppa. */ + +void +cons_fix_new_hppa (frag, where, size, exp) + fragS *frag; /* Which frag? */ + int where; /* Where in that frag? */ + int size; /* 1, 2 or 4 usually. */ + expressionS *exp; /* Expression. */ +{ + unsigned int reloc_type; + + if (is_DP_relative (*exp)) + reloc_type = R_HPPA_GOTOFF; + else if (is_complex (*exp)) + reloc_type = R_HPPA_COMPLEX; + else + reloc_type = R_HPPA; + + if (hppa_field_selector != e_psel && hppa_field_selector != e_fsel) + as_warn("Invalid field selector. Assuming F%%."); + + fix_new_hppa (frag, where, size + exp->X_add_symbol, + exp->X_subtract_symbol, + exp->X_add_number, 0, reloc_type, + hppa_field_selector, 32, 0, (char *) 0); +} + +/* Given a FixS, find the hppa_fixS associated with it. */ +hppa_fixS * +hppa_find_hppa_fix (fix) + fixS *fix; +{ + hppa_fixS *hfP; + + for (hfP = hppa_fix_root; hfP; hfP = hfP->fx_next) + { + if (hfP->fx_fixP == fix) + return hfP; + } + + return (hppa_fixS *) 0; +} + +/* This function is called once, at assembler startup time. It should + set up all the tables, etc. that the MD part of the assembler will need. */ +void +md_begin () +{ + register char *retval = NULL; + int lose = 0; + register unsigned int i = 0; + void pa_spaces_begin (); /* forward declaration */ + + last_call_info = NULL; + call_info_root = NULL; + + pa_spaces_begin (); + + op_hash = hash_new (); + if (op_hash == NULL) + as_fatal ("Virtual memory exhausted"); + + while (i < NUMOPCODES) + { + const char *name = pa_opcodes[i].name; + retval = hash_insert (op_hash, name, &pa_opcodes[i]); + if (retval != NULL && *retval != '\0') + { + as_fatal ("Internal error: can't hash `%s': %s\n", + pa_opcodes[i].name, retval); + lose = 1; + } + do + { + if ((pa_opcodes[i].match & pa_opcodes[i].mask) != pa_opcodes[i].match) + { + fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n", + pa_opcodes[i].name, pa_opcodes[i].args); + lose = 1; + } + ++i; + } + while (i < NUMOPCODES + && !strcmp (pa_opcodes[i].name, name)); + } + + if (lose) + as_fatal ("Broken assembler. No assembly attempted."); + + for (i = '0'; i < '8'; ++i) + octal[i] = 1; + for (i = '0'; i <= '9'; ++i) + toHex[i] = i - '0'; + for (i = 'a'; i <= 'f'; ++i) + toHex[i] = i + 10 - 'a'; + for (i = 'A'; i <= 'F'; ++i) + toHex[i] = i + 10 - 'A'; + +} + +void +md_end () +{ + return; +} + +void +md_assemble (str) + char *str; +{ + char *toP; + + assert (str); + pa_ip (str); + toP = frag_more (4); + /* put out the opcode */ + md_number_to_chars (toP, the_insn.opcode, 4); + + /* put out the symbol-dependent stuff */ +#if defined ( OBJ_SOM ) + if (the_insn.reloc != R_NO_RELOCATION) + { +#else +#if defined ( OBJ_ELF ) + if (the_insn.reloc != R_HPPA_NONE) + { +#endif +#endif + +#if defined(OBJ_ELF) + fix_new_hppa (frag_now, /* which frag */ + (toP - frag_now->fr_literal), /* where */ + 4, /* size */ + the_insn.exp.X_add_symbol, + the_insn.exp.X_subtract_symbol, + the_insn.exp.X_add_number, + the_insn.pcrel, + the_insn.reloc, + the_insn.field_selector, + the_insn.format, + the_insn.arg_reloc, + (char *) 0); +#endif +#ifdef OBJ_SOM + fix_new (frag_now, /* which frag */ + (toP - frag_now->fr_literal), /* where */ + 4, /* size */ + the_insn.exp.X_add_symbol, + the_insn.exp.X_subtract_symbol, + the_insn.exp.X_add_number, + the_insn.pcrel, + the_insn.reloc, + the_insn.field_selector, + the_insn.code, + the_insn.arg_reloc, + (char *) 0); +#endif + } + + /* SKV 12/22/92. Added prev_insn, prev_fix, and initialized the_insn + so that we can recognize instruction sequences such as (ldil, ble) + and generate the appropriate fixups. */ + +#ifdef OBJ_ELF + + prev_insn = the_insn; + strncpy (prev_str, str, 10); + if (prev_insn.reloc = R_HPPA_NONE) + { + prev_fix = NULL; + } + else + { + prev_fix = curr_fix; + } + +#endif /* OBJ_ELF */ +} + +static void +pa_ip (str) + char *str; +{ + char *error_message = ""; + char *s; + const char *args; + char c; + unsigned long i; + struct pa_opcode *insn; + char *argsStart; + unsigned long opcode; + unsigned int mask; + int match = FALSE; + int comma = 0; + + int reg, reg1, reg2, s2, s3; + unsigned int im21, im14, im11, im5; + int m, a, uu, f; + int cmpltr, nullif, flag; + int sfu, cond; + char *name; + char *p, *save_s; + +#ifdef PA_DEBUG + fprintf (stderr, "STATEMENT: \"%s\"\n", str); +#endif + for (s = str; isupper (*s) || islower (*s) || (*s >= '0' && *s <= '3'); ++s) + ; + switch (*s) + { + + case '\0': + break; + + case ',': + comma = 1; + + /*FALLTHROUGH*/ + + case ' ': + *s++ = '\0'; + break; + + default: + as_bad ("Unknown opcode: `%s'", str); + exit (1); + } + + save_s = str; + + while (*save_s) + { + if (isupper (*save_s)) + *save_s = tolower (*save_s); + save_s++; + } + + if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL) + { + as_bad ("Unknown opcode: `%s'", str); + return; + } + if (comma) + { + *--s = ','; + } + argsStart = s; + for (;;) + { + opcode = insn->match; + bzero (&the_insn, sizeof (the_insn)); +#if defined( OBJ_SOM ) + the_insn.reloc = R_NO_RELOCATION; +#else +#if defined ( OBJ_ELF ) + the_insn.reloc = R_HPPA_NONE; +#endif +#endif + /* + * Build the opcode, checking as we go to make + * sure that the operands match + */ + for (args = insn->args;; ++args) + { + + switch (*args) + { + + case '\0': /* end of args */ + if (*s == '\0') + { + match = TRUE; + } + break; + + case '+': + if (*s == '+') + { + ++s; + continue; + } + if (*s == '-') + { + continue; + } + break; + + case '(': /* these must match exactly */ + case ')': + case ',': + case ' ': + if (*s++ == *args) + continue; + break; + + case 'b': /* 5 bit register field at 10 */ + case '^': /* 5 bit control register field at 10 */ + reg = pa_parse_number (&s); + if (reg < 32 && reg >= 0) + { + opcode |= reg << 21; + continue; + } + break; + case 'x': /* 5 bit register field at 15 */ + reg = pa_parse_number (&s); + if (reg < 32 && reg >= 0) + { + opcode |= reg << 16; + continue; + } + break; + case 't': /* 5 bit register field at 31 */ + reg = pa_parse_number (&s); + if (reg < 32 && reg >= 0) + { + opcode |= reg; + continue; + } + break; + case 'T': /* 5 bit field length at 31 (encoded as 32-T) */ + /* + reg = pa_parse_number(&s); + */ + getAbsoluteExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + reg = the_insn.exp.X_add_number; + if (reg <= 32 && reg > 0) + { + opcode |= 32 - reg; + s = expr_end; + continue; + } + } + break; + case '5': /* 5 bit immediate at 15 */ + getAbsoluteExpression (s); + /** PJH: The following 2 calls to as_bad() might eventually **/ + /** want to end up as as_warn(). **/ + if (the_insn.exp.X_add_number > 15) + { + as_bad ("5 bit immediate > 15. Set to 15", + the_insn.exp.X_add_number); + the_insn.exp.X_add_number = 15; + } + else if (the_insn.exp.X_add_number < -16) + { + as_bad ("5 bit immediate < -16. Set to -16", + the_insn.exp.X_add_number); + the_insn.exp.X_add_number = -16; + } + + low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector), + 5, &im5); + opcode |= (im5 << 16); + s = expr_end; + continue; + + case 's': /* 2 bit space identifier at 17 */ + s2 = pa_parse_number (&s); + if (s2 < 4 && s2 >= 0) + { + opcode |= s2 << 14; + continue; + } + break; + case 'S': /* 3 bit space identifier at 18 */ + s3 = pa_parse_number (&s); + if (s3 < 8 && s3 >= 0) + { + dis_assemble_3 (s3, &s3); + opcode |= s3 << 13; + continue; + } + break; + case 'c': /* indexed load completer. */ + uu = 0; + m = 0; + i = 0; + while (*s == ',' && i < 2) + { + s++; + if (strncasecmp (s, "sm", 2) == 0) + { + uu = 1; + m = 1; + s++; + i++; + } + else if (strncasecmp (s, "m", 1) == 0) + m = 1; + else if (strncasecmp (s, "s", 1) == 0) + uu = 1; + else + as_bad ("Unrecognized Indexed Load Completer...assuming 0"); + s++; + i++; + } + if (i > 2) + as_bad ("Illegal Indexed Load Completer Syntax...extras ignored"); + /* pa_skip(&s); */ + while (*s == ' ' || *s == '\t') + s++; + + opcode |= m << 5; + opcode |= uu << 13; + continue; + case 'C': /* short load and store completer */ + a = 0; + m = 0; + if (*s == ',') + { + s++; + if (strncasecmp (s, "ma", 2) == 0) + { + a = 0; + m = 1; + } + else if (strncasecmp (s, "mb", 2) == 0) + { + a = 1; + m = 1; + } + else + as_bad ("Unrecognized Indexed Load Completer...assuming 0"); + s += 2; + } + /* pa_skip(&s); */ + while (*s == ' ' || *s == '\t') + s++; + opcode |= m << 5; + opcode |= a << 13; + continue; + case 'Y': /* Store Bytes Short completer */ + a = 0; + m = 0; + i = 0; + while (*s == ',' && i < 2) + { + s++; + if (strncasecmp (s, "m", 1) == 0) + m = 1; + else if (strncasecmp (s, "b", 1) == 0) + a = 0; + else if (strncasecmp (s, "e", 1) == 0) + a = 1; + else + as_bad ("Unrecognized Store Bytes Short Completer...assuming 0"); + s++; + i++; + } + /** if ( i >= 2 ) **/ + if (i > 2) + as_bad ("Illegal Store Bytes Short Completer...extras ignored"); + while (*s == ' ' || *s == '\t') /* skip to next operand */ + s++; + opcode |= m << 5; + opcode |= a << 13; + continue; + case '<': /* non-negated compare/subtract conditions. */ + cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s); + if (cmpltr < 0) + { + as_bad ("Unrecognized Compare/Subtract Condition: %c", *s); + cmpltr = 0; + } + opcode |= cmpltr << 13; + continue; + case '?': /* negated or non-negated cmp/sub conditions. */ + /* used only by ``comb'' and ``comib'' pseudo-ops */ + save_s = s; + cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s); + if (cmpltr < 0) + { + s = save_s; + cmpltr = pa_parse_neg_cmpsub_cmpltr (&s); + if (cmpltr < 0) + { + as_bad ("Unrecognized Compare/Subtract Condition: %c", *s); + cmpltr = 0; + } + else + { + opcode |= 1 << 27; /* required opcode change to make + COMIBT into a COMIBF or a + COMBT into a COMBF or a + ADDBT into a ADDBF or a + ADDIBT into a ADDIBF */ + } + } + opcode |= cmpltr << 13; + continue; + case '!': /* negated or non-negated add conditions. */ + /* used only by ``addb'' and ``addib'' pseudo-ops */ + save_s = s; + cmpltr = pa_parse_nonneg_add_cmpltr (&s); + if (cmpltr < 0) + { + s = save_s; + cmpltr = pa_parse_neg_add_cmpltr (&s); + if (cmpltr < 0) + { + as_bad ("Unrecognized Compare/Subtract Condition: %c", *s); + cmpltr = 0; + } + else + { + opcode |= 1 << 27; /* required opcode change to make + COMIBT into a COMIBF or a + COMBT into a COMBF or a + ADDBT into a ADDBF or a + ADDIBT into a ADDIBF */ + } + } + opcode |= cmpltr << 13; + continue; + case 'a': /* compare/subtract conditions */ + cmpltr = 0; + f = 0; + save_s = s; + if (*s == ',') + { + cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s); + if (cmpltr < 0) + { + f = 1; + s = save_s; + cmpltr = pa_parse_neg_cmpsub_cmpltr (&s); + if (cmpltr < 0) + { + as_bad ("Unrecognized Compare/Subtract Condition"); + } + } + } + opcode |= cmpltr << 13; + opcode |= f << 12; + continue; + case 'd': /* non-negated add conditions */ + cmpltr = 0; + nullif = 0; + flag = 0; + if (*s == ',') + { + s++; + name = s; + while (*s != ',' && *s != ' ' && *s != '\t') + s += 1; + c = *s; + *s = 0x00; + if (strcmp (name, "=") == 0) + { + cmpltr = 1; + } + else if (strcmp (name, "<") == 0) + { + cmpltr = 2; + } + else if (strcmp (name, "<=") == 0) + { + cmpltr = 3; + } + else if (strcasecmp (name, "nuv") == 0) + { + cmpltr = 4; + } + else if (strcasecmp (name, "znv") == 0) + { + cmpltr = 5; + } + else if (strcasecmp (name, "sv") == 0) + { + cmpltr = 6; + } + else if (strcasecmp (name, "od") == 0) + { + cmpltr = 7; + } + else if (strcasecmp (name, "n") == 0) + { + nullif = 1; + } + else if (strcasecmp (name, "tr") == 0) + { + cmpltr = 0; + flag = 1; + } + else if (strcasecmp (name, "<>") == 0) + { + cmpltr = 1; + flag = 1; + } + else if (strcasecmp (name, ">=") == 0) + { + cmpltr = 2; + flag = 1; + } + else if (strcasecmp (name, ">") == 0) + { + cmpltr = 3; + flag = 1; + } + else if (strcasecmp (name, "uv") == 0) + { + cmpltr = 4; + flag = 1; + } + else if (strcasecmp (name, "vnz") == 0) + { + cmpltr = 5; + flag = 1; + } + else if (strcasecmp (name, "nsv") == 0) + { + cmpltr = 6; + flag = 1; + } + else if (strcasecmp (name, "ev") == 0) + { + cmpltr = 7; + flag = 1; + } + else + as_bad ("Unrecognized Add Condition: %s", name); + *s = c; + } + nullif = pa_parse_nullif (&s); + opcode |= nullif << 1; + opcode |= cmpltr << 13; + opcode |= flag << 12; + continue; + case '&': /* logical instruction conditions */ + cmpltr = 0; + f = 0; + if (*s == ',') + { + s++; + name = s; + while (*s != ',' && *s != ' ' && *s != '\t') + s += 1; + c = *s; + *s = 0x00; + if (strcmp (name, "=") == 0) + { + cmpltr = 1; + } + else if (strcmp (name, "<") == 0) + { + cmpltr = 2; + } + else if (strcmp (name, "<=") == 0) + { + cmpltr = 3; + } + else if (strcasecmp (name, "od") == 0) + { + cmpltr = 7; + } + else if (strcasecmp (name, "tr") == 0) + { + cmpltr = 0; + f = 1; + } + else if (strcmp (name, "<>") == 0) + { + cmpltr = 1; + f = 1; + } + else if (strcmp (name, ">=") == 0) + { + cmpltr = 2; + f = 1; + } + else if (strcmp (name, ">") == 0) + { + cmpltr = 3; + f = 1; + } + else if (strcasecmp (name, "ev") == 0) + { + cmpltr = 7; + f = 1; + } + else + as_bad ("Unrecognized Logical Instruction Condition: %s", name); + *s = c; + } + opcode |= cmpltr << 13; + opcode |= f << 12; + continue; + case 'U': /* unit instruction conditions */ + cmpltr = 0; + f = 0; + if (*s == ',') + { + s++; + if (strncasecmp (s, "sbz", 3) == 0) + { + cmpltr = 2; + s += 3; + } + else if (strncasecmp (s, "shz", 3) == 0) + { + cmpltr = 3; + s += 3; + } + else if (strncasecmp (s, "sdc", 3) == 0) + { + cmpltr = 4; + s += 3; + } + else if (strncasecmp (s, "sbc", 3) == 0) + { + cmpltr = 6; + s += 3; + } + else if (strncasecmp (s, "shc", 3) == 0) + { + cmpltr = 7; + s += 3; + } + else if (strncasecmp (s, "tr", 2) == 0) + { + cmpltr = 0; + f = 1; + s += 2; + } + else if (strncasecmp (s, "nbz", 3) == 0) + { + cmpltr = 2; + f = 1; + s += 3; + } + else if (strncasecmp (s, "nhz", 3) == 0) + { + cmpltr = 3; + f = 1; + s += 3; + } + else if (strncasecmp (s, "ndc", 3) == 0) + { + cmpltr = 4; + f = 1; + s += 3; + } + else if (strncasecmp (s, "nbc", 3) == 0) + { + cmpltr = 6; + f = 1; + s += 3; + } + else if (strncasecmp (s, "nhc", 3) == 0) + { + cmpltr = 7; + f = 1; + s += 3; + } + else + as_bad ("Unrecognized Logical Instruction Condition: %c", *s); + } + opcode |= cmpltr << 13; + opcode |= f << 12; + continue; + case '>': /* shift/extract/deposit conditions. */ + cmpltr = 0; + if (*s == ',') + { + s++; + name = s; + while (*s != ',' && *s != ' ' && *s != '\t') + s += 1; + c = *s; + *s = 0x00; + if (strcmp (name, "=") == 0) + { + cmpltr = 1; + } + else if (strcmp (name, "<") == 0) + { + cmpltr = 2; + } + else if (strcasecmp (name, "od") == 0) + { + cmpltr = 3; + } + else if (strcasecmp (name, "tr") == 0) + { + cmpltr = 4; + } + else if (strcmp (name, "<>") == 0) + { + cmpltr = 5; + } + else if (strcmp (name, ">=") == 0) + { + cmpltr = 6; + } + else if (strcasecmp (name, "ev") == 0) + { + cmpltr = 7; + } + else + as_bad ("Unrecognized Shift/Extract/Deposit Condition: %s", name); + *s = c; + } + opcode |= cmpltr << 13; + continue; + case '~': /* bvb,bb conditions */ + cmpltr = 0; + if (*s == ',') + { + s++; + if (strncmp (s, "<", 1) == 0) + { + cmpltr = 2; + s++; + } + else if (strncmp (s, ">=", 2) == 0) + { + cmpltr = 6; + s += 2; + } + else + as_bad ("Unrecognized Bit Branch Condition: %c", *s); + } + opcode |= cmpltr << 13; + continue; + case 'V': /* 5 bit immediate at 31 */ + getExpression (s); + low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector), + 5, &im5); + opcode |= im5; + s = expr_end; + continue; + case 'r': /* 5 bit immediate at 31 */ + /* (unsigned value for the break instruction) */ + getExpression (s); + im5 = evaluateAbsolute (the_insn.exp, the_insn.field_selector); + if (im5 > 31 || im5 < 0) + { + as_bad ("Operand out of range. Was: %d. Should be [0..31]. Assuming %d.\n", im5, im5 & 0x1f); + im5 = im5 & 0x1f; + } + opcode |= im5; + s = expr_end; + continue; + case 'R': /* 5 bit immediate at 15 */ + /* (unsigned value for the ssm and rsm instruction) */ + getExpression (s); + im5 = evaluateAbsolute (the_insn.exp, the_insn.field_selector); + if (im5 > 31 || im5 < 0) + { + as_bad ("Operand out of range. Was: %d. Should be [0..31]. Assuming %d.\n", im5, im5 & 0x1f); + im5 = im5 & 0x1f; + } + opcode |= im5 << 16; + s = expr_end; + continue; + case 'i': /* 11 bit immediate at 31 */ +#ifdef OBJ_SOM + getExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector), + 11, &im11); + opcode |= im11; + } + else + { + the_insn.reloc = R_CODE_ONE_SYMBOL; + the_insn.code = 'i'; + the_insn.field_selector = the_insn.exp.field_selector; + } + s = expr_end; + continue; +#else + the_insn.field_selector = pa_chk_field_selector (&s); + getExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector), + 11, &im11); + opcode |= im11; + } + else + { + if (is_DP_relative (the_insn.exp)) + the_insn.reloc = R_HPPA_GOTOFF; + else if (is_PC_relative (the_insn.exp)) + the_insn.reloc = R_HPPA_PCREL_CALL; + else if (is_complex (the_insn.exp)) + the_insn.reloc = R_HPPA_COMPLEX; + else + the_insn.reloc = R_HPPA; + the_insn.format = 11; + } + s = expr_end; + continue; +#endif + case 'j': /* 14 bit immediate at 31 */ +#ifdef OBJ_SOM + getExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + low_sign_unext (evaluateAbsolute (the_insn.exp, field_selector), + 14, &im14); + if (the_insn.exp.field_selector == e_rsel) + opcode |= (im14 & 0xfff); + else + opcode |= im14; + } + else + { + the_insn.reloc = R_CODE_ONE_SYMBOL; + the_insn.code = 'j'; + the_insn.field_selector = the_insn.exp.field_selector; + } + s = expr_end; + continue; +#else + the_insn.field_selector = pa_chk_field_selector (&s); + getExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + low_sign_unext (evaluateAbsolute (the_insn.exp, the_insn.field_selector), + 14, &im14); + if (the_insn.field_selector == e_rsel) + opcode |= (im14 & 0xfff); + else + opcode |= im14; + } + else + { + if (is_DP_relative (the_insn.exp)) + the_insn.reloc = R_HPPA_GOTOFF; + else if (is_PC_relative (the_insn.exp)) + the_insn.reloc = R_HPPA_PCREL_CALL; + else if (is_complex (the_insn.exp)) + the_insn.reloc = R_HPPA_COMPLEX; + else + the_insn.reloc = R_HPPA; + the_insn.format = 14; + } + s = expr_end; + continue; +#endif + + case 'k': /* 21 bit immediate at 31 */ +#ifdef OBJ_SOM + getExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + dis_assemble_21 (evaluateAbsolute (the_insn.exp, the_insn.field_selector), + &im21); + opcode |= im21; + } + else + { + the_insn.reloc = R_CODE_ONE_SYMBOL; + the_insn.code = 'k'; + the_insn.field_selector = the_insn.exp.field_selector; + } + s = expr_end; + continue; +#else + the_insn.field_selector = pa_chk_field_selector (&s); + getExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + dis_assemble_21 (evaluateAbsolute (the_insn.exp, the_insn.field_selector), + &im21); + opcode |= im21; + } + else + { + if (is_DP_relative (the_insn.exp)) + the_insn.reloc = R_HPPA_GOTOFF; + else if (is_PC_relative (the_insn.exp)) + the_insn.reloc = R_HPPA_PCREL_CALL; + else if (is_complex (the_insn.exp)) + the_insn.reloc = R_HPPA_COMPLEX; + else + the_insn.reloc = R_HPPA; + the_insn.format = 21; + } + s = expr_end; + continue; +#endif + + case 'n': /* nullification for branch instructions */ + nullif = pa_parse_nullif (&s); + opcode |= nullif << 1; + continue; + case 'w': /* 12 bit branch displacement */ +#ifdef OBJ_SOM + getExpression (s); + the_insn.pcrel = 1; + if (strcmp (the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name, "L0\001") == 0) + { + unsigned int w1, w, result; + + sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 12, &result); + dis_assemble_12 (result, &w1, &w); + opcode |= ((w1 << 2) | w); + the_insn.exp.X_add_symbol->sy_ref = FALSE; + } + else + { + /* this has to be wrong -- dont know what is right! */ + the_insn.reloc = R_PCREL_CALL; + the_insn.code = 'w'; + the_insn.field_selector = the_insn.exp.field_selector; + the_insn.arg_reloc = last_call_desc.arg_reloc; + bzero (&last_call_desc, sizeof (call_descS)); + } + s = expr_end; + continue; +#else + the_insn.field_selector = pa_chk_field_selector (&s); + getExpression (s); + the_insn.pcrel = 1; + if (strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), "L0\001") == 0) + { + unsigned int w1, w, result; + + sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 12, &result); + dis_assemble_12 (result, &w1, &w); + opcode |= ((w1 << 2) | w); + /* the_insn.exp.X_add_symbol->sy_ref = FALSE; *//* XXX: not sure how to do this in BFD */ + } + else + { + if (is_complex (the_insn.exp)) + the_insn.reloc = R_HPPA_COMPLEX_PCREL_CALL; + else + the_insn.reloc = R_HPPA_PCREL_CALL; + the_insn.format = 12; + the_insn.arg_reloc = last_call_desc.arg_reloc; + bzero (&last_call_desc, sizeof (call_descS)); + } + s = expr_end; + continue; +#endif + case 'W': /* 17 bit branch displacement */ +#if defined(OBJ_ELF) + the_insn.field_selector = pa_chk_field_selector (&s); +#endif + getExpression (s); + the_insn.pcrel = 1; +#ifdef OBJ_SOM + if (strcmp (the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name, "L0\001") == 0) + { + unsigned int w2, w1, w, result; + + sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 17, &result); + dis_assemble_17 (result, &w1, &w2, &w); + opcode |= ((w2 << 2) | (w1 << 16) | w); + the_insn.exp.X_add_symbol->sy_ref = FALSE; + } + else + { + /* this has to be wrong -- dont know what is right! */ + the_insn.reloc = R_PCREL_CALL; + the_insn.code = 'W'; + the_insn.field_selector = the_insn.exp.field_selector; + the_insn.arg_reloc = last_call_desc.arg_reloc; + bzero (&last_call_desc, sizeof (call_descS)); + } +#else + if (the_insn.exp.X_add_symbol) + { + if (strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), "L0\001") == 0) + { + unsigned int w2, w1, w, result; + + sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 17, &result); + dis_assemble_17 (result, &w1, &w2, &w); + opcode |= ((w2 << 2) | (w1 << 16) | w); + } + else + { + if (is_complex (the_insn.exp)) + the_insn.reloc = R_HPPA_COMPLEX_PCREL_CALL; + else + the_insn.reloc = R_HPPA_PCREL_CALL; + the_insn.format = 17; + the_insn.arg_reloc = last_call_desc.arg_reloc; + bzero (&last_call_desc, sizeof (call_descS)); + } + } + else + { + unsigned int w2, w1, w, result; + + sign_unext (the_insn.exp.X_add_number >> 2, 17, &result); + dis_assemble_17 (result, &w1, &w2, &w); + opcode |= ((w2 << 2) | (w1 << 16) | w); + } +#endif + s = expr_end; + continue; + case 'z': /* 17 bit branch displacement (not pc-relative) */ +#if defined(OBJ_ELF) + the_insn.field_selector = pa_chk_field_selector (&s); +#endif + getExpression (s); + the_insn.pcrel = 0; +#ifdef OBJ_SOM + if (strcmp (the_insn.exp.X_add_symbol->sy_nlist.n_un.n_name, "L0\001") == 0) + { + unsigned int w2, w1, w, result; + + sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 17, &result); + dis_assemble_17 (result, &w1, &w2, &w); + opcode |= ((w2 << 2) | (w1 << 16) | w); + the_insn.exp.X_add_symbol->sy_ref = FALSE; + } + else + { + /* this has to be wrong -- dont know what is right! */ + the_insn.reloc = R_PCREL_CALL; + the_insn.code = 'W'; + the_insn.field_selector = the_insn.exp.field_selector; + the_insn.arg_reloc = last_call_desc.arg_reloc; + bzero (&last_call_desc, sizeof (call_descS)); + } +#else + if (the_insn.exp.X_add_symbol) + { + if (strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), "L0\001") == 0) + { + unsigned int w2, w1, w, result; + + sign_unext ((the_insn.exp.X_add_number - 8) >> 2, 17, &result); + dis_assemble_17 (result, &w1, &w2, &w); + opcode |= ((w2 << 2) | (w1 << 16) | w); + } + else + { + if (is_complex (the_insn.exp)) + { + the_insn.reloc = R_HPPA_COMPLEX_ABS_CALL; + } + else + { + the_insn.reloc = R_HPPA_ABS_CALL; + } + /* This could also be part of an instruction sequence of + interest. If so, check to make sure that the previous + instruction's fixup is appropriate. (ble, be instructions + affect the reloc of immediately preceding ldil + instructions.) */ + if (strcasecmp (prev_str, "ldil") == 0 && + prev_insn.exp.X_add_symbol == the_insn.exp.X_add_symbol && + prev_insn.exp.X_subtract_symbol == the_insn.exp.X_subtract_symbol && + prev_insn.exp.X_seg == the_insn.exp.X_seg && + prev_insn.exp.X_add_number == the_insn.exp.X_add_number && + prev_fix != NULL) + prev_fix->fx_r_type = the_insn.reloc; + + the_insn.format = 17; + the_insn.arg_reloc = last_call_desc.arg_reloc; + bzero (&last_call_desc, sizeof (call_descS)); + } + } + else + { + unsigned int w2, w1, w, result; + + sign_unext (the_insn.exp.X_add_number >> 2, 17, &result); + dis_assemble_17 (result, &w1, &w2, &w); + opcode |= ((w2 << 2) | (w1 << 16) | w); + } +#endif + s = expr_end; + continue; + case 'p': /* 5 bit shift count at 26 (to support SHD instr.) */ + /* value is encoded in instr. as 31-p where p is */ + /* the value scanned here */ + getExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + opcode |= (((31 - the_insn.exp.X_add_number) & 0x1f) << 5); + } + s = expr_end; + continue; + case 'P': /* 5-bit bit position at 26 */ + getExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + opcode |= (the_insn.exp.X_add_number & 0x1f) << 5; + } + s = expr_end; + continue; + case 'Q': /* 5 bit immediate at 10 */ + /* (unsigned bit position value for the bb instruction) */ + getExpression (s); + im5 = evaluateAbsolute (the_insn.exp, the_insn.field_selector); + if (im5 > 31 || im5 < 0) + { + as_bad ("Operand out of range. Was: %d. Should be [0..31]. Assuming %d.\n", im5, im5 & 0x1f); + im5 = im5 & 0x1f; + } + opcode |= im5 << 21; + s = expr_end; + continue; + case 'A': /* 13 bit immediate at 18 (to support BREAK instr.) */ + getAbsoluteExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + opcode |= (the_insn.exp.X_add_number & 0x1fff) << 13; + s = expr_end; + continue; + case 'Z': /* System Control Completer(for LDA, LHA, etc.) */ + if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M')) + { + m = 1; + s += 2; + } + else + m = 0; + + opcode |= m << 5; + while (*s == ' ' || *s == '\t') /* skip to next operand */ + s++; + + continue; + case 'D': /* 26 bit immediate at 31 (to support DIAG instr.) */ + /* the action (and interpretation of this operand is + implementation dependent) */ +#if defined(OBJ_ELF) + the_insn.field_selector = pa_chk_field_selector (&s); +#endif + getExpression (s); + if (the_insn.exp.X_seg == &bfd_abs_section) + { + opcode |= ((evaluateAbsolute (the_insn.exp, the_insn.field_selector) & 0x1ffffff) << 1); +#ifdef NEW_SOM /* XXX what replaces this? */ + /* PJH: VERY unsure about the following */ + the_insn.field_selector = the_insn.exp.field_selector; +#endif + } + else + as_bad ("Illegal DIAG operand"); + s = expr_end; + continue; + case 'f': /* 3 bit Special Function Unit (SFU) identifier at 25 */ + sfu = pa_parse_number (&s); + if ((sfu > 7) || (sfu < 0)) + as_bad ("Illegal SFU identifier: %02x", sfu); + opcode |= (sfu & 7) << 6; + continue; + case 'O': /* 20 bit SFU op. split between 15 bits at 20 + and 5 bits at 31 */ + getExpression (s); + s = expr_end; + continue; + case 'o': /* 15 bit Special Function Unit operation at 20 */ + getExpression (s); + s = expr_end; + continue; + case '2': /* 22 bit SFU op. split between 17 bits at 20 + and 5 bits at 31 */ + getExpression (s); + s = expr_end; + continue; + case '1': /* 15 bit SFU op. split between 10 bits at 20 + and 5 bits at 31 */ + getExpression (s); + s = expr_end; + continue; + case '0': /* 10 bit SFU op. split between 5 bits at 20 + and 5 bits at 31 */ + getExpression (s); + s = expr_end; + continue; + case 'u': /* 3 bit coprocessor unit identifier at 25 */ + getExpression (s); + s = expr_end; + continue; + case 'F': /* Source FP Operand Format Completer (2 bits at 20) */ + f = pa_parse_fp_format (&s); + opcode |= (int) f << 11; + the_insn.fpof1 = f; + continue; + case 'G': /* Destination FP Operand Format Completer (2 bits at 18) */ + s--; /* need to pass the previous comma to pa_parse_fp_format */ + f = pa_parse_fp_format (&s); + opcode |= (int) f << 13; + the_insn.fpof2 = f; + continue; + case 'M': /* FP Compare Conditions (encoded as 5 bits at 31) */ + cond = pa_parse_fp_cmp_cond (&s); + opcode |= cond; + continue; + + case 'v': /* a 't' type extended to handle L/R register halves. */ + { + struct pa_89_fp_reg_struct result; + int status; + + pa_89_parse_number (&s, &result); + if (result.number_part < 32 && result.number_part >= 0) + { + opcode |= (result.number_part & 0x1f); + + /* 0x30 opcodes are FP arithmetic operation opcodes */ + /* load/store FP opcodes do not get converted to 0x38 */ + /* opcodes like the 0x30 opcodes do */ + if (need_89_opcode (&the_insn, &result)) + { + if ((opcode & 0xfc000000) == 0x30000000) + { + opcode |= (result.L_R_select & 1) << 6; + opcode |= 1 << 27; + } + else + { + opcode |= (result.L_R_select & 1) << 6; + } + } + continue; + } + } + break; + case 'E': /* a 'b' type extended to handle L/R register halves. */ + { + struct pa_89_fp_reg_struct result; + int status; + + pa_89_parse_number (&s, &result); + if (result.number_part < 32 && result.number_part >= 0) + { + opcode |= (result.number_part & 0x1f) << 21; + if (need_89_opcode (&the_insn, &result)) + { + opcode |= (result.L_R_select & 1) << 7; + opcode |= 1 << 27; + } + continue; + } + } + break; + + case 'X': /* an 'x' type extended to handle L/R register halves. */ + { + struct pa_89_fp_reg_struct result; + int status; + + + pa_89_parse_number (&s, &result); + if (result.number_part < 32 && result.number_part >= 0) + { + opcode |= (result.number_part & 0x1f) << 16; + if (need_89_opcode (&the_insn, &result)) + { + opcode |= (result.L_R_select & 1) << 12; + opcode |= 1 << 27; + } + continue; + } + } + break; + + case '4': /* 5 bit register field at 10 + (used in 'fmpyadd' and 'fmpysub') */ + { + struct pa_89_fp_reg_struct result; + int status; + + status = pa_89_parse_number (&s, &result); + if (result.number_part < 32 && result.number_part >= 0) + { + if (the_insn.fpof1 == SGL) + { + result.number_part &= 0xF; + result.number_part |= (result.L_R_select & 1) << 4; + } + opcode |= result.number_part << 21; + continue; + } + } + break; + + case '6': /* 5 bit register field at 15 + (used in 'fmpyadd' and 'fmpysub') */ + { + struct pa_89_fp_reg_struct result; + int status; + + status = pa_89_parse_number (&s, &result); + if (result.number_part < 32 && result.number_part >= 0) + { + if (the_insn.fpof1 == SGL) + { + result.number_part &= 0xF; + result.number_part |= (result.L_R_select & 1) << 4; + } + opcode |= result.number_part << 16; + continue; + } + } + break; + + case '7': /* 5 bit register field at 31 + (used in 'fmpyadd' and 'fmpysub') */ + { + struct pa_89_fp_reg_struct result; + int status; + + status = pa_89_parse_number (&s, &result); + if (result.number_part < 32 && result.number_part >= 0) + { + if (the_insn.fpof1 == SGL) + { + result.number_part &= 0xF; + result.number_part |= (result.L_R_select & 1) << 4; + } + opcode |= result.number_part; + continue; + } + } + break; + + case '8': /* 5 bit register field at 20 + (used in 'fmpyadd' and 'fmpysub') */ + { + struct pa_89_fp_reg_struct result; + int status; + + status = pa_89_parse_number (&s, &result); + if (result.number_part < 32 && result.number_part >= 0) + { + if (the_insn.fpof1 == SGL) + { + result.number_part &= 0xF; + result.number_part |= (result.L_R_select & 1) << 4; + } + opcode |= result.number_part << 11; + continue; + } + } + break; + + case '9': /* 5 bit register field at 25 + (used in 'fmpyadd' and 'fmpysub') */ + { + struct pa_89_fp_reg_struct result; + int status; + + status = pa_89_parse_number (&s, &result); + if (result.number_part < 32 && result.number_part >= 0) + { + if (the_insn.fpof1 == SGL) + { + result.number_part &= 0xF; + result.number_part |= (result.L_R_select & 1) << 4; + } + opcode |= result.number_part << 6; + continue; + } + } + break; + + case 'H': /* Floating Point Operand Format at 26 for */ + /* 'fmpyadd' and 'fmpysub' (very similar to 'F') */ + /* bits are switched from other FP Operand */ + /* formats. 1=SGL, 1=, 0=DBL */ + f = pa_parse_fp_format (&s); + switch (f) + { + case SGL: + opcode |= 0x20; + case DBL: + the_insn.fpof1 = f; + continue; + + case QUAD: + case ILLEGAL_FMT: + default: + as_bad ("Illegal Floating Point Operand Format for this instruction: '%s'", *s); + } + break; + + default: + abort (); + } + break; + } + error: + if (match == FALSE) + { + /* Args don't match. */ + if (&insn[1] - pa_opcodes < NUMOPCODES + && !strcmp (insn->name, insn[1].name)) + { + ++insn; + s = argsStart; + continue; + } + else + { + as_bad ("Illegal operands %s", error_message); + return; + } + } + break; + } + + the_insn.opcode = opcode; + +#ifdef PA_DEBUG + if (the_insn.exp.X_add_symbol && the_insn.exp.X_subtract_symbol) + print_insn_short (&the_insn); + fprintf (stderr, "*********** END OF STATEMENT\n"); +#endif + + return; +} + +/* + This is identical to the md_atof in m68k.c. I think this is right, + but I'm not sure. + + Turn a string in input_line_pointer into a floating point constant of type + type, and store the appropriate bytes in *litP. The number of LITTLENUMS + emitted is stored in *sizeP . An error message is returned, or NULL on OK. + */ + +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +char * +md_atof (type, litP, sizeP) + char type; + char *litP; + int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + char *atof_ieee (); + + switch (type) + { + + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + + case 'x': + case 'X': + prec = 6; + break; + + case 'p': + case 'P': + prec = 6; + break; + + default: + *sizeP = 0; + return "Bad call to MD_ATOF()"; + } + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + *sizeP = prec * sizeof (LITTLENUM_TYPE); + for (wordP = words; prec--;) + { + md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + return ""; /* Someone should teach Dean about null pointers */ +} + +/* + * Write out big-endian. + */ +void +md_number_to_chars (buf, val, n) + char *buf; + valueT val; + int n; +{ + + switch (n) + { + + case 4: + *buf++ = val >> 24; + *buf++ = val >> 16; + case 2: + *buf++ = val >> 8; + case 1: + *buf = val; + break; + + default: + abort (); + } + return; +} + +void +md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; +{ + fprintf (stderr, "pa_create_short_jmp\n"); + abort (); +} + +void +md_number_to_disp (buf, val, n) + char *buf; + long val; + int n; +{ + fprintf (stderr, "md_number_to_disp\n"); + abort (); +} + +void +md_number_to_field (buf, val, fix) + char *buf; + long val; + void *fix; +{ + fprintf (stderr, "pa_number_to_field\n"); + abort (); +} + +/* the bit-field entries in the relocation_info struct plays hell + with the byte-order problems of cross-assembly. So as a hack, + I added this mach. dependent ri twiddler. Ugly, but it gets + you there. -KWK */ +/* on sparc: first 4 bytes are normal unsigned long address, next three + bytes are index, most sig. byte first. Byte 7 is broken up with + bit 7 as external, bits 6 & 5 unused, and the lower + five bits as relocation type. Next 4 bytes are long int addend. */ +/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */ + +#ifdef OBJ_SOM +void +md_ri_to_chars (ri_p, ri) + struct reloc_info_pa *ri_p, ri; +{ + unsigned char the_bytes[sizeof (*ri_p)]; +#if defined(OBJ_SOM) | defined(OBJ_OSFROSE) | defined(OBJ_ELF) + /* not sure what, if any, changes are required for new-style cross-assembly */ +#else + the_bytes[0] = ((ri.need_data_ref << 7) & 0x80) | ((ri.arg_reloc & 0x03f8) >> 3); + the_bytes[1] = ((ri.arg_reloc & 0x07) << 5) | ri.expression_type; + the_bytes[2] = ((ri.exec_level << 6) & 0xc0) | ri.fixup_format; + the_bytes[3] = ri.fixup_field & 0xff; + md_number_to_chars (&the_bytes[4], ri.subspace_offset, sizeof (ri.subspace_offset)); + md_number_to_chars (&the_bytes[8], ri.symbol_index_one, sizeof (ri.symbol_index_one)); + md_number_to_chars (&the_bytes[12], ri.symbol_index_two, sizeof (ri.symbol_index_two)); + md_number_to_chars (&the_bytes[16], ri.fixup_constant, sizeof (ri.fixup_constant)); + + /* now put it back where you found it, Junior... */ + bcopy (the_bytes, (char *) ri_p, sizeof (*ri_p)); +#endif + +} + +#endif + + +/* Translate internal representation of relocation info to BFD target + format. */ +/* This may need additional work to make sure that SOM support is complete. */ +#ifdef OBJ_ELF +arelent ** +tc_gen_reloc (section, fixp) + asection *section; + fixS *fixp; +{ + arelent *reloc; + hppa_fixS *hppa_fixp = hppa_find_hppa_fix (fixp); + bfd_reloc_code_real_type code; + static int unwind_reloc_fixp_cnt = 0; + static arelent *unwind_reloc_entryP = NULL; + static arelent *no_relocs = NULL; + arelent **relocs; + bfd_reloc_code_real_type **codes; + int n_relocs; + int i; + + if (fixp->fx_addsy == 0) + return &no_relocs; + assert (hppa_fixp != 0); + assert (section != 0); + + /* unwind section relocations are handled in a special way. */ + /* The relocations for the .unwind section are originally */ + /* built in the usual way. That is, for each unwind table */ + /* entry there are two relocations: one for the beginning of */ + /* the function and one for the end. */ + + /* The first time we enter this function we create a */ + /* relocation of the type R_HPPA_UNWIND_ENTRIES. The addend */ + /* of the relocation is initialized to 0. Each additional */ + /* pair of times this function is called for the unwind */ + /* section represents an additional unwind table entry. Thus, */ + /* the addend of the relocation should end up to be the number */ + /* of unwind table entries. */ + if (strcmp (UNWIND_SECTION_NAME, section->name) == 0) + { + if (unwind_reloc_entryP == NULL) + { + reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent)); + assert (reloc != 0); + unwind_reloc_entryP = reloc; + unwind_reloc_fixp_cnt++; + unwind_reloc_entryP->address = fixp->fx_frag->fr_address + fixp->fx_where; + /* a pointer any function will do. We only */ + /* need one to tell us what section the unwind */ + /* relocations are for. */ + unwind_reloc_entryP->sym_ptr_ptr = &fixp->fx_addsy->bsym; + code = R_HPPA_UNWIND_ENTRIES; + unwind_reloc_entryP->howto = bfd_reloc_type_lookup (stdoutput, code); + unwind_reloc_entryP->addend = unwind_reloc_fixp_cnt / 2; + relocs = (arelent **) bfd_alloc_by_size_t (stdoutput, sizeof (arelent *) * 2); + assert (relocs != 0); + relocs[0] = unwind_reloc_entryP; + relocs[1] = NULL; + return relocs; + } + unwind_reloc_fixp_cnt++; + unwind_reloc_entryP->addend = unwind_reloc_fixp_cnt / 2; + + return &no_relocs; + } + + reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent)); + assert (reloc != 0); + + reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; + /* XXX: might need additional processing here */ + /* hppa_elf_gen_reloc_type() is defined in the */ + /* ELF/PA BFD back-end */ + codes = hppa_elf_gen_reloc_type (stdoutput, + fixp->fx_r_type, + hppa_fixp->fx_r_format, + hppa_fixp->fx_r_field); + + for (n_relocs = 0; codes[n_relocs]; n_relocs++) + ; + + relocs = (arelent **) bfd_alloc_by_size_t (stdoutput, sizeof (arelent *) * n_relocs + 1); + assert (relocs != 0); + + reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent) * n_relocs); + if (n_relocs > 0) + assert (reloc != 0); + + for (i = 0; i < n_relocs; i++) + relocs[i] = &reloc[i]; + + relocs[n_relocs] = NULL; + + switch (fixp->fx_r_type) + { + case R_HPPA_COMPLEX: + case R_HPPA_COMPLEX_PCREL_CALL: + case R_HPPA_COMPLEX_ABS_CALL: + assert (n_relocs == 5); + + for (i = 0; i < n_relocs; i++) + { + reloc[i].sym_ptr_ptr = NULL; + reloc[i].address = 0; + reloc[i].addend = 0; + reloc[i].howto = bfd_reloc_type_lookup (stdoutput, *codes[i]); + assert (reloc[i].howto && *codes[i] == reloc[i].howto->type); + } + + reloc[0].sym_ptr_ptr = &fixp->fx_addsy->bsym; + reloc[1].sym_ptr_ptr = &fixp->fx_subsy->bsym; + reloc[4].address = fixp->fx_frag->fr_address + fixp->fx_where; + + if (fixp->fx_r_type == R_HPPA_COMPLEX) + reloc[3].addend = fixp->fx_addnumber; + else if (fixp->fx_r_type == R_HPPA_COMPLEX_PCREL_CALL || + fixp->fx_r_type == R_HPPA_COMPLEX_ABS_CALL) + reloc[1].addend = fixp->fx_addnumber; + + break; + + default: + assert (n_relocs == 1); + + code = *codes[0]; + + reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; + reloc->howto = bfd_reloc_type_lookup (stdoutput, code); + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->addend = 0; /* default */ + + assert (reloc->howto && code == reloc->howto->type); + + /* Now, do any processing that is dependent on the relocation */ + /* type. */ + switch (code) + { + case R_HPPA_PLABEL_32: + case R_HPPA_PLABEL_11: + case R_HPPA_PLABEL_14: + case R_HPPA_PLABEL_L21: + case R_HPPA_PLABEL_R11: + case R_HPPA_PLABEL_R14: + /* For plabel relocations, the addend of the */ + /* relocation should be either 0 (no static link) or 2 */ + /* (static link required). */ + /* XXX: assume that fx_addnumber contains this */ + /* information */ + reloc->addend = fixp->fx_addnumber; + break; + + case R_HPPA_ABS_CALL_11: + case R_HPPA_ABS_CALL_14: + case R_HPPA_ABS_CALL_17: + case R_HPPA_ABS_CALL_L21: + case R_HPPA_ABS_CALL_R11: + case R_HPPA_ABS_CALL_R14: + case R_HPPA_ABS_CALL_R17: + case R_HPPA_ABS_CALL_LS21: + case R_HPPA_ABS_CALL_RS11: + case R_HPPA_ABS_CALL_RS14: + case R_HPPA_ABS_CALL_RS17: + case R_HPPA_ABS_CALL_LD21: + case R_HPPA_ABS_CALL_RD11: + case R_HPPA_ABS_CALL_RD14: + case R_HPPA_ABS_CALL_RD17: + case R_HPPA_ABS_CALL_LR21: + case R_HPPA_ABS_CALL_RR14: + case R_HPPA_ABS_CALL_RR17: + + case R_HPPA_PCREL_CALL_11: + case R_HPPA_PCREL_CALL_14: + case R_HPPA_PCREL_CALL_17: + case R_HPPA_PCREL_CALL_L21: + case R_HPPA_PCREL_CALL_R11: + case R_HPPA_PCREL_CALL_R14: + case R_HPPA_PCREL_CALL_R17: + case R_HPPA_PCREL_CALL_LS21: + case R_HPPA_PCREL_CALL_RS11: + case R_HPPA_PCREL_CALL_RS14: + case R_HPPA_PCREL_CALL_RS17: + case R_HPPA_PCREL_CALL_LD21: + case R_HPPA_PCREL_CALL_RD11: + case R_HPPA_PCREL_CALL_RD14: + case R_HPPA_PCREL_CALL_RD17: + case R_HPPA_PCREL_CALL_LR21: + case R_HPPA_PCREL_CALL_RR14: + case R_HPPA_PCREL_CALL_RR17: + /* constant is stored in the instruction */ + reloc->addend = ELF32_HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0); + break; + default: + reloc->addend = fixp->fx_addnumber; + break; + } + break; + } + + return relocs; +} + +#else +arelent * +tc_gen_reloc (section, fixp) + asection *section; + fixS *fixp; +{ + arelent *reloc; + hppa_fixS *hppa_fixp = hppa_find_hppa_fix (fixp); + bfd_reloc_code_real_type code; + + if (fixp->fx_addsy == 0) + return 0; + assert (hppa_fixp != 0); + assert (section != 0); + + reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent)); + assert (reloc != 0); + + reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; + /* XXX: might need additional processing here */ + /* hppa_elf_gen_reloc_type() is defined in the */ + /* ELF/PA BFD back-end */ + code = hppa_elf_gen_reloc_type (stdoutput, + fixp->fx_r_type, + hppa_fixp->fx_r_format, + hppa_fixp->fx_r_field); + reloc->howto = bfd_reloc_type_lookup (stdoutput, code); + + assert (code == reloc->howto->type); + + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->addend = 0; /* default */ + + /* Now, do any processing that is dependent on the relocation */ + /* type. (Is there any?) */ + switch (code) + { + default: + reloc->addend = fixp->fx_addnumber; + break; + } + + return reloc; +} + +#endif + +void +md_convert_frag (abfd, sec, fragP) + register bfd *abfd; + register asection *sec; + register fragS *fragP; +{ + unsigned int address; + + if (fragP->fr_type == rs_machine_dependent) + { + switch ((int) fragP->fr_subtype) + { + case 0: + fragP->fr_type = rs_fill; + know (fragP->fr_var == 1); + know (fragP->fr_next); + address = fragP->fr_address + fragP->fr_fix; + if (address % fragP->fr_offset) + { + fragP->fr_offset = + fragP->fr_next->fr_address + - fragP->fr_address + - fragP->fr_fix; + } + else + fragP->fr_offset = 0; + break; + } + } +} + +/* Round up a section size to the appropriate boundary. */ +valueT +md_section_align (segment, size) + asection *segment; + valueT size; +{ + return (size + 7) & ~7; /* Round all sects to multiple of 8 */ +} /* md_section_align() */ + +void +md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; +{ + fprintf (stderr, "pa_create_long_jump\n"); + abort (); +} + +int +/* md_estimate_size_before_relax(fragP, segtype) */ +md_estimate_size_before_relax (fragP, segment) + register fragS *fragP; + asection *segment; +{ + int size; + + size = 0; + + while ((fragP->fr_fix + size) % fragP->fr_offset) + size++; + + return size; +} + +int +md_parse_option (argP, cntP, vecP) + char **argP; + int *cntP; + char ***vecP; +{ + return 1; +} + +/* We have no need to default values of symbols. */ + +/* ARGSUSED */ +symbolS * +md_undefined_symbol (name) + char *name; +{ + return 0; +} /*md_undefined_symbol() */ + +/* Parse an operand that is machine-specific. + We just return without modifying the expression if we have nothing + to do. */ + +/* ARGSUSED */ +void +md_operand (expressionP) + expressionS *expressionP; +{ +} + +/* Apply a fixS to the frags, now that we know the value it ought to + hold. */ + +int +apply_field_selector (value, constant, field_selector) + long value; + long constant; + int field_selector; +{ + /* hppa_field_adjust() is defined in the HPPA target */ + return hppa_field_adjust (value, constant, field_selector); +} + +void +md_apply_fix_1 (fixP, val) + fixS *fixP; + long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + hppa_fixS *hppa_fixP = hppa_find_hppa_fix (fixP); + long new_val; + long result; + unsigned int w1, w2, w; + /* The following routine is defined in the ELF/PA back-end */ + extern unsigned char hppa_elf_insn2fmt (); + + if (hppa_fixP) + { + unsigned long buf_wd = bfd_get_32 (stdoutput, buf); + unsigned char fmt = hppa_elf_insn2fmt (fixP->fx_r_type, buf_wd); + + assert (fixP->fx_r_type < R_HPPA_UNIMPLEMENTED); + assert (fixP->fx_r_type >= R_HPPA_NONE); + + fixP->fx_addnumber = val; /* Remember value for emit_reloc */ + + /* Check if this is an undefined symbol. No relocation can */ + /* possibly be performed in this case. */ + + if ((fixP->fx_addsy && fixP->fx_addsy->bsym->section == &bfd_und_section) + || (fixP->fx_subsy && fixP->fx_subsy->bsym->section == &bfd_und_section)) + return; + + /* Perform some processing particular to unwind */ + /* relocations */ + + if (hppa_fixP->fx_call_infop + && (((fixP == hppa_fixP->fx_call_infop->start_fix) + && (fixP->fx_addsy == + hppa_fixP->fx_call_infop->start_symbol)) + || ((fixP == hppa_fixP->fx_call_infop->end_fix) + && (fixP->fx_addsy == + hppa_fixP->fx_call_infop->end_symbol)) + )) + val += fixP->fx_addsy->sy_frag->fr_address; + + switch (fmt) + { + + case 14: /* all the opcodes with the 'j' operand type */ + new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field); + /* need to check for overflow here */ + + /* mask off 14 bits to be changed */ + /* *(long *)buf = *(long *)buf & 0xffffc000; */ + bfd_put_32 (stdoutput, + bfd_get_32 (stdoutput, buf) & 0xffffc000, + buf); + low_sign_unext (new_val, 14, &result); + break; + + case 21: /* all the opcodes with the 'k' operand type */ + new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field); + /* need to check for overflow here */ + + /* mask off 21 bits to be changed */ + /* *(long *)buf = *(long *)buf & 0xffe00000; */ + bfd_put_32 (stdoutput, + bfd_get_32 (stdoutput, buf) & 0xffe00000, + buf); + dis_assemble_21 (new_val, &result); + break; + + case 11: /* all the opcodes with the 'i' operand type */ + new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field); + /* need to check for overflow here */ + + /* mask off 11 bits to be changed */ + /* *(long *)buf = *(long *)buf & 0xffff800; */ + bfd_put_32 (stdoutput, + bfd_get_32 (stdoutput, buf) & 0xffff800, + buf); + low_sign_unext (new_val, 11, &result); + break; + + case 12: /* all the opcodes with the 'w' operand type */ + new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field); + + /* mask off 11 bits to be changed */ + sign_unext ((new_val - 8) >> 2, 12, &result); + /* *(long *)buf = *(long *)buf & 0xffffe002; */ + bfd_put_32 (stdoutput, + bfd_get_32 (stdoutput, buf) & 0xffffe002, + buf); + + dis_assemble_12 (result, &w1, &w); + result = ((w1 << 2) | w); + break; + + case 17: /* some of the opcodes with the 'W' operand type */ + new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field); + /* need to check for overflow here */ + + /* mask off 17 bits to be changed */ + /* *(long *)buf = *(long *)buf & 0xffe0e002; */ + bfd_put_32 (stdoutput, + bfd_get_32 (stdoutput, buf) & 0xffe0e002, + buf); + sign_unext ((new_val - 8) >> 2, 17, &result); + dis_assemble_17 (result, &w1, &w2, &w); + result = ((w2 << 2) | (w1 << 16) | w); + break; + + case 32: + new_val = apply_field_selector (val, 0, hppa_fixP->fx_r_field); + result = new_val; /* no transformation on result */ + /* *(long *)buf = 0; *//* clear out everything */ + bfd_put_32 (stdoutput, 0, buf); /* clear out everything */ + break; + + case 0: + return; + + default: + as_bad ("bad relocation type/fmt: 0x%02x/0x%02x", + fixP->fx_r_type, fmt); + return; + } + buf[0] |= (result & 0xff000000) >> 24; + buf[1] |= (result & 0x00ff0000) >> 16; + buf[2] |= (result & 0x0000ff00) >> 8; + buf[3] |= result & 0x000000ff; + /* We've now adjusted for fx_addnumber, we can */ + /* forget it now. */ + fixP->fx_addnumber = 0; + } + else + { + printf ("no hppa_fixup entry for this fixup (fixP = 0x%x, type = 0x%x)\n", + fixP, fixP->fx_r_type); + } +} /* md_apply_fix_1() */ + +#ifdef BFD_ASSEMBLER +int +md_apply_fix (fixP, valp) + fixS *fixP; + long *valp; +{ + md_apply_fix_1 (fixP, *valp); + return 1; +} + +#else +void +md_apply_fix (fixP, val) + fixS *fixP; + long val; +{ + md_apply_fix_1 (fixP, val); +} + +#endif + +/* Exactly what point is a PC-relative offset relative TO? + On the PA, they're relative to the address of the offset. + (??? Is this right? FIXME-SOON) */ +long +md_pcrel_from (fixP) + fixS *fixP; +{ + return fixP->fx_where + fixP->fx_frag->fr_address; +} /* md_pcrel_from() */ + +int +is_end_of_statement () +{ + return ((*input_line_pointer == '\n') + || (*input_line_pointer == ';') + || (*input_line_pointer == '!')); +} + +/* pa-aux.c -- Assembler for the PA - PA-RISC specific support routines */ + +struct aux_hdr_list *aux_hdr_root = NULL; + +int print_errors = 1; + +void +pa_skip (s) + char **s; +{ + while (**s == ' ' || **s == '\t') + *s = *s + 1; +} + +int +pa_parse_number (s) + char **s; +{ + int num; + char *name; + char c; + symbolS *sym; + int status; + char *p = *s; + + while (*p == ' ' || *p == '\t') + p = p + 1; + num = -1; /* assume invalid number to begin with */ + if (isdigit (*p)) + { + num = 0; /* now we know it is a number */ + + if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) + { /* hex input */ + p = p + 2; + while (isdigit (*p) || ((*p >= 'a') && (*p <= 'f')) + || ((*p >= 'A') && (*p <= 'F'))) + { + if (isdigit (*p)) + num = num * 16 + *p - '0'; + else if (*p >= 'a' && *p <= 'f') + num = num * 16 + *p - 'a' + 10; + else + num = num * 16 + *p - 'A' + 10; + ++p; + } + } + else + { + while (isdigit (*p)) + { + num = num * 10 + *p - '0'; + ++p; + } + } + } + else if (*p == '%') + { /* could be a pre-defined register */ + num = 0; + name = p; + p++; + c = *p; + /* tege hack: Special case for general registers + as the general code makes a binary search with case translation, + and is VERY slow. */ + if (c == 'r') + { + p++; + if (*p == 'e' && *(p + 1) == 't' && (*(p + 2) == '0' || *(p + 2) == '1')) + { + p += 2; + num = *p - '0' + 28; /* r28 is ret0 */ + p++; + } + else if (!isdigit (*p)) + as_bad ("Undefined register: '%s'. ASSUMING 0", name); + else + { + do + num = num * 10 + *p++ - '0'; + while (isdigit (*p)); + } + } + else + { + while (is_part_of_name (c)) + { + p = p + 1; + c = *p; + } + *p = 0; + status = reg_name_search (name); + if (status >= 0) + num = status; + else + { + if (print_errors) + as_bad ("Undefined register: '%s'. ASSUMING 0", name); + else + num = -1; + } + *p = c; + } + } + else + { + num = 0; + name = p; + c = *p; + while (is_part_of_name (c)) + { + p = p + 1; + c = *p; + } + *p = 0; + if ((sym = symbol_find (name)) != NULL) + { +#ifdef OBJ_SOM + if (sym->pa_sy_type == ST_ABSOLUTE) + { + num = sym->pa_sy_value; +#else + if (S_GET_SEGMENT (sym) == &bfd_abs_section) + { + num = S_GET_VALUE (sym); +#endif + } + else + { + if (print_errors) + as_bad ("Non-absolute constant: '%s'. ASSUMING 0", name); + else + num = -1; + } + } + else + { + if (print_errors) + as_bad ("Undefined absolute constant: '%s'. ASSUMING 0", name); + else + num = -1; + } + *p = c; + } + + *s = p; + return num; +} + +struct pd_reg + { + char *name; + int value; + }; + +/* List of registers that are pre-defined: + + General Registers: + + Name Value Name Value + %r0 0 %r16 16 + %r1 1 %r17 17 + %r2 2 %r18 18 + %r3 3 %r19 19 + %r4 4 %r20 20 + %r5 5 %r21 21 + %r6 6 %r22 22 + %r7 7 %r23 23 + %r8 8 %r24 24 + %r9 9 %r25 25 + %r10 10 %r26 26 + %r11 11 %r27 27 + %r12 12 %r28 28 + %r13 13 %r29 29 + %r14 14 %r30 30 + %r15 15 %r31 31 + + Floating-point Registers: + [NOTE: Also includes L and R versions of these (e.g. %fr19L, %fr19R)] + + Name Value Name Value + %fr0 0 %fr16 16 + %fr1 1 %fr17 17 + %fr2 2 %fr18 18 + %fr3 3 %fr19 19 + %fr4 4 %fr20 20 + %fr5 5 %fr21 21 + %fr6 6 %fr22 22 + %fr7 7 %fr23 23 + %fr8 8 %fr24 24 + %fr9 9 %fr25 25 + %fr10 10 %fr26 26 + %fr11 11 %fr27 27 + %fr12 12 %fr28 28 + %fr13 13 %fr29 29 + %fr14 14 %fr30 30 + %fr15 15 %fr31 31 + + Space Registers: + + Name Value Name Value + %sr0 0 %sr4 4 + %sr1 1 %sr5 5 + %sr2 2 %sr6 6 + %sr3 3 %sr7 7 + + Control registers and their synonyms: + + Names Value + %cr0 %rctr 0 + %cr8 %pidr1 8 + %cr9 %pidr2 9 + %cr10 %ccr 10 + %cr11 %sar 11 + %cr12 %pidr3 12 + %cr13 %pidr4 13 + %cr14 %iva 14 + %cr15 %eiem 15 + %cr16 %itmr 16 + %cr17 %pcsq 17 + %cr18 %pcoq 18 + %cr19 %iir 19 + %cr20 %isr 20 + %cr21 %ior 21 + %cr22 %ipsw 22 + %cr23 %eirr 23 + %cr24 %tr0 %ppda 24 + %cr25 %tr1 %hta 25 + %cr26 %tr2 26 + %cr27 %tr3 27 + %cr28 %tr4 28 + %cr29 %tr5 29 + %cr30 %tr6 30 + %cr31 %tr7 31 + + Miscellaneous registers and their synonyms: + + Names Value + %arg0 26 + %arg1 25 + %arg2 24 + %arg3 23 + %sp 30 + %ret0 28 + %ret1 29 +*/ + +/* This table is sorted. Suitable for searching by a binary search. */ + +static struct pd_reg pre_defined_registers[] = +{ + {"%arg0", 26}, + {"%arg1", 25}, + {"%arg2", 24}, + {"%arg3", 23}, + {"%cr0", 0}, + {"%cr10", 10}, + {"%cr11", 11}, + {"%cr12", 12}, + {"%cr13", 13}, + {"%cr14", 14}, + {"%cr15", 15}, + {"%cr16", 16}, + {"%cr17", 17}, + {"%cr18", 18}, + {"%cr19", 19}, + {"%cr20", 20}, + {"%cr21", 21}, + {"%cr22", 22}, + {"%cr23", 23}, + {"%cr24", 24}, + {"%cr25", 25}, + {"%cr26", 26}, + {"%cr27", 27}, + {"%cr28", 28}, + {"%cr29", 29}, + {"%cr30", 30}, + {"%cr31", 31}, + {"%cr8", 8}, + {"%cr9", 9}, + {"%eiem", 15}, + {"%eirr", 23}, + {"%fr0", 0}, + {"%fr0L", 0}, + {"%fr0R", 0}, + {"%fr1", 1}, + {"%fr10", 10}, + {"%fr10L", 10}, + {"%fr10R", 10}, + {"%fr11", 11}, + {"%fr11L", 11}, + {"%fr11R", 11}, + {"%fr12", 12}, + {"%fr12L", 12}, + {"%fr12R", 12}, + {"%fr13", 13}, + {"%fr13L", 13}, + {"%fr13R", 13}, + {"%fr14", 14}, + {"%fr14L", 14}, + {"%fr14R", 14}, + {"%fr15", 15}, + {"%fr15L", 15}, + {"%fr15R", 15}, + {"%fr16", 16}, + {"%fr16L", 16}, + {"%fr16R", 16}, + {"%fr17", 17}, + {"%fr17L", 17}, + {"%fr17R", 17}, + {"%fr18", 18}, + {"%fr18L", 18}, + {"%fr18R", 18}, + {"%fr19", 19}, + {"%fr19L", 19}, + {"%fr19R", 19}, + {"%fr1L", 1}, + {"%fr1R", 1}, + {"%fr2", 2}, + {"%fr20", 20}, + {"%fr20L", 20}, + {"%fr20R", 20}, + {"%fr21", 21}, + {"%fr21L", 21}, + {"%fr21R", 21}, + {"%fr22", 22}, + {"%fr22L", 22}, + {"%fr22R", 22}, + {"%fr23", 23}, + {"%fr23L", 23}, + {"%fr23R", 23}, + {"%fr24", 24}, + {"%fr24L", 24}, + {"%fr24R", 24}, + {"%fr25", 25}, + {"%fr25L", 25}, + {"%fr25R", 25}, + {"%fr26", 26}, + {"%fr26L", 26}, + {"%fr26R", 26}, + {"%fr27", 27}, + {"%fr27L", 27}, + {"%fr27R", 27}, + {"%fr28", 28}, + {"%fr28L", 28}, + {"%fr28R", 28}, + {"%fr29", 29}, + {"%fr29L", 29}, + {"%fr29R", 29}, + {"%fr2L", 2}, + {"%fr2R", 2}, + {"%fr3", 3}, + {"%fr30", 30}, + {"%fr30L", 30}, + {"%fr30R", 30}, + {"%fr31", 31}, + {"%fr31L", 31}, + {"%fr31R", 31}, + {"%fr3L", 3}, + {"%fr3R", 3}, + {"%fr4", 4}, + {"%fr4L", 4}, + {"%fr4R", 4}, + {"%fr5", 5}, + {"%fr5L", 5}, + {"%fr5R", 5}, + {"%fr6", 6}, + {"%fr6L", 6}, + {"%fr6R", 6}, + {"%fr7", 7}, + {"%fr7L", 7}, + {"%fr7R", 7}, + {"%fr8", 8}, + {"%fr8L", 8}, + {"%fr8R", 8}, + {"%fr9", 9}, + {"%fr9L", 9}, + {"%fr9R", 9}, + {"%hta", 25}, + {"%iir", 19}, + {"%ior", 21}, + {"%ipsw", 22}, + {"%isr", 20}, + {"%itmr", 16}, + {"%iva", 14}, + {"%pcoq", 18}, + {"%pcsq", 17}, + {"%pidr1", 8}, + {"%pidr2", 9}, + {"%pidr3", 12}, + {"%pidr4", 13}, + {"%ppda", 24}, + {"%r0", 0}, + {"%r1", 1}, + {"%r10", 10}, + {"%r11", 11}, + {"%r12", 12}, + {"%r13", 13}, + {"%r14", 14}, + {"%r15", 15}, + {"%r16", 16}, + {"%r17", 17}, + {"%r18", 18}, + {"%r19", 19}, + {"%r2", 2}, + {"%r20", 20}, + {"%r21", 21}, + {"%r22", 22}, + {"%r23", 23}, + {"%r24", 24}, + {"%r25", 25}, + {"%r26", 26}, + {"%r27", 27}, + {"%r28", 28}, + {"%r29", 29}, + {"%r3", 3}, + {"%r30", 30}, + {"%r31", 31}, + {"%r4", 4}, + {"%r4L", 4}, + {"%r4R", 4}, + {"%r5", 5}, + {"%r5L", 5}, + {"%r5R", 5}, + {"%r6", 6}, + {"%r6L", 6}, + {"%r6R", 6}, + {"%r7", 7}, + {"%r7L", 7}, + {"%r7R", 7}, + {"%r8", 8}, + {"%r8L", 8}, + {"%r8R", 8}, + {"%r9", 9}, + {"%r9L", 9}, + {"%r9R", 9}, + {"%rctr", 0}, + {"%ret0", 28}, + {"%ret1", 29}, + {"%sar", 11}, + {"%sp", 30}, + {"%sr0", 0}, + {"%sr1", 1}, + {"%sr2", 2}, + {"%sr3", 3}, + {"%sr4", 4}, + {"%sr5", 5}, + {"%sr6", 6}, + {"%sr7", 7}, + {"%tr0", 24}, + {"%tr1", 25}, + {"%tr2", 26}, + {"%tr3", 27}, + {"%tr4", 28}, + {"%tr5", 29}, + {"%tr6", 30}, + {"%tr7", 31} +}; + +#define REG_NAME_CNT (sizeof(pre_defined_registers) / sizeof(struct pd_reg)) + +int +reg_name_search (name) + char *name; +{ + int x, l, r; + + l = 0; + r = REG_NAME_CNT - 1; + + do + { + x = (l + r) / 2; + if (strcasecmp (name, pre_defined_registers[x].name) < 0) + r = x - 1; + else + l = x + 1; + } + while (!((strcasecmp (name, pre_defined_registers[x].name) == 0) || + (l > r))); + + if (strcasecmp (name, pre_defined_registers[x].name) == 0) + return (pre_defined_registers[x].value); + else + return (-1); + +} + +int +is_pre_defined_register (s) + char *s; +{ + if (reg_name_search (s) >= 0) + return (TRUE); + else + return (FALSE); +} + +int +is_R_select (s) + char *s; +{ + + if (*s == 'R' || *s == 'r') + return (TRUE); + else + return (FALSE); +} + +int +is_L_select (s) + char *s; +{ + + if (*s == 'L' || *s == 'l') + return (TRUE); + else + return (FALSE); +} + +int +need_89_opcode (insn, result) + struct pa_it *insn; + struct pa_89_fp_reg_struct *result; +{ + /* if ( result->L_R_select == 1 || insn->fpof1 == DBL || insn->fpof2 == DBL ) */ + /* if (result->L_R_select == 1 && !(insn->fpof1 == DBL || insn->fpof2 == DBL) ) */ + if (result->L_R_select == 1 && !(insn->fpof1 == DBL && insn->fpof2 == DBL)) + /* if ( insn->fpof1 == DBL || insn->fpof2 == DBL ) */ + return TRUE; + else + return FALSE; +} + +int +pa_89_parse_number (s, result) + char **s; + struct pa_89_fp_reg_struct *result; +{ + int num; + char *name; + char c; + symbolS *sym; + int status; + char *p = *s; + + while (*p == ' ' || *p == '\t') + p = p + 1; + num = -1; /* assume invalid number to begin with */ + result->number_part = -1; + result->L_R_select = -1; + + if (isdigit (*p)) + { + num = 0; /* now we know it is a number */ + + if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) + { /* hex input */ + p = p + 2; + while (isdigit (*p) || ((*p >= 'a') && (*p <= 'f')) + || ((*p >= 'A') && (*p <= 'F'))) + { + if (isdigit (*p)) + num = num * 16 + *p - '0'; + else if (*p >= 'a' && *p <= 'f') + num = num * 16 + *p - 'a' + 10; + else + num = num * 16 + *p - 'A' + 10; + ++p; + } + } + else + { + while (isdigit (*p)) + { + num = num * 10 + *p - '0'; + ++p; + } + } + + result->number_part = num; + + if (is_R_select (p)) + { + result->L_R_select = 1; + ++p; + } + else if (is_L_select (p)) + { + result->L_R_select = 0; + ++p; + } + else + result->L_R_select = 0; + + } + else if (*p == '%') + { /* could be a pre-defined register */ + num = 0; + name = p; + p++; + c = *p; + /* tege hack: Special case for general registers + as the general code makes a binary search with case translation, + and is VERY slow. */ + if (c == 'r') + { + p++; + if (*p == 'e' && *(p + 1) == 't' && (*(p + 2) == '0' || *(p + 2) == '1')) + { + p += 2; + num = *p - '0' + 28; /* r28 is ret0 */ + p++; + } + else if (!isdigit (*p)) + as_bad ("Undefined register: '%s'. ASSUMING 0", name); + else + { + do + num = num * 10 + *p++ - '0'; + while (isdigit (*p)); + } + } + else + { + while (is_part_of_name (c)) + { + p = p + 1; + c = *p; + } + *p = 0; + status = reg_name_search (name); + if (status >= 0) + num = status; + else + { + if (print_errors) + as_bad ("Undefined register: '%s'. ASSUMING 0", name); + else + num = -1; + } + *p = c; + } + + result->number_part = num; + + if (is_R_select (p - 1)) + result->L_R_select = 1; + else if (is_L_select (p - 1)) + result->L_R_select = 0; + else + result->L_R_select = 0; + + } + else + { + num = 0; + name = p; + c = *p; + while (is_part_of_name (c)) + { + p = p + 1; + c = *p; + } + *p = 0; + if ((sym = symbol_find (name)) != NULL) + { +#ifdef OBJ_SOM + if (sym->pa_sy_type == ST_ABSOLUTE) + { + num = sym->pa_sy_value; +#else + if (S_GET_SEGMENT (sym) == &bfd_abs_section) + { + num = S_GET_VALUE (sym); +#endif + } + else + { + if (print_errors) + as_bad ("Non-absolute constant: '%s'. ASSUMING 0", name); + else + num = -1; + } + } + else + { + if (print_errors) + as_bad ("Undefined absolute constant: '%s'. ASSUMING 0", name); + else + num = -1; + } + *p = c; + result->number_part = num; + + if (is_R_select (p - 1)) + result->L_R_select = 1; + else if (is_L_select (p - 1)) + result->L_R_select = 0; + else + result->L_R_select = 0; + + } + + *s = p; + return num; + +} + +int +pa_parse_fp_cmp_cond (s) + char **s; +{ + int cond, i; + struct possibleS + { + char *string; + int cond; + }; + + /* + This table is sorted by order of the length of the string. This is so we + check for <> before we check for <. If we had a <> and checked for < first, + we would get a false match. + */ + static struct possibleS poss[] = + { + {"false?", 0}, + {"false", 1}, + {"true?", 30}, + {"true", 31}, + {"!<=>", 3}, + {"!?>=", 8}, + {"!?<=", 16}, + {"!<>", 7}, + {"!>=", 11}, + {"!?>", 12}, + {"?<=", 14}, + {"!<=", 19}, + {"!?<", 20}, + {"?>=", 22}, + {"!?=", 24}, + {"!=t", 27}, + {"<=>", 29}, + {"=t", 5}, + {"?=", 6}, + {"?<", 10}, + {"<=", 13}, + {"!>", 15}, + {"?>", 18}, + {">=", 21}, + {"!<", 23}, + {"<>", 25}, + {"!=", 26}, + {"!?", 28}, + {"?", 2}, + {"=", 4}, + {"<", 9}, + {">", 17} + }; + + cond = 0; + + for (i = 0; i < 32; i++) + { + if (strncasecmp (*s, poss[i].string, strlen (poss[i].string)) == 0) + { + cond = poss[i].cond; + *s += strlen (poss[i].string); + while (**s == ' ' || **s == '\t') + *s = *s + 1; + return cond; + } + } + + as_bad ("Illegal FP Compare Condition: %c", **s); + return 0; +} + +FP_Operand_Format +pa_parse_fp_format (s) + char **s; +{ + int f; + + f = SGL; + if (**s == ',') + { + *s += 1; + if (strncasecmp (*s, "sgl", 3) == 0) + { + f = SGL; + *s += 4; + } + else if (strncasecmp (*s, "dbl", 3) == 0) + { + f = DBL; + *s += 4; + } + else if (strncasecmp (*s, "quad", 4) == 0) + { + f = QUAD; + *s += 5; + } + else + { + f = ILLEGAL_FMT; + as_bad ("Unrecognized FP Operand Format: %3s", *s); + } + } + while (**s == ' ' || **s == '\t' || **s == 0) + *s = *s + 1; + + return f; +} + +#if defined(OBJ_ELF) +int +pa_chk_field_selector (str) + char **str; +{ + int selector; + struct selector_entry + { + char *prefix; + int field_selector; + }; + static struct selector_entry selector_table[] = + { + {"F'", e_fsel}, + {"F%", e_fsel}, + {"LS'", e_lssel}, + {"LS%", e_lssel}, + {"RS'", e_rssel}, + {"RS%", e_rssel}, + {"L'", e_lsel}, + {"L%", e_lsel}, + {"R'", e_rsel}, + {"R%", e_rsel}, + {"LD'", e_ldsel}, + {"LD%", e_ldsel}, + {"RD'", e_rdsel}, + {"RD%", e_rdsel}, + {"LR'", e_lrsel}, + {"LR%", e_lrsel}, + {"RR'", e_rrsel}, + {"RR%", e_rrsel}, + {"P'", e_psel}, + {"P%", e_psel}, + {"RP'", e_rpsel}, + {"RP%", e_rpsel}, + {"LP'", e_lpsel}, + {"LP%", e_lpsel}, + {"T'", e_tsel}, + {"T%", e_tsel}, + {"RT'", e_rtsel}, + {"RT%", e_rtsel}, + {"LT'", e_ltsel}, + {"LT%", e_ltsel}, + {NULL, e_fsel} + }; + struct selector_entry *tableP; + + selector = e_fsel; + + while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\f') + { + *str = *str + 1; + } + for (tableP = selector_table; tableP->prefix; tableP++) + { + if (strncasecmp (tableP->prefix, *str, strlen (tableP->prefix)) == 0) + { + *str += strlen (tableP->prefix); + selector = tableP->field_selector; + break; + } + } + return selector; +} + +int +getExpression (str) + char *str; +{ + char *save_in; + asection *seg; + + save_in = input_line_pointer; + input_line_pointer = str; + seg = expression (&the_insn.exp); + + if (!(seg == &bfd_abs_section + || seg == &bfd_und_section + || seg == text_section + || seg == data_section + || seg == bss_section + || seg == diff_section + || seg == big_section + || seg == absent_section)) + { + the_insn.error = "bad segment"; + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 1; + } + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 0; +} + +int +getAbsoluteExpression (str) + char *str; +{ + char *save_in; + asection *seg; + + save_in = input_line_pointer; + input_line_pointer = str; + seg = expression (&the_insn.exp); + + if (seg != &bfd_abs_section) + { + the_insn.error = "segment should be ABSOLUTE"; + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 1; + } + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 0; +} + +#else +int +getExpression (str) + char *str; +{ + char *save_in; + segT seg; + + save_in = input_line_pointer; + input_line_pointer = str; + switch (seg = expression (&the_insn.exp)) + { + + case SEG_ABSOLUTE: + case SEG_TEXT: + case SEG_DATA: + case SEG_BSS: + case SEG_UNKNOWN: + case SEG_DIFFERENCE: + case SEG_BIG: + case SEG_GDB: + case SEG_MILLICODE: + case SEG_NONE: + break; + + default: + the_insn.error = "illegal segment"; + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 1; + } + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 0; +} + +int +getAbsoluteExpression (str) + char *str; +{ + char *save_in; + segT seg; + + save_in = input_line_pointer; + input_line_pointer = str; + switch (seg = expression (&the_insn.exp)) + { + + case SEG_ABSOLUTE: + break; + + default: + the_insn.error = "segment should be ABSOLUTE"; + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 1; + } + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 0; +} + +#endif + +int +evaluateAbsolute (exp, field_selector) + expressionS exp; + int field_selector; +{ + int value; + + value = exp.X_add_number; + + if (exp.X_add_symbol) + { + value += S_GET_VALUE (exp.X_add_symbol); + } + if (exp.X_subtract_symbol) + { + value -= S_GET_VALUE (exp.X_subtract_symbol); + } + + switch (field_selector) + { + case e_fsel: /* F : no change */ + break; + + case e_lssel: /* LS : if (bit 21) then add 0x800 + arithmetic shift right 11 bits */ + if (value & 0x00000400) + value += 0x800; + value = (value & 0xfffff800) >> 11; + break; + + case e_rssel: /* RS : Sign extend from bit 21 */ + if (value & 0x00000400) + value |= 0xfffff800; + else + value &= 0x7ff; + break; + + case e_lsel: /* L : Arithmetic shift right 11 bits */ + value = (value & 0xfffff800) >> 11; + break; + + case e_rsel: /* R : Set bits 0-20 to zero */ + value = value & 0x7ff; + break; + + case e_ldsel: /* LD : Add 0x800, arithmetic shift + right 11 bits */ + value += 0x800; + value = (value & 0xfffff800) >> 11; + break; + + case e_rdsel: /* RD : Set bits 0-20 to one */ + value |= 0xfffff800; + break; + + case e_lrsel: /* LR : L with "rounded" constant */ + /* XXX: this isn't right. Need to add a "rounded" constant */ + /* XXX: (presumably from X_add_number) */ + value = (value & 0xfffff800) >> 11; + break; + + case e_rrsel: /* RR : R with "rounded" constant */ + /* XXX: this isn't right. Need to add a "rounded" constant */ + /* XXX: (presumably from X_add_number) */ + value = value & 0x7ff; + break; + + default: + BAD_CASE (field_selector); + break; + } + return value; +} + +int +pa_build_arg_reloc (type_name) + char *type_name; +{ + + if (strncasecmp (type_name, "no", 2) == 0) + { + return 0; + } + if (strncasecmp (type_name, "gr", 2) == 0) + { + return 1; + } + else if (strncasecmp (type_name, "fr", 2) == 0) + { + return 2; + } + else if (strncasecmp (type_name, "fu", 2) == 0) + { + return 3; + } + else + as_bad ("Unrecognized argument location: %s\n", type_name); + + return 0; +} + +unsigned int +pa_align_arg_reloc (reg, arg_reloc) + unsigned int reg; + unsigned int arg_reloc; +{ + unsigned int new_reloc; + + new_reloc = arg_reloc; + switch (reg) + { + case 0: + new_reloc <<= 8; + break; + case 1: + new_reloc <<= 6; + break; + case 2: + new_reloc <<= 4; + break; + case 3: + new_reloc <<= 2; + break; + default: + as_bad ("Illegal argument description: %d", reg); + } + + return new_reloc; +} + +int +pa_parse_nullif (s) + char **s; +{ + int nullif; + + nullif = 0; + if (**s == ',') + { + *s = *s + 1; + if (strncasecmp (*s, "n", 1) == 0) + nullif = 1; + else + { + as_bad ("Unrecognized Nullification: (%c)", **s); + nullif = 0; + } + *s = *s + 1; + } + while (**s == ' ' || **s == '\t') + *s = *s + 1; + + return nullif; +} + +#if 0 +int +pa_parse_nonneg_cmpsub_cmpltr (s) + char **s; +{ + int cmpltr; + char *name; + char c; + + cmpltr = -1; + /** cmpltr = 0; **/ + if (**s == ',') + { + *s += 1; + name = *s; + while (**s != ',' && **s != ' ' && **s != '\t') + *s += 1; + c = **s; + **s = 0x00; + if (strcmp (name, "=") == 0) + { + cmpltr = 1; + } + else if (strcmp (name, "<") == 0) + { + cmpltr = 2; + } + else if (strcmp (name, "<=") == 0) + { + cmpltr = 3; + } + else if (strcmp (name, "<<") == 0) + { + cmpltr = 4; + } + else if (strcmp (name, "<<=") == 0) + { + cmpltr = 5; + } + else if (strcasecmp (name, "sv") == 0) + { + cmpltr = 6; + } + else if (strcasecmp (name, "od") == 0) + { + cmpltr = 7; + } + /** + else + cmpltr = -1; + **/ + **s = c; + } + if (cmpltr >= 0) + { + while (**s == ' ' || **s == '\t') + *s = *s + 1; + } + + return cmpltr; +} + +#endif +int +pa_parse_nonneg_cmpsub_cmpltr (s) + char **s; +{ + int cmpltr; + char *name; + char c; + + cmpltr = 0; + if (**s == ',') + { + *s += 1; + name = *s; + while (**s != ',' && **s != ' ' && **s != '\t') + *s += 1; + c = **s; + **s = 0x00; + if (strcmp (name, "=") == 0) + { + cmpltr = 1; + } + else if (strcmp (name, "<") == 0) + { + cmpltr = 2; + } + else if (strcmp (name, "<=") == 0) + { + cmpltr = 3; + } + else if (strcmp (name, "<<") == 0) + { + cmpltr = 4; + } + else if (strcmp (name, "<<=") == 0) + { + cmpltr = 5; + } + else if (strcasecmp (name, "sv") == 0) + { + cmpltr = 6; + } + else if (strcasecmp (name, "od") == 0) + { + cmpltr = 7; + } + else + cmpltr = -1; + **s = c; + } + if (cmpltr >= 0) + { + while (**s == ' ' || **s == '\t') + *s = *s + 1; + } + + return cmpltr; +} + +int +pa_parse_neg_cmpsub_cmpltr (s) + char **s; +{ + int cmpltr; + char *name; + char c; + + cmpltr = -1; + if (**s == ',') + { + *s += 1; + name = *s; + while (**s != ',' && **s != ' ' && **s != '\t') + *s += 1; + c = **s; + **s = 0x00; + if (strcasecmp (name, "tr") == 0) + { + cmpltr = 0; + } + else if (strcmp (name, "<>") == 0) + { + cmpltr = 1; + } + else if (strcmp (name, ">=") == 0) + { + cmpltr = 2; + } + else if (strcmp (name, ">") == 0) + { + cmpltr = 3; + } + else if (strcmp (name, ">>=") == 0) + { + cmpltr = 4; + } + else if (strcmp (name, ">>") == 0) + { + cmpltr = 5; + } + else if (strcasecmp (name, "nsv") == 0) + { + cmpltr = 6; + } + else if (strcasecmp (name, "ev") == 0) + { + cmpltr = 7; + } + **s = c; + } + if (cmpltr >= 0) + { + while (**s == ' ' || **s == '\t') + *s = *s + 1; + } + + return cmpltr; +} + +int +pa_parse_nonneg_add_cmpltr (s) + char **s; +{ + int cmpltr; + char *name; + char c; + + cmpltr = -1; + if (**s == ',') + { + *s += 1; + name = *s; + while (**s != ',' && **s != ' ' && **s != '\t') + *s += 1; + c = **s; + **s = 0x00; + if (strcmp (name, "=") == 0) + { + cmpltr = 1; + } + else if (strcmp (name, "<") == 0) + { + cmpltr = 2; + } + else if (strcmp (name, "<=") == 0) + { + cmpltr = 3; + } + else if (strcasecmp (name, "nuv") == 0) + { + cmpltr = 4; + } + else if (strcasecmp (name, "znv") == 0) + { + cmpltr = 5; + } + else if (strcasecmp (name, "sv") == 0) + { + cmpltr = 6; + } + else if (strcasecmp (name, "od") == 0) + { + cmpltr = 7; + } + **s = c; + } + if (cmpltr >= 0) + { + while (**s == ' ' || **s == '\t') + *s = *s + 1; + } + + return cmpltr; +} + +int +pa_parse_neg_add_cmpltr (s) + char **s; +{ + int cmpltr; + char *name; + char c; + + cmpltr = -1; + if (**s == ',') + { + *s += 1; + name = *s; + while (**s != ',' && **s != ' ' && **s != '\t') + *s += 1; + c = **s; + **s = 0x00; + if (strcasecmp (name, "tr") == 0) + { + cmpltr = 0; + } + else if (strcmp (name, "<>") == 0) + { + cmpltr = 1; + } + else if (strcmp (name, ">=") == 0) + { + cmpltr = 2; + } + else if (strcmp (name, ">") == 0) + { + cmpltr = 3; + } + else if (strcmp (name, "uv") == 0) + { + cmpltr = 4; + } + else if (strcmp (name, "vnz") == 0) + { + cmpltr = 5; + } + else if (strcasecmp (name, "nsv") == 0) + { + cmpltr = 6; + } + else if (strcasecmp (name, "ev") == 0) + { + cmpltr = 7; + } + **s = c; + } + if (cmpltr >= 0) + { + while (**s == ' ' || **s == '\t') + *s = *s + 1; + } + + return cmpltr; +} + +void +s_seg () +{ + + if (strncmp (input_line_pointer, "\"text\"", 6) == 0) + { + input_line_pointer += 6; + s_text (); + return; + } + if (strncmp (input_line_pointer, "\"data\"", 6) == 0) + { + input_line_pointer += 6; + s_data (); + return; + } + if (strncmp (input_line_pointer, "\"data1\"", 7) == 0) + { + input_line_pointer += 7; + s_data1 (); + return; + } + as_bad ("Unknown segment type"); + demand_empty_rest_of_line (); + return; +} + +void +s_private () +{ + register int temp; + + temp = get_absolute_expression (); +#ifdef OBJ_SOM + subseg_new (SEG_DATA, (subsegT) temp); +#else + subseg_new (".data", (subsegT) temp); +#endif + demand_empty_rest_of_line (); +} + +void +s_data1 () +{ +#ifdef OBJ_SOM + subseg_new (SEG_DATA, 1); +#else + subseg_new (".data", 1); +#endif + demand_empty_rest_of_line (); + return; +} + +void +s_proc () +{ + extern char is_end_of_line[]; + + while (!is_end_of_line[*input_line_pointer]) + { + ++input_line_pointer; + } + ++input_line_pointer; + return; +} + +void +pa_block (z) + int z; +{ + register char *p; + register long int temp_fill; + register long int temp_size; + register int i; + + temp_size = get_absolute_expression (); + + if (z) + { /* fill with zeroes even if not requested to do so. */ + temp_fill = 0; /* HP assembler does this too. */ + } + else + { + temp_fill = 0; + } + + if (temp_size <= 0) + { + as_bad ("size < 0, .block ignored"); + temp_size = 0; + } + p = frag_var (rs_fill, + (int) temp_size, + (int) temp_size, (relax_substateT) 0, (symbolS *) 0, 1, (char *) 0); + bzero (p, (int) temp_size); + + /* convert 2 bytes at a time */ + + for (i = 0; i < temp_size; i += 2) + { + md_number_to_chars (p + i, + temp_fill, + (int) ((temp_size - i) > 2 ? 2 : (temp_size - i))); + } + + pa_undefine_label (); + demand_empty_rest_of_line (); + return; +} + +void +pa_call () +{ + + pa_call_args (&last_call_desc); + demand_empty_rest_of_line (); + return; +} + +void +pa_call_args (call_desc) + register call_descS *call_desc; +{ + register char *name; + register char c; + register char *p; + register int temp; + register unsigned int arg_reloc; + + while (!is_end_of_statement ()) + { + name = input_line_pointer; + c = get_symbol_end (); + if ((strncasecmp (name, "argw", 4) == 0)) + { + temp = atoi (name + 4); + p = input_line_pointer; + *p = c; + input_line_pointer++; + name = input_line_pointer; + c = get_symbol_end (); + arg_reloc = pa_build_arg_reloc (name); + call_desc->arg_reloc |= pa_align_arg_reloc (temp, arg_reloc); + } + else if ((strncasecmp (name, "rtnval", 6) == 0)) + { + p = input_line_pointer; + *p = c; + input_line_pointer++; + name = input_line_pointer; + c = get_symbol_end (); + arg_reloc = pa_build_arg_reloc (name); + call_desc->arg_reloc |= (arg_reloc & 0x3); + } + else + { + as_bad ("Unrecognized .CALL argument: %s", name); + } + p = input_line_pointer; + *p = c; + if (!is_end_of_statement ()) + input_line_pointer++; + } +} + +static int +is_same_frag (frag1P, frag2P) + fragS *frag1P; + fragS *frag2P; +{ + + if (frag1P == NULL) + return (FALSE); + else if (frag2P == NULL) + return (FALSE); + else if (frag1P == frag2P) + return (TRUE); + else if (frag2P->fr_type == rs_fill && frag2P->fr_fix == 0) + is_same_frag (frag1P, frag2P->fr_next); + else + return (FALSE); +} + +#ifdef OBJ_ELF +static void +pa_build_unwind_subspace (call_info) + call_infoS *call_info; +{ + char *unwindP; + asection *seg; + asection *save_seg; + subsegT subseg, save_subseg; + int i; + char c; + char *p; + + subseg = SUBSEG_UNWIND; + seg = bfd_get_section_by_name (stdoutput, UNWIND_SECTION_NAME); + if (seg == ASEC_NULL) + { + seg = bfd_make_section_old_way (stdoutput, UNWIND_SECTION_NAME); + } + bfd_set_section_flags (stdoutput, + seg, + SEC_READONLY | SEC_ALLOC | SEC_LOAD | SEC_RELOC); + + /* callinfo.frame is in bytes and unwind_desc is in 8 byte units */ + call_info->ci_unwind.descriptor.frame_size = call_info->frame / 8; + + /* Now, dump the unwind descriptor to the $UNWIND$ subspace. This + creates a couple of relocations */ + + save_seg = now_seg; + save_subseg = now_subseg; + subseg_new ((char *) seg->name, subseg); + unwindP = (char *) &call_info->ci_unwind; + + p = frag_more (4); + call_info->start_offset_frag = frag_now; + call_info->start_frag_where = p - frag_now->fr_literal; + + /* relocation info. for start offset of the function */ + + fix_new_hppa (frag_now, p - frag_now->fr_literal, 4, + call_info->start_symbol, (symbolS *) NULL, + 0, 0, R_HPPA, e_fsel, 32, 0, (char *) 0); + + /** we need to search for the first relocation involving the start_symbol of **/ + /** this call_info descriptor **/ + + { + fixS *fixP; + + call_info->start_fix = seg_info (now_seg)->fix_root; /* the default */ + for (fixP = call_info->start_fix; fixP; fixP = fixP->fx_next) + { + if (fixP->fx_addsy == call_info->start_symbol + || fixP->fx_subsy == call_info->start_symbol) + { + call_info->start_fix = fixP; + break; + } + } + } + + p = frag_more (4); + call_info->end_offset_frag = frag_now; + call_info->end_frag_where = p - frag_now->fr_literal; + + /* relocation info. for end offset of the function */ + + fix_new_hppa (frag_now, p - frag_now->fr_literal, 4, + call_info->end_symbol, (symbolS *) NULL, + 0, 0, R_HPPA, e_fsel, 32, 0, (char *) 0); + + /** we need to search for the first relocation involving the start_symbol of **/ + /** this call_info descriptor **/ + + { + fixS *fixP; + + call_info->end_fix = seg_info (now_seg)->fix_root; /* the default */ + for (fixP = call_info->end_fix; fixP; fixP = fixP->fx_next) + { + if (fixP->fx_addsy == call_info->end_symbol + || fixP->fx_subsy == call_info->end_symbol) + { + call_info->end_fix = fixP; + break; + } + } + } + + for (i = 8; i < sizeof (unwind_tableS); i++) + { + c = *(unwindP + i); + { + FRAG_APPEND_1_CHAR (c); + } + } + + subseg_new ((char *) save_seg->name, save_subseg); +} + +#else +#ifdef OBJ_SOM +static void +pa_build_unwind_subspace (call_info) + call_infoS *call_info; +{ + space_dict_chainS *spaceP; + subspace_dict_chainS *subspaceP; + char *unwindP; + char defined, loadable, code_only, common, dup_common, is_zero, sort; + int access, space_index, alignment, quadrant; + segT seg, save_seg; + subsegT subseg, save_subseg; + int i; + char c; + char *p; + + defined = 1; + loadable = 1; + code_only = 0; + common = 0; + dup_common = 0; + is_zero = 0; + sort = 0x40; + access = 0x2c; + space_index = 0; + alignment = 8; + quadrant = 0; + subseg = SUBSEG_UNWIND; + seg = SEG_TEXT; + + spaceP = pa_segment_to_space (seg); + + if ((subspaceP = is_defined_subspace ("$UNWIND$", SUBSEG_UNWIND))) + { + update_subspace ("$UNWIND$", defined, loadable, code_only, common, dup_common, + sort, is_zero, access, space_index, alignment, quadrant, + SUBSEG_UNWIND); + } + else + { + subspaceP = create_new_subspace (spaceP, "$UNWIND$", defined, loadable, code_only, + common, dup_common, is_zero, sort, access, + space_index, alignment, quadrant, seg); + } + + + /* callinfo.frame is in bytes and unwind_desc is in 8 byte units */ + call_info->ci_unwind.descriptor.frame_size = call_info->frame / 8; + + /* Now, dump the unwind descriptor to the $UNWIND$ subspace. This + creates a couple of relocations */ + + save_seg = now_seg; + save_subseg = now_subseg; + subseg_new (seg, subseg); + unwindP = (char *) &call_info->ci_unwind; + + p = frag_more (4); + call_info->start_offset_frag = frag_now; + call_info->start_frag_where = p - frag_now->fr_literal; + + /* relocation info. for start offset of the function */ + + fix_new (frag_now, p - frag_now->fr_literal, 4, + call_info->start_symbol, (symbolS *) NULL, + 0, 0, R_DATA_ONE_SYMBOL, e_fsel, 0, 0, (char *) 0); + + /** we need to search for the first relocation involving the start_symbol of **/ + /** this call_info descriptor **/ + + { + fixS *fixP; + + call_info->start_fix = seg_info (now_seg)->fix_root; /* the default */ + for (fixP = call_info->start_fix; fixP; fixP = fixP->fx_next) + { + /* + if ( ( fixP->fx_addsy == call_info->start_symbol || + fixP->fx_subsy == call_info->start_symbol ) + && + ( fixP->fx_frag == call_info->start_symbol->sy_frag ) ) { + */ + if ((fixP->fx_addsy == call_info->start_symbol || + fixP->fx_subsy == call_info->start_symbol) + && + (is_same_frag (fixP->fx_frag, call_info->start_symbol->sy_frag))) + { + call_info->start_fix = fixP; + break; + } + } + } + + p = frag_more (4); + call_info->end_offset_frag = frag_now; + call_info->end_frag_where = p - frag_now->fr_literal; + + /* relocation info. for end offset of the function */ + + fix_new (frag_now, p - frag_now->fr_literal, 4, + call_info->start_symbol, (symbolS *) NULL, + 0, 0, R_DATA_ONE_SYMBOL, e_fsel, 0, 0, (char *) 0); + + /** we need to search for the first relocation involving the start_symbol of **/ + /** this call_info descriptor **/ + + { + fixS *fixP; + + call_info->end_fix = seg_info (now_seg)->fix_root; /* the default */ + for (fixP = call_info->end_fix; fixP; fixP = fixP->fx_next) + { + /* + if ( ( fixP->fx_addsy == call_info->start_symbol || + fixP->fx_subsy == call_info->start_symbol ) + && + ( fixP->fx_frag == call_info->start_symbol->sy_frag ) ) { + */ + if ((fixP->fx_addsy == call_info->start_symbol || + fixP->fx_subsy == call_info->start_symbol) + && + (is_same_frag (fixP->fx_frag, call_info->start_symbol->sy_frag))) + { + call_info->end_fix = fixP; + break; + } + } + } + + for (i = 8; i < sizeof (unwind_tableS); i++) + { + c = *(unwindP + i); + { + FRAG_APPEND_1_CHAR (c); + } + } + + subseg_new (save_seg, save_subseg); + +} + +#endif +#endif + +void +pa_callinfo () +{ + register char *name; + register char c; + register char *p; + register int temp; + register symbolS *symbolP; + + if (!within_procedure) + as_bad (".callinfo is not within a procedure definition"); + + callinfo_found = TRUE; + + while (!is_end_of_statement ()) + { + name = input_line_pointer; + c = get_symbol_end (); + if ((strncasecmp (name, "frame", 5) == 0)) + { + p = input_line_pointer; + *p = c; + input_line_pointer++; + temp = get_absolute_expression (); + if ((temp & 0x3) != 0) + { + as_bad ("FRAME parameter must be a multiple of 8: %d\n", temp); + temp = 0; + } + last_call_info->frame = temp; + } + else if ((strncasecmp (name, "entry_gr", 8) == 0)) + { + p = input_line_pointer; + *p = c; + input_line_pointer++; + temp = get_absolute_expression (); + last_call_info->ci_unwind.descriptor.entry_gr = temp; + } + else if ((strncasecmp (name, "entry_fr", 8) == 0)) + { + p = input_line_pointer; + *p = c; + input_line_pointer++; + temp = get_absolute_expression (); + last_call_info->ci_unwind.descriptor.entry_fr = temp; + } + else if ((strncasecmp (name, "entry_sr", 8) == 0)) + { + p = input_line_pointer; + *p = c; + input_line_pointer++; + temp = get_absolute_expression (); + last_call_info->entry_sr = temp; + } + else if ((strncasecmp (name, "calls", 5) == 0) || + (strncasecmp (name, "caller", 6) == 0)) + { + p = input_line_pointer; + *p = c; + last_call_info->makes_calls = 1; + } + else if ((strncasecmp (name, "no_calls", 8) == 0)) + { + p = input_line_pointer; + *p = c; + last_call_info->makes_calls = 0; + } + else if ((strncasecmp (name, "save_rp", 7) == 0)) + { + p = input_line_pointer; + *p = c; + last_call_info->ci_unwind.descriptor.save_rp = 1; + } + else if ((strncasecmp (name, "save_sp", 7) == 0)) + { + p = input_line_pointer; + *p = c; + last_call_info->ci_unwind.descriptor.save_sp = 1; + } + else if ((strncasecmp (name, "no_unwind", 9) == 0)) + { + p = input_line_pointer; + *p = c; + last_call_info->ci_unwind.descriptor.cannot_unwind = 1; + } + else if ((strncasecmp (name, "hpux_int", 7) == 0)) + { + p = input_line_pointer; + *p = c; + last_call_info->hpux_int = 1; + } + else + { + as_bad ("Unrecognized .CALLINFO argument: %s", name); + } + if (!is_end_of_statement ()) + input_line_pointer++; + } + + demand_empty_rest_of_line (); + return; +} + +void +pa_code () +{ + space_dict_chainS *sdchain; + + if ((sdchain = is_defined_space ("$TEXT$")) == NULL) + { + sdchain = create_new_space (pa_def_spaces[0].name, pa_def_spaces[0].spnum, + pa_def_spaces[0].loadable, pa_def_spaces[0].defined, + pa_def_spaces[0].private, pa_def_spaces[0].sort, + 1, pa_def_spaces[0].segment); + } + + SPACE_DEFINED (sdchain) = 1; +#ifdef OBJ_SOM + + subseg_new (SEG_TEXT, SUBSEG_CODE); +#else + + subseg_new (".text", SUBSEG_CODE); +#endif + + demand_empty_rest_of_line (); + return; +} + +/* + * This is different than the standard GAS s_comm(). On HP9000/800 machines, + * the .comm pseudo-op has the following symtax: + * + *