diff options
author | Mark Eichin <eichin@cygnus> | 1993-07-12 19:42:32 +0000 |
---|---|---|
committer | Mark Eichin <eichin@cygnus> | 1993-07-12 19:42:32 +0000 |
commit | 025b0302439df01169c7d9cb06493bbb53c7ce6b (patch) | |
tree | 25846278d32fbd19b92cdd1fc69ffac86a0d6f23 /gas/config | |
parent | d723cd17d5f3e2db2f32bee905f0632fba4389cf (diff) | |
download | gdb-025b0302439df01169c7d9cb06493bbb53c7ce6b.zip gdb-025b0302439df01169c7d9cb06493bbb53c7ce6b.tar.gz gdb-025b0302439df01169c7d9cb06493bbb53c7ce6b.tar.bz2 |
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
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-h8300.c | 2289 | ||||
-rw-r--r-- | gas/config/tc-h8500.c | 12 | ||||
-rw-r--r-- | gas/config/tc-hppa.c | 6941 | ||||
-rw-r--r-- | gas/config/tc-i386.c | 4 | ||||
-rw-r--r-- | gas/config/tc-i860.c | 2087 | ||||
-rw-r--r-- | gas/config/tc-m68k.c | 29 | ||||
-rw-r--r-- | gas/config/tc-ns32k.c | 57 | ||||
-rw-r--r-- | gas/config/tc-sh.c | 1390 | ||||
-rw-r--r-- | gas/config/tc-tahoe.c | 16 | ||||
-rw-r--r-- | gas/config/tc-vax.c | 21 | ||||
-rw-r--r-- | gas/config/tc-z8k.c | 16 |
11 files changed, 10727 insertions, 2135 deletions
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 <stdio.h> #include "as.h" #include "bfd.h" +#define DEFINE_TABLE +#define h8_opcodes ops #include "opcode/h8300.h" #include <ctype.h> -#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 <stdio.h> +#include <ctype.h> + +#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=<none>, 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: + * + * <label> .comm <length> + * + * where <label> is optional and is a symbol whose address will be the start of + * a block of memory <length> bytes long. <length> must be an absolute expressio +n. + * <length> bytes will be allocated in the current space and subspace. + * + */ + +void +pa_comm () +{ + register char *p; + register int size, i; + register symbolS *symbolP; + register label_symbolS *label_symbolP = pa_get_label (); + + if (label_symbolP) + symbolP = label_symbolP->lss_label; + else + symbolP = NULL; + + SKIP_WHITESPACE (); + if ((size = get_absolute_expression ()) < 0) + { + as_warn (".COMMon length (%d.) <0! Ignored.", size); + ignore_rest_of_line (); + return; + } + + if (symbolP) + { +#ifdef OBJ_SOM + if (symbolP->pa_sy_type == ST_STORAGE && + symbolP->pa_sy_scope == SS_UNSAT) + { + if (symbolP->pa_sy_value != size) + { + as_warn ("Length of .comm \"%s\" is already %d. Not changed to %d.", + symbolP->pa_sy_name, symbolP->pa_sy_value, size); + return; + } + } + else + { + symbolP->pa_sy_value = size; + symbolP->pa_sy_scope = SS_UNSAT; + symbolP->pa_sy_type = ST_STORAGE; + symbolP->sy_ref = sym_def; + } +#endif +#ifdef OBJ_ELF + if (S_IS_DEFINED (symbolP) && S_GET_SEGMENT (symbolP) == bss_section) + { + as_bad ("Ignoring attempt to re-define symbol"); + ignore_rest_of_line (); + return; + } + if (S_GET_VALUE (symbolP)) + { + if (S_GET_VALUE (symbolP) != size) + { + as_warn ("Length of .comm \"%s\" is already %d. Not changed to %d.", + S_GET_NAME (symbolP), S_GET_VALUE (symbolP), size); + return; + } + } + else + { + S_SET_VALUE (symbolP, size); + S_SET_SEGMENT (symbolP, bss_section); + S_SET_EXTERNAL (symbolP); + } +#endif + } + + + demand_empty_rest_of_line (); +} + +void +pa_copyright () +{ + register char *name; + register char c; + register char *p; + register int temp; + register symbolS *symbolP; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '\"') + { + ++input_line_pointer; /* -> 1st char of string. */ + name = input_line_pointer; + while ((c = next_char_of_string ()) >= 0) + ; + c = *input_line_pointer; + *input_line_pointer = '\0'; + *(input_line_pointer - 1) = '\0'; + { +#ifdef OBJ_SOM +#define PREFIX "Copyright " +#define MIDFIX ". All rights reserved. No part of this program may be photocopied, reproduced, or transmitted without prior written consent of " +#define SUFFIX "." + + struct aux_hdr_list *aux_hdr_entry; + int len; + char *company_name = name; + char *date_part; + + date_part = (char *) index (name, ','); + if (date_part) + { + *date_part = 0x00; + date_part++; + } + + len = + strlen (PREFIX) + + strlen (MIDFIX) + + strlen (SUFFIX) + + 2 * strlen (name); + + if (date_part) + { + len += strlen (date_part) + strlen (","); + } + + aux_hdr_entry = (struct aux_hdr_list *) malloc (sizeof (struct aux_hdr_list)); + if (aux_hdr_root) + { + aux_hdr_entry->ahl_next = aux_hdr_root; + aux_hdr_root = aux_hdr_entry; + } + else + { + aux_hdr_entry->ahl_next = NULL; + aux_hdr_root = aux_hdr_entry; + } + aux_hdr_entry->type = COPYRIGHT_AUX_ID; + aux_hdr_entry->contents.cpy.header_id.append = 1; + aux_hdr_entry->contents.cpy.header_id.type = COPYRIGHT_AUX_ID; + aux_hdr_entry->contents.cpy.header_id.length = len + sizeof (unsigned int); + while (aux_hdr_entry->contents.usr_str.header_id.length % 4) + aux_hdr_entry->contents.usr_str.header_id.length += 1; + + aux_hdr_entry->contents.cpy.string_length = len; + aux_hdr_entry->contents.cpy.copyright = (char *) (malloc (len + 1)); + strcpy (aux_hdr_entry->contents.cpy.copyright, PREFIX); + strcat (aux_hdr_entry->contents.cpy.copyright, name); + if (date_part) + { + strcat (aux_hdr_entry->contents.cpy.copyright, ","); + strcat (aux_hdr_entry->contents.cpy.copyright, date_part); + } + strcat (aux_hdr_entry->contents.cpy.copyright, MIDFIX); + strcat (aux_hdr_entry->contents.cpy.copyright, name); + strcat (aux_hdr_entry->contents.cpy.copyright, SUFFIX); + aux_hdr_entry->contents.cpy.copyright[len] = NULL; +#undef PREFIX +#undef MIDFIX +#undef SUFFIX +#endif /* OBJ_SOM */ + } + *input_line_pointer = c; + } + else + { + as_bad ("Expected \"-ed string"); + } + pa_undefine_label (); + demand_empty_rest_of_line (); +} + +void +pa_end () +{ + + demand_empty_rest_of_line (); + return; +} + +void +pa_enter () +{ + + as_bad (".ENTER encountered. gas doesn't generate entry code sequences."); + pa_entry (); + return; +} + +void +pa_entry () +{ + char *where; + + if (!within_procedure) + as_bad ("Misplaced .entry. Ignored."); + else + { + if (!callinfo_found) + as_bad ("Missing .callinfo."); + + last_call_info->start_frag = frag_now; + } + demand_empty_rest_of_line (); + within_entry_exit = TRUE; + where = frag_more (0); +#ifdef OBJ_SOM + fix_new (frag_now, where - frag_now->fr_literal, 0, + last_call_info->start_symbol, (symbolS *) NULL, 0, 0, + R_ENTRY, e_fsel, 0, 0, (char *) &last_call_info->ci_unwind.descriptor); +#else +#ifdef OBJ_ELF + /* XXX: no ENTRY relocation for PA ELF. What do we do instead? */ +#else + fix_new_hppa (frag_now, where - frag_now->fr_literal, 0, + last_call_info->start_symbol, (symbolS *) NULL, 0, 0, + R_HPPA_ENTRY, 0, 0, 0, + (char *) &last_call_info->ci_unwind.descriptor); +#endif +#endif + return; +} + +void +pa_equ (reg) + int reg; +{ + register label_symbolS *label_symbolP = pa_get_label (); + register symbolS *symbolP; + + if (label_symbolP) + { + symbolP = label_symbolP->lss_label; +#ifdef OBJ_SOM + symbolP->pa_sy_value = get_absolute_expression (); + symbolP->pa_sy_type = ST_ABSOLUTE; + symbolP->sy_ref = sym_unref; + symbolP->sy_equ = 1; +#else + S_SET_VALUE (symbolP, get_absolute_expression ()); + S_SET_SEGMENT (symbolP, &bfd_abs_section); +#endif + } + else + { + if (reg) + as_bad (".REG must use a label"); + else + as_bad (".EQU must use a label"); + } + + pa_undefine_label (); + demand_empty_rest_of_line (); + return; +} + +void +process_exit () +{ + char *where; + + where = frag_more (0); +#ifdef OBJ_SOM + fix_new (frag_now, where - frag_now->fr_literal, 0, + last_call_info->start_symbol, (symbolS *) NULL, 0, + 0, R_EXIT, e_fsel, 0, 0, (char *) NULL); +#endif +#ifdef OBJ_ELF + /* XXX: no EXIT relocation for PA ELF. All we do is create a */ + /* temporary symbol marking the end of the function. */ + { + char *name = (char *) xmalloc (strlen ("L\001end_") + + strlen (S_GET_NAME (last_call_info->start_symbol)) + 1); + + if (name) + { + symbolS *symbolP; + + strcpy (name, "L\001end_"); + strcat (name, S_GET_NAME (last_call_info->start_symbol)); + + symbolP = symbol_find (name); + if (symbolP) + as_warn ("Symbol '%s' already defined.", name); + else + { + /* symbol value should be the offset of the */ + /* last instruction of the function */ + symbolP = symbol_new (name, + now_seg, + (valueT) (obstack_next_free (&frags) - frag_now->fr_literal - 4), + frag_now); + + assert (symbolP); + + symbolP->bsym->flags = last_call_info->start_symbol->bsym->flags; + symbol_table_insert (symbolP); + } + if (symbolP) + last_call_info->end_symbol = symbolP; + else + as_bad ("Symbol '%s' could not be created.", name); + + } + else + as_bad ("No memory for symbol name."); + } +#else + fix_new_hppa (frag_now, where - frag_now->fr_literal, 0, + last_call_info->start_symbol, (symbolS *) NULL, 0, + 0, R_HPPA_EXIT, 0, 0, 0, (char *) NULL); +#endif + last_call_info->end_frag = frag_now; + + pa_build_unwind_subspace (last_call_info); + + exit_processing_complete = TRUE; +} + +void +pa_exit () +{ + + if (!within_procedure) + as_bad (".EXIT must appear within a procedure"); + else + { + if (!callinfo_found) + as_bad ("Missing .callinfo"); + else + { + if (!within_entry_exit) + as_bad ("No .ENTRY for this .EXIT"); + else + { + within_entry_exit = FALSE; + process_exit (); + } + } + } + demand_empty_rest_of_line (); + return; +} + +void +pa_export () +{ + register char *name; + register char c; + register char *p; + register int temp; + register int regno; + register symbolS *symbolP; + + name = input_line_pointer; + c = get_symbol_end (); + /* just after name is now '\0' */ + + if ((symbolP = symbol_find_or_make (name)) == NULL) + { + as_bad ("Cannot define export symbol: %s\n", name); + p = input_line_pointer; + *p = c; + input_line_pointer++; + } + else + { +#ifdef OBJ_SOM + symbolP->pa_sy_dict.symbol_scope = SS_UNIVERSAL; + /* determination of the symbol_type field will have to wait until + we know the subspace index (within the object file) of the subspace + containing this symbol */ +#else + /* S_SET_SEGMENT(symbolP,&bfd_und_section); */ + S_SET_EXTERNAL (symbolP); + /* symbolP->sy_frag = frag_now; */ +#endif + + p = input_line_pointer; + *p = c; + if (!is_end_of_statement ()) + { + input_line_pointer++; + pa_export_args (symbolP); + } + } + + demand_empty_rest_of_line (); + return; +} + +void +pa_export_args (symbolP) + register symbolS *symbolP; +{ + register char *name; + register char c; + register char *p; + register int temp; + register unsigned int arg_reloc; +#ifdef OBJ_ELF + elf_symbol_type *esymbolP = (elf_symbol_type *) (symbolP->bsym); +#endif + + if (strncasecmp (input_line_pointer, "absolute", 8) == 0) + { + input_line_pointer += 8; +#ifdef OBJ_SOM + symbolP->pa_sy_dict.symbol_type = ST_ABSOLUTE; +#else + S_SET_SEGMENT (symbolP, &bfd_abs_section); +#endif + } + else if (strncasecmp (input_line_pointer, "code", 4) == 0) + { + input_line_pointer += 4; +#ifdef OBJ_SOM + symbolP->pa_sy_dict.symbol_type = ST_CODE; +#else + /* S_SET_SEGMENT(symbolP,text_section); */ +#endif + } + else if (strncasecmp (input_line_pointer, "data", 4) == 0) + { + input_line_pointer += 4; +#ifdef OBJ_SOM + symbolP->pa_sy_dict.symbol_type = ST_DATA; +#else + /* S_SET_SEGMENT(symbolP,data_section); */ +#endif + } + else if ((strncasecmp (input_line_pointer, "entry", 5) == 0)) + { + input_line_pointer += 5; +#ifdef OBJ_SOM + symbolP->pa_sy_dict.symbol_type = ST_ENTRY; +#else + symbolP->bsym->flags |= BSF_FUNCTION; +#endif + } + else if (strncasecmp (input_line_pointer, "millicode", 9) == 0) + { + input_line_pointer += 9; +#ifdef OBJ_SOM + symbolP->pa_sy_dict.symbol_type = ST_MILLICODE; +#endif + } + else if (strncasecmp (input_line_pointer, "plabel", 6) == 0) + { + input_line_pointer += 6; +#ifdef OBJ_SOM + symbolP->pa_sy_dict.symbol_type = ST_PLABEL; +#endif + } + else if (strncasecmp (input_line_pointer, "pri_prog", 8) == 0) + { + input_line_pointer += 8; +#ifdef OBJ_SOM + symbolP->pa_sy_dict.symbol_type = ST_PRI_PROG; +#endif + } + else if (strncasecmp (input_line_pointer, "sec_prog", 8) == 0) + { + input_line_pointer += 8; +#ifdef OBJ_SOM + symbolP->pa_sy_dict.symbol_type = ST_SEC_PROG; +#endif + } + + while (!is_end_of_statement ()) + { + if (*input_line_pointer == ',') + input_line_pointer++; + name = input_line_pointer; + c = get_symbol_end (); + if ((strncasecmp (name, "argw", 4) == 0)) + { + p = input_line_pointer; + *p = c; + input_line_pointer++; + temp = atoi (name + 4); + name = input_line_pointer; + c = get_symbol_end (); + arg_reloc = pa_align_arg_reloc (temp, pa_build_arg_reloc (name)); +#ifdef OBJ_SOM + symbolP->pa_sy_dict.arg_reloc |= arg_reloc; +#else + esymbolP->tc_data.hppa_arg_reloc |= arg_reloc; +#endif + *input_line_pointer = c; + } + 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); +#ifdef OBJ_SOM + symbolP->pa_sy_dict.arg_reloc |= arg_reloc; +#else + esymbolP->tc_data.hppa_arg_reloc |= arg_reloc; +#endif + *input_line_pointer = c; + } + else if ((strncasecmp (name, "priv_lev", 8)) == 0) + { + p = input_line_pointer; + *p = c; + input_line_pointer++; + /*** temp = get_absolute_expression (); ***/ + temp = atoi (input_line_pointer); + c = get_symbol_end (); + *input_line_pointer = c; +#ifdef OBJ_SOM + symbolP->sy_priv_lev = temp & 3; /* this is stored in symbol_value later */ +#endif + } + else + { + as_bad ("Undefined .EXPORT/.IMPORT argument (ignored): %s", name); + p = input_line_pointer; + *p = c; + } + if (!is_end_of_statement ()) + input_line_pointer++; + } +} + +void +pa_import () +{ + register char *name; + register char c; + register char *p; + register symbolS *symbolP; + register expressionS resultP; /* Deliver result here. */ + + name = input_line_pointer; + c = get_symbol_end (); + /* just after name is now '\0' */ + + symbolP = symbol_find_or_make (name); +#if defined(OBJ_ELF) + /* symbolP->bsym->flags |= BSF_IMPORT; *//* XXX BSF_IMPORT is obsolete */ +#else + /* Check to see if this symbol has already been exported (this means its */ + /* defined locally and the import statement is redundant). */ + /* If it has not been exported, go ahead and mark this symbol as SS_UNSAT */ + /* (an unsatisfied external symbol) */ + + /* But, if the symbol has already been referenced (sy_ref == TRUE), + leave it alone. */ + + if (!symbolP->sy_ref) + { + if (symbolP->pa_sy_dict.symbol_scope != SS_UNIVERSAL) + { + symbolP->pa_sy_dict.symbol_scope = SS_UNSAT; + symbolP->sy_ref = FALSE; + } + } +#endif + + p = input_line_pointer; + *p = c; + + if (!is_end_of_statement ()) + { + input_line_pointer++; + + pa_export_args (symbolP); +#ifdef OBJ_ELF + /* In ELF, since this is an import, leave the section undefined. */ + /* S_SET_SEGMENT(symbolP,&bfd_und_section); */ +#endif + } + else + { +#ifdef OBJ_SOM + /* no further arguments, assign a default type according + to the current subspace (CODE or DATA) */ + switch (now_seg) + { + case SEG_TEXT: + symbolP->pa_sy_dict.symbol_type = ST_CODE; + break; + case SEG_ABSOLUTE: + symbolP->pa_sy_dict.symbol_type = ST_ABSOLUTE; + break; + default: + symbolP->pa_sy_dict.symbol_type = ST_DATA; + } +#else + /* In ELF, if the section is undefined, then the symbol is undefined */ + /* Since this is an import, leave the section undefined. */ + S_SET_SEGMENT (symbolP, &bfd_und_section); +#endif + } + + + demand_empty_rest_of_line (); + return; +} + +void +pa_label () +{ + register char *name; + register char c; + register char *p; + + name = input_line_pointer; + c = get_symbol_end (); + /* just after name is now '\0' */ + + if (strlen (name) > 0) + { + colon (name); + p = input_line_pointer; + *p = c; + } + else + { + as_warn ("Missing label name on .LABEL"); + } + + if (!is_end_of_statement ()) + { + as_warn ("extra .LABEL arguments ignored."); + ignore_rest_of_line (); + } + demand_empty_rest_of_line (); + return; +} + +void +pa_leave () +{ + + as_bad (".LEAVE encountered. gas doesn't generate exit code sequences."); + pa_exit (); + return; +} + +void +pa_origin () +{ + s_org (); /* ORG actually allows another argument (the fill value) + but maybe this is OK? */ + pa_undefine_label (); + return; +} + +void +pa_proc () +{ + call_infoS *call_info; + + if (within_procedure) + as_fatal ("Nested procedures"); + + callinfo_found = FALSE; + within_procedure = TRUE; + exit_processing_complete = FALSE; + + /* create another call_info structure */ + + call_info = (call_infoS *) xmalloc (sizeof (call_infoS)); + + if (!call_info) + as_fatal ("Cannot allocate unwind descriptor\n"); + + bzero (call_info, sizeof (call_infoS)); + + call_info->ci_next = NULL; + + if (call_info_root == NULL) + { + call_info_root = call_info; + last_call_info = call_info; + } + else + { + last_call_info->ci_next = call_info; + last_call_info = call_info; + } + + /* set up defaults on call_info structure */ + + call_info->ci_unwind.descriptor.cannot_unwind = 0; + call_info->ci_unwind.descriptor.region_desc = 1; + call_info->entry_sr = ~0; + call_info->makes_calls = 1; + call_info->hpux_int = 0; + + /* If we got a .PROC pseudo-op, we know that the function is defined + locally. Make sure it gets into the symbol table */ + { + label_symbolS *label_symbolP = pa_get_label (); + + if (label_symbolP) + { + if (label_symbolP->lss_label) + { +#ifdef OBJ_SOM + label_symbolP->lss_label->sy_ref |= sym_def; +#endif + last_call_info->start_symbol = label_symbolP->lss_label; + label_symbolP->lss_label->bsym->flags |= BSF_FUNCTION; + } + else + as_bad ("Missing function name for .PROC (corrupted label)"); + } + else + as_bad ("Missing function name for .PROC"); + } + + demand_empty_rest_of_line (); + return; +} + +void +pa_procend () +{ + + if (!within_procedure) + as_bad ("misplaced .procend"); + + if (!callinfo_found) + as_bad ("Missing .callinfo for this procedure"); + + if (within_entry_exit) + as_bad ("Missing .EXIT for a .ENTRY"); + + if (!exit_processing_complete) + process_exit (); + + within_procedure = FALSE; + demand_empty_rest_of_line (); + return; +} + +space_dict_chainS * +pa_parse_space_stmt (space_name, create_flag) + char *space_name; + int create_flag; +{ + register char *name; + register char c; + register char *p; + register int temp; + + char *ptemp; + int spnum; + char loadable; + char defined; + char private; + char sort; +#ifdef OBJ_SOM + segT seg; +#else + asection *seg; +#endif + space_dict_chainS *space; + + /* load default values */ + spnum = 0; + loadable = TRUE; + defined = TRUE; + private = FALSE; + if (strcasecmp (space_name, "$TEXT$") == 0) + { +#ifdef OBJ_SOM + seg = SEG_TEXT; +#else + seg = text_section; +#endif + sort = 8; + } + else + { +#ifdef OBJ_SOM + seg = SEG_DATA; +#else + seg = data_section; +#endif + sort = 16; + } + + if (!is_end_of_statement ()) + { + print_errors = FALSE; + ptemp = input_line_pointer + 1; + if ((temp = pa_parse_number (&ptemp)) >= 0) + { + spnum = temp; + input_line_pointer = ptemp; + } + else + { + while (!is_end_of_statement ()) + { + input_line_pointer++; + name = input_line_pointer; + c = get_symbol_end (); + if ((strncasecmp (name, "SPNUM", 5) == 0)) + { + p = input_line_pointer; + *p = c; + input_line_pointer++; + temp = get_absolute_expression (); + spnum = temp; + } + else if ((strncasecmp (name, "SORT", 4) == 0)) + { + p = input_line_pointer; + *p = c; + input_line_pointer++; + temp = get_absolute_expression (); + sort = temp; + } + else if ((strncasecmp (name, "UNLOADABLE", 10) == 0)) + { + p = input_line_pointer; + *p = c; + loadable = FALSE; + } + else if ((strncasecmp (name, "NOTDEFINED", 10) == 0)) + { + p = input_line_pointer; + *p = c; + defined = FALSE; + } + else if ((strncasecmp (name, "PRIVATE", 7) == 0)) + { + p = input_line_pointer; + *p = c; + private = TRUE; + } + else + { + as_bad ("Unrecognized .SPACE argument"); + p = input_line_pointer; + *p = c; + } + } + } + print_errors = TRUE; + } + if (create_flag) + space = create_new_space (space_name, spnum, loadable, defined, private, sort, 1, seg); + else + { /* if no creation of new space, this must be the first */ + /* occurrence of a built-in space */ + space = is_defined_space (space_name); + SPACE_SPNUM (space) = spnum; + SPACE_LOADABLE (space) = loadable & 1; + SPACE_DEFINED (space) = defined & 1; + SPACE_PRIVATE (space) = private & 1; + SPACE_SORT (space) = sort & 0xff; + space->sd_defined = 1; + space->sd_seg = seg; + } + return space; +} + +void +pa_align_subseg (seg, subseg) +#ifdef OBJ_SOM + segT seg; +#else + asection *seg; +#endif + subsegT subseg; +{ + subspace_dict_chainS *now_subspace; + int alignment; + int shift; + + now_subspace = pa_subsegment_to_subspace (seg, subseg); + if (SUBSPACE_ALIGN (now_subspace) == 0) + alignment = now_subspace->ssd_last_align; + else if (now_subspace->ssd_last_align > SUBSPACE_ALIGN (now_subspace)) + alignment = now_subspace->ssd_last_align; + else + alignment = SUBSPACE_ALIGN (now_subspace); + + shift = 0; + while ((1 << shift) < alignment) + shift++; + + frag_align (shift, 0); +} + +void +pa_space () +{ + register char *name; + register char c; + register char *p; + register int temp; + register symbolS *symbolP; + register space_dict_chainS *sd_chain; + char space_name[40]; + + if (within_procedure) + { + as_bad ("Can\'t change spaces within a procedure definition. Ignored"); + ignore_rest_of_line (); + } + else + { + if (strncasecmp (input_line_pointer, "$text$", 6) == 0) + { + input_line_pointer += 6; + sd_chain = is_defined_space ("$TEXT$"); + if (sd_chain == NULL) + sd_chain = pa_parse_space_stmt ("$TEXT$", 1); + else if (sd_chain->sd_defined == 0) + sd_chain = pa_parse_space_stmt ("$TEXT$", 0); + + current_space = sd_chain; + SPACE_DEFINED (current_space) = 1; + current_space->sd_defined = 1; +#ifdef OBJ_SOM + if (now_seg != SEG_TEXT) /* no need to align if we are already there */ +#else + if (now_seg != text_section) /* no need to align if we are already there */ +#endif + pa_align_subseg (now_seg, now_subseg); + +#ifdef OBJ_SOM + subseg_new (SEG_TEXT, sd_chain->sd_last_subseg); + current_subspace = pa_subsegment_to_subspace (SEG_TEXT, + sd_chain->sd_last_subseg); +#else + subseg_new ((char *) text_section->name, sd_chain->sd_last_subseg); + current_subspace = pa_subsegment_to_subspace (text_section, + sd_chain->sd_last_subseg); +#endif + demand_empty_rest_of_line (); + return; + } + if (strncasecmp (input_line_pointer, "$private$", 9) == 0) + { + input_line_pointer += 9; + sd_chain = is_defined_space ("$PRIVATE$"); + if (sd_chain == NULL) + sd_chain = pa_parse_space_stmt ("$PRIVATE$", 1); + else if (sd_chain->sd_defined == 0) + sd_chain = pa_parse_space_stmt ("$PRIVATE$", 0); + + current_space = sd_chain; + SPACE_DEFINED (current_space) = 1; + current_space->sd_defined = 1; +#ifdef OBJ_SOM + if (now_seg != SEG_DATA) /* no need to align if we are already there */ +#else + if (now_seg != data_section) /* no need to align if we are already there */ +#endif + pa_align_subseg (now_seg, now_subseg); +#ifdef OBJ_SOM + subseg_new (SEG_DATA, sd_chain->sd_last_subseg); + current_subspace = pa_subsegment_to_subspace (SEG_DATA, + sd_chain->sd_last_subseg); +#else + subseg_new ((char *) data_section->name, sd_chain->sd_last_subseg); + current_subspace = pa_subsegment_to_subspace (data_section, + sd_chain->sd_last_subseg); +#endif + demand_empty_rest_of_line (); + return; + } + if (strncasecmp (input_line_pointer, + GDB_DEBUG_SPACE_NAME, strlen (GDB_DEBUG_SPACE_NAME)) == 0) + { + input_line_pointer += strlen (GDB_DEBUG_SPACE_NAME); + sd_chain = is_defined_space (GDB_DEBUG_SPACE_NAME); + if (sd_chain == NULL) + sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 1); + else if (sd_chain->sd_defined == 0) + sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 0); + + current_space = sd_chain; + SPACE_DEFINED (current_space) = 1; + current_space->sd_defined = 1; +#ifdef OBJ_SOM + if (now_seg != SEG_GDB) /* no need to align if we are already there */ + pa_align_subseg (now_seg, now_subseg); + subseg_new (SEG_GDB, sd_chain->sd_last_subseg); + current_subspace = pa_subsegment_to_subspace (SEG_GDB, + sd_chain->sd_last_subseg); +#else + if (now_seg != gdb_section) /* no need to align if we are already there */ + pa_align_subseg (now_seg, now_subseg); + subseg_new ((char *) gdb_section->name, sd_chain->sd_last_subseg); + current_subspace = pa_subsegment_to_subspace (gdb_section, + sd_chain->sd_last_subseg); +#endif + demand_empty_rest_of_line (); + return; + } + + /* it could be a space specified by number */ + + if ((temp = pa_parse_number (&input_line_pointer)) >= 0) + { + if (sd_chain = pa_find_space_by_number (temp)) + { + current_space = sd_chain; + SPACE_DEFINED (current_space) = 1; + current_space->sd_defined = 1; + if (now_seg != sd_chain->sd_seg) /* don't align if we're already there */ + pa_align_subseg (now_seg, now_subseg); +#ifdef OBJ_SOM + subseg_new (sd_chain->sd_seg, sd_chain->sd_last_subseg); +#else + subseg_new ((char *) sd_chain->sd_seg->name, sd_chain->sd_last_subseg); +#endif + current_subspace = pa_subsegment_to_subspace (sd_chain->sd_seg, + sd_chain->sd_last_subseg); + demand_empty_rest_of_line (); + return; + } + } + + /* not a number, attempt to create a new space */ + + name = input_line_pointer; + c = get_symbol_end (); + space_name[0] = 0x00; + strcpy (space_name, name); + *input_line_pointer = c; + + sd_chain = pa_parse_space_stmt (space_name, 1); + current_space = sd_chain; + SPACE_DEFINED (current_space) = 1; + current_space->sd_defined = 1; + if (now_seg != sd_chain->sd_seg) /* don't align if we're already there */ + pa_align_subseg (now_seg, now_subseg); +#ifdef OBJ_SOM + subseg_new (sd_chain->sd_seg, sd_chain->sd_last_subseg); +#else + subseg_new ((char *) sd_chain->sd_seg->name, sd_chain->sd_last_subseg); +#endif + current_subspace = pa_subsegment_to_subspace (sd_chain->sd_seg, + sd_chain->sd_last_subseg); + demand_empty_rest_of_line (); + } + return; +} + +void +pa_spnum () +{ + register char *name; + register char c; + register char *p; + space_dict_chainS *space; + + name = input_line_pointer; + c = get_symbol_end (); + space = is_defined_space (name); + if (space) + { + p = frag_more (4); + /* put bytes in right order. */ + md_number_to_chars (p, SPACE_SPNUM (space), 4); + } + else + as_warn ("Undefined space: '%s' Assuming space number = 0.", name); + + *input_line_pointer = c; + demand_empty_rest_of_line (); + return; +} + +static +int +is_power_of_2 (value) + int value; +{ + int shift; + + shift = 0; + while ((1 << shift) != value && shift < 32) + shift++; + + if (shift >= 32) + shift = 0; + return shift; +} + +void +pa_subspace () +{ + register char *name; + register char c; + register char *p; + register int temp; + register symbolS *symbolP; + + char loadable, code_only, common, dup_common, zero; + char sort; + int number; + int i; + int access; + int space_index; + int alignment; + int quadrant; + int subseg; + space_dict_chainS *space; + subspace_dict_chainS *ssd; + subspace_dict_chainS *ssdCh; + char *ss_name; + int is_power_of_2 (); + + if (within_procedure) + { + as_bad ("Can\'t change subspaces within a procedure definition. Ignored"); + ignore_rest_of_line (); + } + else + { + name = input_line_pointer; + c = get_symbol_end (); + space = pa_segment_to_space (now_seg); + ssd = is_defined_subspace (name, space->sd_last_subseg); + + ss_name = xmalloc (strlen (name) + 1); + strcpy (ss_name, name); + + *input_line_pointer = c; + + /* load default values */ + sort = 0; + access = 0x7f; + loadable = 1; + common = 0; + dup_common = 0; + code_only = 0; + zero = 0; + space_index = ~0; /* filled in when the .o file is written */ + alignment = 0; /* alignment=0 means no ALIGN= appeared on the .SUBSPA */ + /* pseudo-op. The default will be the largest .ALIGN */ + /* encountered (or 1 if no .ALIGN is encountered) */ + quadrant = 0; + + if (ssd) + { + if (ssd->ssd_defined) + { +#ifdef OBJ_SOM + subseg_new (now_seg, ssd->ssd_subseg); +#else + /* subseg_new(now_seg->name,ssd->ssd_subseg); */ + subseg_new ((char *) ssd->ssd_seg->name, ssd->ssd_subseg); +#endif + if (!is_end_of_statement ()) + { + as_warn ("Parameters of an existing subspace can\'t be modified"); + } + demand_empty_rest_of_line (); + return; + } + else + { + ssd->ssd_defined = 1; + } + } + else + { + /* a new subspace */ + /* load default values */ + i = 0; + while (pa_def_subspaces[i].name) + { + if (strcasecmp (pa_def_subspaces[i].name, ss_name) == 0) + { + loadable = pa_def_subspaces[i].loadable; + common = pa_def_subspaces[i].common; + dup_common = pa_def_subspaces[i].dup_common; + code_only = pa_def_subspaces[i].code_only; + zero = pa_def_subspaces[i].zero; + space_index = pa_def_subspaces[i].space_index; + /* alignment = pa_def_subspaces[i].alignment; */ + alignment = 0; + quadrant = pa_def_subspaces[i].quadrant; + access = pa_def_subspaces[i].access; + sort = pa_def_subspaces[i].sort; + break; + } + i++; + } + } + + if (!is_end_of_statement ()) + { + input_line_pointer++; + while (!is_end_of_statement ()) + { + name = input_line_pointer; + c = get_symbol_end (); + if ((strncasecmp (name, "QUAD", 4) == 0)) + { + *input_line_pointer = c; + input_line_pointer++; + temp = get_absolute_expression (); + quadrant = temp; + } + else if ((strncasecmp (name, "ALIGN", 5) == 0)) + { + *input_line_pointer = c; + input_line_pointer++; + temp = get_absolute_expression (); + alignment = temp; + if (!is_power_of_2 (alignment)) + { + as_bad ("Alignment must be a power of 2"); + alignment = 1; + } + } + else if ((strncasecmp (name, "ACCESS", 6) == 0)) + { + *input_line_pointer = c; + input_line_pointer++; + temp = get_absolute_expression (); + access = temp; + } + else if ((strncasecmp (name, "SORT", 4) == 0)) + { + *input_line_pointer = c; + input_line_pointer++; + temp = get_absolute_expression (); + sort = temp; + } + else if ((strncasecmp (name, "CODE_ONLY", 9) == 0)) + { + *input_line_pointer = c; + code_only = 1; + } + else if ((strncasecmp (name, "UNLOADABLE", 10) == 0)) + { + *input_line_pointer = c; + loadable = 0; + } + else if ((strncasecmp (name, "COMMON", 6) == 0)) + { + *input_line_pointer = c; + common = 1; + } + else if ((strncasecmp (name, "DUP_COMM", 8) == 0)) + { + *input_line_pointer = c; + dup_common = 1; + } + else if ((strncasecmp (name, "ZERO", 4) == 0)) + { + *input_line_pointer = c; + zero = 1; + } + else + { + as_bad ("Unrecognized .SUBSPACE argument"); + } + if (!is_end_of_statement ()) + input_line_pointer++; + } + } + space = pa_segment_to_space (now_seg); + if (ssd) + { + current_subspace = update_subspace (ss_name, 1, loadable, code_only, + common, dup_common, sort, zero, access, + space_index, alignment, quadrant, + ssd->ssd_subseg); + } + else + { + current_subspace = create_new_subspace (space, ss_name, 1, loadable, code_only, + common, dup_common, zero, sort, + access, space_index, alignment, + quadrant, now_seg); + } + SUBSPACE_SUBSPACE_START (current_subspace) = pa_subspace_start (space, quadrant); + + demand_empty_rest_of_line (); +#ifdef OBJ_SOM + subseg_new (current_subspace->ssd_seg, current_subspace->ssd_subseg); +#else + subseg_new ((char *) current_subspace->ssd_seg->name, current_subspace->ssd_subseg); +#endif + } + return; +} + +/* For ELF, this function serves one purpose: to setup the st_size */ +/* field of STT_FUNC symbols. To do this, we need to scan the */ +/* call_info structure list, determining st_size in one of two possible */ +/* ways: */ + +/* 1. call_info->start_frag->fr_fix has the size of the fragment. */ +/* This approach assumes that the function was built into a */ +/* single fragment. This works for most cases, but might fail. */ +/* For example, if there was a segment change in the middle of */ +/* the function. */ + +/* 2. The st_size field is the difference in the addresses of the */ +/* call_info->start_frag->fr_address field and the fr_address */ +/* field of the next fragment with fr_type == rs_fill and */ +/* fr_fix != 0. */ + +void +elf_hppa_final_processing_hook () +{ + extern call_infoS *call_info_root; + + call_infoS *ciP; + + for (ciP = call_info_root; ciP; ciP = ciP->ci_next) + { + elf_symbol_type *esym = (elf_symbol_type *) ciP->start_symbol->bsym; + esym->internal_elf_sym.st_size = + ciP->end_symbol->bsym->value + - ciP->start_symbol->bsym->value + 4; + } +} + +/* pa-spaces.c -- Space/subspace support for the HP PA-RISC version of GAS */ + +/* for space, subspace, and symbol maintenance on HP 9000 Series 800 */ + +space_dict_chainS *space_dict_root; +space_dict_chainS *space_dict_last; + +space_dict_chainS *current_space; +subspace_dict_chainS *current_subspace; + +extern symbolS *start_symbol_root; +extern symbolS *start_symbol_last; + +void +pa_spaces_begin () +{ + space_dict_chainS *space; + int i; + subsegT now_subseg = now_subseg; + + space_dict_root = NULL; + space_dict_last = NULL; + + start_symbol_root = NULL; + start_symbol_last = NULL; + + /* create default space and subspace dictionaries */ + + i = 0; + while (pa_def_spaces[i].name) + { + if (pa_def_spaces[i].alias) + pa_def_spaces[i].segment = subseg_new (pa_def_spaces[i].alias, 0); + else + pa_def_spaces[i].segment = bfd_make_section_old_way (stdoutput, pa_def_spaces[i].name); + + create_new_space (pa_def_spaces[i].name, pa_def_spaces[i].spnum, + pa_def_spaces[i].loadable, pa_def_spaces[i].defined, + pa_def_spaces[i].private, pa_def_spaces[i].sort, 0, + pa_def_spaces[i].segment); + i++; + } + + i = 0; + while (pa_def_subspaces[i].name) + { + space = pa_segment_to_space (pa_def_spaces[pa_def_subspaces[i].def_space_index].segment); + if (space) + { + char *name = pa_def_subspaces[i].alias; + if (!name) + name = pa_def_subspaces[i].name; + create_new_subspace (space, name, + pa_def_subspaces[i].defined, + pa_def_subspaces[i].loadable, + pa_def_subspaces[i].code_only, pa_def_subspaces[i].common, + pa_def_subspaces[i].dup_common, pa_def_subspaces[i].zero, + pa_def_subspaces[i].sort, pa_def_subspaces[i].access, + pa_def_subspaces[i].space_index, + pa_def_subspaces[i].alignment, + pa_def_subspaces[i].quadrant, + pa_def_spaces[pa_def_subspaces[i].def_space_index].segment); + subseg_new (name, pa_def_subspaces[i].subsegment); + } + else + as_fatal ("Internal error: space missing for subspace \"%s\"\n", + pa_def_subspaces[i].name); + i++; + } +} + +space_dict_chainS * +create_new_space (name, spnum, loadable, defined, private, sort, defined_in_file, seg) + char *name; + int spnum; + char loadable; + char defined; + char private; + char sort; + char defined_in_file; + asection *seg; + +{ + Elf_Internal_Shdr *new_space; + space_dict_chainS *chain_entry; + + new_space = (Elf_Internal_Shdr *) xmalloc (sizeof (Elf_Internal_Shdr)); + if (!new_space) + as_fatal ("Out of memory: could not allocate new Elf_Internal_Shdr: %s\n", name); + + /* + new_space->space_number = spnum; + new_space->is_loadable = loadable & 1; + new_space->is_defined = defined & 1; + new_space->is_private = private & 1; + new_space->sort_key = sort & 0xff; + + new_space->loader_fix_index = ~0; + new_space->loader_fix_quantity = 0; + new_space->init_pointer_index = ~0; + new_space->init_pointer_quantity = 0; + new_space->subspace_quantity = 0; + */ + + chain_entry = (space_dict_chainS *) xmalloc (sizeof (space_dict_chainS)); + if (!chain_entry) + as_fatal ("Out of memory: could not allocate new space chain entry: %s\n", name); + + SPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1); + strcpy (SPACE_NAME (chain_entry), name); + + chain_entry->sd_entry = new_space; + chain_entry->sd_defined = defined_in_file; + chain_entry->sd_seg = seg; + chain_entry->sd_last_subseg = -1; + chain_entry->sd_next = NULL; + + SPACE_SPNUM (chain_entry) = spnum; + SPACE_LOADABLE (chain_entry) = loadable & 1; + SPACE_DEFINED (chain_entry) = defined & 1; + SPACE_PRIVATE (chain_entry) = private & 1; + SPACE_SORT (chain_entry) = sort & 0xff; + + /* find spot for the new space based on its sort key */ + + if (!space_dict_last) + space_dict_last = chain_entry; + + if (space_dict_root == NULL) /* if root is null, it is very easy */ + space_dict_root = chain_entry; + else + { + space_dict_chainS *sdcP; + space_dict_chainS *last_sdcP; + + sdcP = space_dict_root; + last_sdcP = NULL; + + while (sdcP) + { + if (SPACE_SORT (sdcP) < SPACE_SORT (chain_entry)) + { + last_sdcP = sdcP; + sdcP = sdcP->sd_next; + } + else if (SPACE_SORT (sdcP) == SPACE_SORT (chain_entry)) + { + last_sdcP = sdcP; + sdcP = sdcP->sd_next; + } + else if (SPACE_SORT (sdcP) > SPACE_SORT (chain_entry)) + { + break; + } + } + + if (last_sdcP) + { + chain_entry->sd_next = sdcP; + last_sdcP->sd_next = chain_entry; + } + else + { + space_dict_root = chain_entry; + chain_entry->sd_next = sdcP; + } + + if (chain_entry->sd_next == NULL) + space_dict_last = chain_entry; + } + + return chain_entry; +} + +subspace_dict_chainS +* create_new_subspace (space, name, defined, loadable, code_only, common, dup_common, + is_zero, sort, access, space_index, alignment, quadrant, seg) + space_dict_chainS *space; + char *name; + char defined, loadable, code_only, common, dup_common, is_zero; + char sort; + int access; + int space_index; + int alignment; + int quadrant; + asection *seg; +{ + Elf_Internal_Shdr *new_subspace; + subspace_dict_chainS *chain_entry; + symbolS *start_symbol; + + new_subspace = (Elf_Internal_Shdr *) xmalloc (sizeof (Elf_Internal_Shdr)); + if (!new_subspace) + as_fatal ("Out of memory: could not allocate new Elf_Internal_Shdr: %s\n", + name); + + /* + new_subspace->space_index = space_index; + new_subspace->fixup_request_index = ~0; + */ + + chain_entry = (subspace_dict_chainS *) xmalloc (sizeof (subspace_dict_chainS)); + if (!chain_entry) + as_fatal ("Out of memory: could not allocate new subspace chain entry: %s\n", name); + + chain_entry->ssd_entry = new_subspace; + SUBSPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1); + strcpy (SUBSPACE_NAME (chain_entry), name); + + SUBSPACE_ACCESS (chain_entry) = access & 0x7f; + SUBSPACE_LOADABLE (chain_entry) = loadable & 1; + SUBSPACE_COMMON (chain_entry) = common & 1; + SUBSPACE_DUP_COMM (chain_entry) = dup_common & 1; + SUBSPACE_SORT (chain_entry) = sort & 0xff; + SET_SUBSPACE_CODE_ONLY (chain_entry, code_only & 1); + SUBSPACE_ALIGN (chain_entry) = alignment & 0xffff; + SUBSPACE_QUADRANT (chain_entry) = quadrant & 0x3; + SUBSPACE_SUBSPACE_START (chain_entry) = pa_subspace_start (space, quadrant); + + chain_entry->ssd_defined = defined; + chain_entry->ssd_space_number = space_index; + chain_entry->ssd_subseg = pa_next_subseg (space); + chain_entry->ssd_seg = seg; + SUBSPACE_ZERO (chain_entry) = is_zero; + chain_entry->ssd_last_align = 1; + chain_entry->ssd_next = NULL; + + /* find spot for the new subspace based on its sort key */ + + if (space->sd_subspaces == NULL) /* if root is null, it is very easy */ + space->sd_subspaces = chain_entry; + else + { + subspace_dict_chainS *ssdcP; + subspace_dict_chainS *last_ssdcP; + + ssdcP = space->sd_subspaces; + last_ssdcP = NULL; + + while (ssdcP) + { + if (SUBSPACE_SORT (ssdcP) < SUBSPACE_SORT (chain_entry)) + { + last_ssdcP = ssdcP; + ssdcP = ssdcP->ssd_next; + } + else if (SUBSPACE_SORT (ssdcP) == SUBSPACE_SORT (chain_entry)) + { + last_ssdcP = ssdcP; + ssdcP = ssdcP->ssd_next; + } + else if (SUBSPACE_SORT (ssdcP) > SUBSPACE_SORT (chain_entry)) + { + break; + } + } + + if (last_ssdcP) + { + chain_entry->ssd_next = ssdcP; + last_ssdcP->ssd_next = chain_entry; + } + else + { + space->sd_subspaces = chain_entry; + chain_entry->ssd_next = ssdcP; + } + } + + start_symbol = pa_set_start_symbol (seg, space->sd_last_subseg); + chain_entry->ssd_start_sym = start_symbol; + return chain_entry; + +} + +subspace_dict_chainS +* update_subspace (name, defined, loadable, code_only, common, dup_common, sort, zero, + access, space_index, alignment, quadrant, subseg) + char *name; + char defined, loadable, code_only, common, dup_common, zero; + char sort; + int access; + int space_index; + int alignment; + int quadrant; + subsegT subseg; +{ + subspace_dict_chainS *chain_entry; + subspace_dict_chainS *is_defined_subspace (); + + if ((chain_entry = is_defined_subspace (name, subseg))) + { + + SUBSPACE_ACCESS (chain_entry) = access & 0x7f; + SUBSPACE_LOADABLE (chain_entry) = loadable & 1; + SUBSPACE_COMMON (chain_entry) = common & 1; + SUBSPACE_DUP_COMM (chain_entry) = dup_common & 1; + SET_SUBSPACE_CODE_ONLY (chain_entry, code_only & 1); + SUBSPACE_SORT (chain_entry) = sort & 0xff; + /* chain_entry->ssd_entry->space_index = space_index; */ + SUBSPACE_ALIGN (chain_entry) = alignment & 0xffff; + SUBSPACE_QUADRANT (chain_entry) = quadrant & 0x3; + + chain_entry->ssd_defined = defined; + chain_entry->ssd_space_number = space_index; + SUBSPACE_ZERO (chain_entry) = zero; + } + else + chain_entry = NULL; + + return chain_entry; + +} + +space_dict_chainS * +is_defined_space (name) + char *name; +{ + space_dict_chainS *spaceCh; + + for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next) + { + if (strcmp (SPACE_NAME (spaceCh), name) == 0) + { + return spaceCh; + } + } + + return NULL; +} + +space_dict_chainS * +pa_segment_to_space (seg) + asection *seg; +{ + space_dict_chainS *spaceCh; + + for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next) + { + if (spaceCh->sd_seg == seg) + { + return spaceCh; + } + } + + return NULL; +} + +subspace_dict_chainS * +is_defined_subspace (name, subseg) + char *name; + subsegT subseg; +{ + space_dict_chainS *spaceCh; + subspace_dict_chainS *subspCh; + + for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next) + { + for (subspCh = spaceCh->sd_subspaces; subspCh; subspCh = subspCh->ssd_next) + { + /* + if ( strcmp(SUBSPACE_NAME(subspCh),name) == 0 && + subspCh->ssd_subseg == subseg ) { + */ + if (strcmp (SUBSPACE_NAME (subspCh), name) == 0) + { + return subspCh; + } + } + } + return NULL; +} + +subspace_dict_chainS * +pa_subsegment_to_subspace (seg, subseg) + asection *seg; + subsegT subseg; +{ + space_dict_chainS *spaceCh; + subspace_dict_chainS *subspCh; + + for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next) + { + if (spaceCh->sd_seg == seg) + { + for (subspCh = spaceCh->sd_subspaces; subspCh; subspCh = subspCh->ssd_next) + { + if (subspCh->ssd_subseg == (int) subseg) + { + return subspCh; + } + } + } + } + + return NULL; +} + +space_dict_chainS * +pa_find_space_by_number (number) + int number; +{ + space_dict_chainS *spaceCh; + + for (spaceCh = space_dict_root; spaceCh; spaceCh = spaceCh->sd_next) + { + if (SPACE_SPNUM (spaceCh) == number) + { + return spaceCh; + } + } + + return NULL; +} + +unsigned int +pa_subspace_start (space, quadrant) + space_dict_chainS *space; + int quadrant; +{ + if ((strcasecmp (SPACE_NAME (space), "$PRIVATE$") == 0) && + quadrant == 1) + { + return 0x40000000; + } + else if (space->sd_seg == data_section && quadrant == 1) + { /* in case name is */ + /* already converted */ + /* to a space dict- */ + /* ionary index */ + return 0x40000000; + } + else + return 0; +} + +int +pa_next_subseg (space) + space_dict_chainS *space; +{ + + space->sd_last_subseg++; + return space->sd_last_subseg; +} + +int +is_last_defined_subspace (ssd) + subspace_dict_chainS *ssd; +{ + + for (; ssd; ssd = ssd->ssd_next) + { + if (ssd->ssd_defined) + return FALSE; + } + + return TRUE; +} + +symbolS * +pa_get_start_symbol (seg, subseg) + asection *seg; + subsegT subseg; +{ + symbolS *start_symbol; + subspace_dict_chainS *ssd; + + start_symbol = NULL; + + /* each time a new space is created, build a symbol called LS$START_seg_subseg$ */ + /* where <space-name> is the name of the space */ + /* the start symbol will be SS_LOCAL and ST_CODE */ + + if (seg == bfd_make_section_old_way (stdoutput, ".text") || + seg == bfd_make_section_old_way (stdoutput, ".data") || + seg == bfd_make_section_old_way (stdoutput, GDB_DEBUG_SPACE_NAME)) + { + ssd = pa_subsegment_to_subspace (seg, subseg); + if (ssd) + { + start_symbol = ssd->ssd_start_sym; + } + else + as_fatal ("Internal error: missing subspace for (seg,subseg)=('%s',%d)", + seg->name, subseg); + } + else + as_fatal ("Internal error: attempt to find start symbol for unloadable segment: '%s'", + seg->name); + + return start_symbol; +} + +/* + Function to define a symbol whose address is the beginning of a subspace. + This function assumes the symbol is to be defined for the current subspace. + */ + +symbolS * +pa_set_start_symbol (seg, subseg) + asection *seg; + subsegT subseg; +{ + symbolS *start_symbol; + subspace_dict_chainS *ssd; + char *symbol_name; + + symbol_name = (char *) xmalloc (strlen ("LS$START__000000$") + strlen (seg->name) + 1); + + sprintf (symbol_name, "LS$START_%s_%03d$", seg->name, subseg); + + start_symbol + = symbol_new (symbol_name, seg, 0, frag_now); /* XXX: not sure if value s.b. 0 or frag s.b. NULL */ + + start_symbol->bsym->flags = BSF_LOCAL; /* XXX: isn't there a macro defined for this? */ + + /* each time a new space is created, build a symbol called LS$START_seg_subseg$ */ + /* where <space-name> is the name of the space */ + /* the start symbol will be SS_LOCAL and ST_CODE */ + /* This function assumes that (seg,subseg) is a new subsegment(subspace) */ + + if (seg == bfd_make_section_old_way (stdoutput, ".text") || + seg == bfd_make_section_old_way (stdoutput, ".data") || + seg == bfd_make_section_old_way (stdoutput, GDB_DEBUG_SPACE_NAME)) + { + ssd = pa_subsegment_to_subspace (seg, subseg); + if (ssd) + { + ssd->ssd_start_sym = start_symbol; + } + else + as_fatal ("Internal error: missing subspace for (seg,subseg)=('%s',%d)", + seg, subseg); + } + else + as_fatal ("Internal error: attempt to define start symbol for unloadable segment: '%s'", + seg->name); + + return start_symbol; +} + +static unsigned int +pa_stringer_aux (s) + char *s; +{ + unsigned int c = *s & CHAR_MASK; + switch (c) + { + case '\"': + c = NOT_A_CHAR; + break; + default: + break; + } + return c; +} + +void +pa_stringer (append_zero) /* Worker to do .ascii etc statements. */ + /* Checks end-of-line. */ + register int append_zero; /* 0: don't append '\0', else 1 */ +{ + char *s; + unsigned int c; + char num_buf[4]; + int i; + + /* Preprocess the string to handle PA-specific escape sequences. */ + /* For example, \xDD where DD is a hexidecimal number should be */ + /* changed to \OOO where OOO is an octal number. */ + + s = input_line_pointer + 1; /* skip the opening quote */ + + while (is_a_char (c = pa_stringer_aux (s++))) + { + if (c == '\\') + { + c = *s; + switch (c) + { + case 'x': + { + unsigned int number; + int num_digit; + char dg; + char *s_start = s; + + s++; /* get past the 'x' */ + for (num_digit = 0, number = 0, dg = *s; + num_digit < 2 + && (isdigit (dg) || (dg >= 'a' && dg <= 'f') + || (dg >= 'A' && dg <= 'F')); + num_digit++) + { + if (isdigit (dg)) + number = number * 16 + dg - '0'; + else if (dg >= 'a' && dg <= 'f') + number = number * 16 + dg - 'a' + 10; + else + number = number * 16 + dg - 'A' + 10; + + s++; + dg = *s; + } + if (num_digit > 0) + { + switch (num_digit) + { + case 1: + sprintf (num_buf, "%02o", number); + break; + case 2: + sprintf (num_buf, "%03o", number); + break; + } + for (i = 0; i <= num_digit; i++) + s_start[i] = num_buf[i]; + } + } + break; + } + } + } + stringer (append_zero); + pa_undefine_label (); +} + +void +pa_version () +{ +#ifdef OBJ_ELF + obj_elf_version (); +#endif + pa_undefine_label (); +} + +void +pa_cons (nbytes) + register unsigned int nbytes; /* 1=.byte, 2=.word, 4=.long */ +{ + cons (nbytes); + pa_undefine_label (); +} + +void +pa_data () +{ + s_data (); + pa_undefine_label (); +} + +void +pa_desc () +{ + +#ifdef OBJ_ELF + obj_elf_desc (); +#endif + pa_undefine_label (); +} + +void +pa_float_cons (float_type) + register int float_type; /* 'f':.ffloat ... 'F':.float ... */ +{ + float_cons (float_type); + pa_undefine_label (); +} + +void +pa_fill () +{ + s_fill (); + pa_undefine_label (); +} + +void +pa_lcomm (needs_align) + /* 1 if this was a ".bss" directive, which may require a 3rd argument + (alignment); 0 if it was an ".lcomm" (2 args only) */ + int needs_align; +{ + s_lcomm (needs_align); + pa_undefine_label (); +} + +void +pa_lsym () +{ + s_lsym (); + pa_undefine_label (); +} + +void +pa_big_cons (nbytes) + register int nbytes; +{ + big_cons (nbytes); + pa_undefine_label (); +} + +void +pa_text () +{ + s_text (); + pa_undefine_label (); +} diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index a61ccd0..3774d93 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -2161,7 +2161,7 @@ const int md_reloc_size = 8; /* Size of relocation record */ void md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) char *ptr; - valueT from_addr, to_addr; + addressT from_addr, to_addr; fragS *frag; symbolS *to_symbol; { @@ -2175,7 +2175,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; - valueT from_addr, to_addr; + addressT from_addr, to_addr; fragS *frag; symbolS *to_symbol; { diff --git a/gas/config/tc-i860.c b/gas/config/tc-i860.c index abd53c8..b103dcb 100644 --- a/gas/config/tc-i860.c +++ b/gas/config/tc-i860.c @@ -1,18 +1,18 @@ /* tc-i860.c -- Assemble for the I860 Copyright (C) 1989, 1992 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 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. */ @@ -21,78 +21,50 @@ #include "opcode/i860.h" -/* incorporated from i860.h */ -enum reloc_type /* NOTE: three bits max, see struct reloc_info_i860.r_type */ -{ - NO_RELOC = 0, BRADDR, LOW0, LOW1, LOW2, LOW3, LOW4, SPLIT0, SPLIT1, SPLIT2, RELOC_32, -}; - -enum highlow_type /* NOTE: two bits max, see reloc_info_i860.r_type */ -{ - NO_SPEC = 0, PAIR, HIGH, HIGHADJ, -}; - -struct reloc_info_i860 -{ - unsigned long r_address; - /* - * Using bit fields here is a bad idea because the order is not portable. :-( - */ - unsigned int r_symbolnum: 24; - unsigned int r_pcrel : 1; - unsigned int r_extern : 1; - /* combining the two field simplifies the argument passing in "new_fix()" */ - /* and is compatible with the existing Sparc #ifdef's */ - /* r_type: highlow_type - bits 5,4; reloc_type - bits 3-0 */ - unsigned int r_type : 6; - long r_addend; -}; - -#define relocation_info reloc_info_i860 - - -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(); -static void i860_ip(); -void emit_machine_reloc(); +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 (); +static void i860_ip (); +/* void emit_machine_reloc(); */ -int md_reloc_size = sizeof(struct relocation_info); +const int md_reloc_size = sizeof (struct relocation_info); -void (*md_emit_relocations)() = emit_machine_reloc; +/* void (*md_emit_relocations)() = emit_machine_reloc; */ -const relax_typeS md_relax_table[] = { 0 }; +const relax_typeS md_relax_table[] = +{0}; /* handle of the OPCODE hash table */ static struct hash_control *op_hash = NULL; -static void s_dual(), s_enddual(); -static void s_atmp(); +static void s_dual (), s_enddual (); +static void s_atmp (); const pseudo_typeS - md_pseudo_table[] = { - { "dual", s_dual, 4 }, - { "enddual", s_enddual, 4 }, - { "atmp", s_atmp, 4 }, - { NULL, 0, 0 }, - }; + md_pseudo_table[] = +{ + {"dual", s_dual, 4}, + {"enddual", s_enddual, 4}, + {"atmp", s_atmp, 4}, + {NULL, 0, 0}, +}; 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 */ -char comment_chars[] = "!/"; /* JF removed '|' from comment_chars */ +const char comment_chars[] = "!/"; /* JF removed '|' from comment_chars */ /* 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' @@ -101,46 +73,49 @@ char comment_chars[] = "!/"; /* JF removed '|' from comment_chars */ first line of the input file. This is because the compiler outputs #NO_APP at the beginning of its output. */ /* Also note that comments like this one will always work. */ -char line_comment_chars[] = "#/"; +const char line_comment_chars[] = "#/"; + +const char line_separator_chars[] = ""; /* Chars that can be used to separate mant from exp in floating point nums */ -char EXP_CHARS[] = "eE"; +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"; /* 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. */ -int size_reloc_info = sizeof(struct relocation_info); +int size_reloc_info = sizeof (struct relocation_info); static unsigned char octal[256]; #define isoctal(c) octal[c] - static unsigned char toHex[256]; - -struct i860_it { - char *error; - unsigned long opcode; - struct nlist *nlistp; - expressionS exp; - int pcrel; - enum expand_type expand; - enum highlow_type highlow; - enum reloc_type reloc; -} the_insn; +static unsigned char toHex[256]; + +struct i860_it + { + char *error; + unsigned long opcode; + struct nlist *nlistp; + expressionS exp; + int pcrel; + enum expand_type expand; + enum highlow_type highlow; + enum reloc_type reloc; + } the_insn; #if __STDC__ == 1 -static void print_insn(struct i860_it *insn); -static int getExpression(char *str); +static void print_insn (struct i860_it *insn); +static int getExpression (char *str); #else /* not __STDC__ */ -static void print_insn(); -static int getExpression(); +static void print_insn (); +static int getExpression (); #endif /* not __STDC__ */ @@ -149,627 +124,674 @@ static char last_expand; /* error if expansion after branch */ enum dual { - DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT, + DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT, }; static enum dual dual_mode = DUAL_OFF; /* dual-instruction mode */ static void - s_dual() /* floating point instructions have dual set */ +s_dual () /* floating point instructions have dual set */ { - dual_mode = DUAL_ON; + dual_mode = DUAL_ON; } static void - s_enddual() /* floating point instructions have dual set */ +s_enddual () /* floating point instructions have dual set */ { - dual_mode = DUAL_OFF; + dual_mode = DUAL_OFF; } -static int atmp = 31; /* temporary register for pseudo's */ +static int atmp = 31; /* temporary register for pseudo's */ static void - s_atmp() +s_atmp () { - register int temp; - if (strncmp(input_line_pointer, "sp", 2) == 0) { - input_line_pointer += 2; - atmp = 2; - } - else if (strncmp(input_line_pointer, "fp", 2) == 0) { - input_line_pointer += 2; - atmp = 3; - } - else if (strncmp(input_line_pointer, "r", 1) == 0) { - input_line_pointer += 1; - temp = get_absolute_expression(); - if (temp >= 0 && temp <= 31) - atmp = temp; - else - as_bad("Unknown temporary pseudo register"); - } - else { - as_bad("Unknown temporary pseudo register"); - } - demand_empty_rest_of_line(); - return; + register int temp; + if (strncmp (input_line_pointer, "sp", 2) == 0) + { + input_line_pointer += 2; + atmp = 2; + } + else if (strncmp (input_line_pointer, "fp", 2) == 0) + { + input_line_pointer += 2; + atmp = 3; + } + else if (strncmp (input_line_pointer, "r", 1) == 0) + { + input_line_pointer += 1; + temp = get_absolute_expression (); + if (temp >= 0 && temp <= 31) + atmp = temp; + else + as_bad ("Unknown temporary pseudo register"); + } + else + { + as_bad ("Unknown temporary pseudo register"); + } + demand_empty_rest_of_line (); + return; } /* 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() +md_begin () { - register char *retval = NULL; - int lose = 0; - register unsigned int i = 0; - - op_hash = hash_new(); - if (op_hash == NULL) - as_fatal("Virtual memory exhausted"); - - while (i < NUMOPCODES) + register char *retval = NULL; + int lose = 0; + register unsigned int i = 0; + + op_hash = hash_new (); + if (op_hash == NULL) + as_fatal ("Virtual memory exhausted"); + + while (i < NUMOPCODES) + { + const char *name = i860_opcodes[i].name; + retval = hash_insert (op_hash, name, &i860_opcodes[i]); + if (retval != NULL && *retval != '\0') + { + fprintf (stderr, "internal error: can't hash `%s': %s\n", + i860_opcodes[i].name, retval); + lose = 1; + } + do + { + if (i860_opcodes[i].match & i860_opcodes[i].lose) { - const char *name = i860_opcodes[i].name; - retval = hash_insert(op_hash, name, &i860_opcodes[i]); - if(retval != NULL && *retval != '\0') - { - fprintf (stderr, "internal error: can't hash `%s': %s\n", - i860_opcodes[i].name, retval); - lose = 1; - } - do - { - if (i860_opcodes[i].match & i860_opcodes[i].lose) - { - fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n", - i860_opcodes[i].name, i860_opcodes[i].args); - lose = 1; - } - ++i; - } while (i < NUMOPCODES - && !strcmp(i860_opcodes[i].name, name)); + fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n", + i860_opcodes[i].name, i860_opcodes[i].args); + lose = 1; } - - 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'; + ++i; + } + while (i < NUMOPCODES + && !strcmp (i860_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() +md_end () { - return; + return; } void - md_assemble(str) -char *str; +md_assemble (str) + char *str; { - char *toP; - int rsd; - int no_opcodes = 1; - int i; - struct i860_it pseudo[3]; - - assert(str); - i860_ip(str); - - /* check for expandable flag to produce pseudo-instructions */ - if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) { - for (i = 0; i < 3; i++) - pseudo[i] = the_insn; - - switch (the_insn.expand) { - - case E_DELAY: - no_opcodes = 1; - break; - - case E_MOV: - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_subtract_symbol == NULL && - (the_insn.exp.X_add_number < (1 << 15) && - the_insn.exp.X_add_number >= -(1 << 15))) - break; - /* or l%const,r0,ireg_dest */ - pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000; - pseudo[0].highlow = PAIR; - /* orh h%const,ireg_dest,ireg_dest */ - pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 | - ((the_insn.opcode & 0x001f0000) << 5); - pseudo[1].highlow = HIGH; - no_opcodes = 2; - break; - - case E_ADDR: - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_subtract_symbol == NULL) - break; - /* orh ha%addr_expr,r0,r31 */ - pseudo[0].opcode = 0xec000000 | (atmp<<16); - pseudo[0].highlow = HIGHADJ; - pseudo[0].reloc = LOW0; /* must overwrite */ - /* l%addr_expr(r31),ireg_dest */ - pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21); - pseudo[1].highlow = PAIR; - no_opcodes = 2; - break; - - case E_U32: /* 2nd version emulates Intel as, not doc. */ - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_subtract_symbol == NULL && - (the_insn.exp.X_add_number < (1 << 16) && - the_insn.exp.X_add_number >= 0)) - break; - /* $(opcode)h h%const,ireg_src2,ireg_dest + char *toP; + int rsd; + int no_opcodes = 1; + int i; + struct i860_it pseudo[3]; + + assert (str); + i860_ip (str); + + /* check for expandable flag to produce pseudo-instructions */ + if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) + { + for (i = 0; i < 3; i++) + pseudo[i] = the_insn; + + switch (the_insn.expand) + { + + case E_DELAY: + no_opcodes = 1; + break; + + case E_MOV: + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL && + (the_insn.exp.X_add_number < (1 << 15) && + the_insn.exp.X_add_number >= -(1 << 15))) + break; + /* or l%const,r0,ireg_dest */ + pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000; + pseudo[0].highlow = PAIR; + /* orh h%const,ireg_dest,ireg_dest */ + pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 | + ((the_insn.opcode & 0x001f0000) << 5); + pseudo[1].highlow = HIGH; + no_opcodes = 2; + break; + + case E_ADDR: + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL) + break; + /* orh ha%addr_expr,r0,r31 */ + pseudo[0].opcode = 0xec000000 | (atmp << 16); + pseudo[0].highlow = HIGHADJ; + pseudo[0].reloc = LOW0; /* must overwrite */ + /* l%addr_expr(r31),ireg_dest */ + pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21); + pseudo[1].highlow = PAIR; + no_opcodes = 2; + break; + + case E_U32: /* 2nd version emulates Intel as, not doc. */ + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL && + (the_insn.exp.X_add_number < (1 << 16) && + the_insn.exp.X_add_number >= 0)) + break; + /* $(opcode)h h%const,ireg_src2,ireg_dest pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */ - /* $(opcode)h h%const,ireg_src2,r31 */ - pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 | - (atmp << 16); - pseudo[0].highlow = HIGH; - /* $(opcode) l%const,ireg_dest,ireg_dest + /* $(opcode)h h%const,ireg_src2,r31 */ + pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 | + (atmp << 16); + pseudo[0].highlow = HIGH; + /* $(opcode) l%const,ireg_dest,ireg_dest pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 | ((the_insn.opcode & 0x001f0000) << 5); */ - /* $(opcode) l%const,r31,ireg_dest */ - pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 | - (atmp << 21); - pseudo[1].highlow = PAIR; - no_opcodes = 2; - break; - - case E_AND: /* 2nd version emulates Intel as, not doc. */ - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_subtract_symbol == NULL && - (the_insn.exp.X_add_number < (1 << 16) && - the_insn.exp.X_add_number >= 0)) - break; - /* andnot h%const,ireg_src2,ireg_dest + /* $(opcode) l%const,r31,ireg_dest */ + pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 | + (atmp << 21); + pseudo[1].highlow = PAIR; + no_opcodes = 2; + break; + + case E_AND: /* 2nd version emulates Intel as, not doc. */ + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL && + (the_insn.exp.X_add_number < (1 << 16) && + the_insn.exp.X_add_number >= 0)) + break; + /* andnot h%const,ireg_src2,ireg_dest pseudo[0].opcode = (the_insn.opcode & 0x03ffffff) | 0xd4000000; */ - /* andnot h%const,ireg_src2,r31 */ - pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 | - (atmp << 16); - pseudo[0].highlow = HIGH; - pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number; - /* andnot l%const,ireg_dest,ireg_dest + /* andnot h%const,ireg_src2,r31 */ + pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 | + (atmp << 16); + pseudo[0].highlow = HIGH; + pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number; + /* andnot l%const,ireg_dest,ireg_dest pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 | ((the_insn.opcode & 0x001f0000) << 5); */ - /* andnot l%const,r31,ireg_dest */ - pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 | - (atmp << 21); - pseudo[1].highlow = PAIR; - pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number; - no_opcodes = 2; - break; - - case E_S32: - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_subtract_symbol == NULL && - (the_insn.exp.X_add_number < (1 << 15) && - the_insn.exp.X_add_number >= -(1 << 15))) - break; - /* orh h%const,r0,r31 */ - pseudo[0].opcode = 0xec000000 | (atmp << 16); - pseudo[0].highlow = HIGH; - /* or l%const,r31,r31 */ - pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16); - pseudo[1].highlow = PAIR; - /* r31,ireg_src2,ireg_dest */ - pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11); - pseudo[2].reloc = NO_RELOC; - no_opcodes = 3; - break; - - default: - as_fatal("failed sanity check."); - } - - the_insn = pseudo[0]; - /* check for expanded opcode after branch or in dual */ - if (no_opcodes > 1 && last_expand == 1) - as_warn("Expanded opcode after delayed branch: `%s'", str); - if (no_opcodes > 1 && dual_mode != DUAL_OFF) - as_warn("Expanded opcode in dual mode: `%s'", str); + /* andnot l%const,r31,ireg_dest */ + pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 | + (atmp << 21); + pseudo[1].highlow = PAIR; + pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number; + no_opcodes = 2; + break; + + case E_S32: + if (the_insn.exp.X_add_symbol == NULL && + the_insn.exp.X_subtract_symbol == NULL && + (the_insn.exp.X_add_number < (1 << 15) && + the_insn.exp.X_add_number >= -(1 << 15))) + break; + /* orh h%const,r0,r31 */ + pseudo[0].opcode = 0xec000000 | (atmp << 16); + pseudo[0].highlow = HIGH; + /* or l%const,r31,r31 */ + pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16); + pseudo[1].highlow = PAIR; + /* r31,ireg_src2,ireg_dest */ + pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11); + pseudo[2].reloc = NO_RELOC; + no_opcodes = 3; + break; + + default: + as_fatal ("failed sanity check."); } - - i = 0; - do { /* always produce at least one opcode */ - toP = frag_more(4); - /* put out the opcode */ - md_number_to_chars(toP, the_insn.opcode, 4); - - /* check for expanded opcode after branch or in dual */ - last_expand = the_insn.pcrel; - - /* put out the symbol-dependent stuff */ - if (the_insn.reloc != NO_RELOC) { - 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, - /* merge bit fields into one argument */ - (int)(((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf)) - ); - } - the_insn = pseudo[++i]; - } while (--no_opcodes > 0); - + + the_insn = pseudo[0]; + /* check for expanded opcode after branch or in dual */ + if (no_opcodes > 1 && last_expand == 1) + as_warn ("Expanded opcode after delayed branch: `%s'", str); + if (no_opcodes > 1 && dual_mode != DUAL_OFF) + as_warn ("Expanded opcode in dual mode: `%s'", str); + } + + i = 0; + do + { /* always produce at least one opcode */ + toP = frag_more (4); + /* put out the opcode */ + md_number_to_chars (toP, the_insn.opcode, 4); + + /* check for expanded opcode after branch or in dual */ + last_expand = the_insn.pcrel; + + /* put out the symbol-dependent stuff */ + if (the_insn.reloc != NO_RELOC) + { + 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, + /* merge bit fields into one argument */ + (int) (((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf))); + } + the_insn = pseudo[++i]; + } + while (--no_opcodes > 0); + } static void - i860_ip(str) -char *str; +i860_ip (str) + char *str; { - char *s; - const char *args; - char c; - unsigned long i; - struct i860_opcode *insn; - char *argsStart; - unsigned long opcode; - unsigned int mask; - int match = 0; - int comma = 0; - - - for (s = str; islower(*s) || *s == '.' || *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); - } - - if (strncmp(str, "d.", 2) == 0) { /* check for d. opcode prefix */ - if (dual_mode == DUAL_ON) - dual_mode = DUAL_ONDDOT; - else - dual_mode = DUAL_DDOT; - str += 2; - } - - if ((insn = (struct i860_opcode *) hash_find(op_hash, str)) == NULL) { - if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT) - str -= 2; - as_bad("Unknown opcode: `%s'", str); - return; - } - if (comma) { - *--s = ','; - } - argsStart = s; - for (;;) { - opcode = insn->match; - memset(&the_insn, '\0', sizeof(the_insn)); - the_insn.reloc = NO_RELOC; - - /* + char *s; + const char *args; + char c; + unsigned long i; + struct i860_opcode *insn; + char *argsStart; + unsigned long opcode; + unsigned int mask; + int match = 0; + int comma = 0; + + + for (s = str; islower (*s) || *s == '.' || *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); + } + + if (strncmp (str, "d.", 2) == 0) + { /* check for d. opcode prefix */ + if (dual_mode == DUAL_ON) + dual_mode = DUAL_ONDDOT; + else + dual_mode = DUAL_DDOT; + str += 2; + } + + if ((insn = (struct i860_opcode *) hash_find (op_hash, str)) == NULL) + { + if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT) + str -= 2; + as_bad ("Unknown opcode: `%s'", str); + return; + } + if (comma) + { + *--s = ','; + } + argsStart = s; + for (;;) + { + opcode = insn->match; + memset (&the_insn, '\0', sizeof (the_insn)); + the_insn.reloc = NO_RELOC; + + /* * 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 = 1; - } - break; - - case '+': - case '(': /* these must match exactly */ - case ')': - case ',': - case ' ': - if (*s++ == *args) - continue; - break; - - case '#': /* must be at least one digit */ - if (isdigit(*s++)) { - while (isdigit(*s)) { - ++s; - } - continue; - } - break; - - case '1': /* next operand must be a register */ - case '2': - case 'd': - switch (*s) { - - case 'f': /* frame pointer */ - s++; - if (*s++ == 'p') { - mask = 0x3; - break; - } - goto error; - - case 's': /* stack pointer */ - s++; - if (*s++ == 'p') { - mask= 0x2; - break; - } - goto error; - - case 'r': /* any register */ - s++; - if (!isdigit(c = *s++)) { - goto error; - } - if (isdigit(*s)) { - if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) { - goto error; - } - } else { - c -= '0'; - } - mask= c; - break; - - default: /* not this opcode */ - goto error; - } - /* + for (args = insn->args;; ++args) + { + switch (*args) + { + + case '\0': /* end of args */ + if (*s == '\0') + { + match = 1; + } + break; + + case '+': + case '(': /* these must match exactly */ + case ')': + case ',': + case ' ': + if (*s++ == *args) + continue; + break; + + case '#': /* must be at least one digit */ + if (isdigit (*s++)) + { + while (isdigit (*s)) + { + ++s; + } + continue; + } + break; + + case '1': /* next operand must be a register */ + case '2': + case 'd': + switch (*s) + { + + case 'f': /* frame pointer */ + s++; + if (*s++ == 'p') + { + mask = 0x3; + break; + } + goto error; + + case 's': /* stack pointer */ + s++; + if (*s++ == 'p') + { + mask = 0x2; + break; + } + goto error; + + case 'r': /* any register */ + s++; + if (!isdigit (c = *s++)) + { + goto error; + } + if (isdigit (*s)) + { + if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) + { + goto error; + } + } + else + { + c -= '0'; + } + mask = c; + break; + + default: /* not this opcode */ + goto error; + } + /* * Got the register, now figure out where * it goes in the opcode. */ - switch (*args) { - - case '1': - opcode |= mask << 11; - continue; - - case '2': - opcode |= mask << 21; - continue; - - case 'd': - opcode |= mask << 16; - continue; - - } - break; - - case 'e': /* next operand is a floating point register */ - case 'f': - case 'g': - if (*s++ == 'f' && isdigit(*s)) { - mask = *s++; - if (isdigit(*s)) { - mask = 10 * (mask - '0') + (*s++ - '0'); - if (mask >= 32) { - break; - } - } else { - mask -= '0'; - } - switch (*args) { - - case 'e': - opcode |= mask << 11; - continue; - - case 'f': - opcode |= mask << 21; - continue; - - case 'g': - opcode |= mask << 16; - if (dual_mode != DUAL_OFF) - opcode |= (1 << 9); /* dual mode instruction */ - if (dual_mode == DUAL_DDOT) - dual_mode = DUAL_OFF; - if (dual_mode == DUAL_ONDDOT) - dual_mode = DUAL_ON; - if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f))) - as_warn("Fsr1 equals fdest with Pipelining"); - continue; - } - } - break; - - case 'c': /* next operand must be a control register */ - if (strncmp(s, "fir", 3) == 0) { - opcode |= 0x0 << 21; - s += 3; - continue; - } - if (strncmp(s, "psr", 3) == 0) { - opcode |= 0x1 << 21; - s += 3; - continue; - } - if (strncmp(s, "dirbase", 7) == 0) { - opcode |= 0x2 << 21; - s += 7; - continue; - } - if (strncmp(s, "db", 2) == 0) { - opcode |= 0x3 << 21; - s += 2; - continue; - } - if (strncmp(s, "fsr", 3) == 0) { - opcode |= 0x4 << 21; - s += 3; - continue; - } - if (strncmp(s, "epsr", 4) == 0) { - opcode |= 0x5 << 21; - s += 4; - continue; - } - break; - - case '5': /* 5 bit immediate in src1 */ - memset(&the_insn, '\0', sizeof(the_insn)); - if ( !getExpression(s)) { - s = expr_end; - if (the_insn.exp.X_add_number & ~0x1f) - as_bad("5-bit immediate too large"); - opcode |= (the_insn.exp.X_add_number & 0x1f) << 11; - memset(&the_insn, '\0', sizeof(the_insn)); - the_insn.reloc = NO_RELOC; - continue; - } - break; - - case 'l': /* 26 bit immediate, relative branch */ - the_insn.reloc = BRADDR; - the_insn.pcrel = 1; - goto immediate; - - case 's': /* 16 bit immediate, split relative branch */ - /* upper 5 bits of offset in dest field */ - the_insn.pcrel = 1; - the_insn.reloc = SPLIT0; - goto immediate; - - case 'S': /* 16 bit immediate, split (st), aligned */ - if (opcode & (1 << 28)) - if (opcode & 0x1) - the_insn.reloc = SPLIT2; - else - the_insn.reloc = SPLIT1; - else - the_insn.reloc = SPLIT0; - goto immediate; - - case 'I': /* 16 bit immediate, aligned */ - if (opcode & (1 << 28)) - if (opcode & 0x1) - the_insn.reloc = LOW2; - else - the_insn.reloc = LOW1; - else - the_insn.reloc = LOW0; - goto immediate; - - case 'i': /* 16 bit immediate */ - the_insn.reloc = LOW0; - - /*FALLTHROUGH*/ - - immediate: - if(*s==' ') - s++; - if (strncmp(s, "ha%", 3) == 0) { - the_insn.highlow = HIGHADJ; - s += 3; - } else if (strncmp(s, "h%", 2) == 0) { - the_insn.highlow = HIGH; - s += 2; - } else if (strncmp(s, "l%", 2) == 0) { - the_insn.highlow = PAIR; - s += 2; - } - the_insn.expand = insn->expand; - - /* Note that if the getExpression() fails, we will still have + switch (*args) + { + + case '1': + opcode |= mask << 11; + continue; + + case '2': + opcode |= mask << 21; + continue; + + case 'd': + opcode |= mask << 16; + continue; + + } + break; + + case 'e': /* next operand is a floating point register */ + case 'f': + case 'g': + if (*s++ == 'f' && isdigit (*s)) + { + mask = *s++; + if (isdigit (*s)) + { + mask = 10 * (mask - '0') + (*s++ - '0'); + if (mask >= 32) + { + break; + } + } + else + { + mask -= '0'; + } + switch (*args) + { + + case 'e': + opcode |= mask << 11; + continue; + + case 'f': + opcode |= mask << 21; + continue; + + case 'g': + opcode |= mask << 16; + if (dual_mode != DUAL_OFF) + opcode |= (1 << 9); /* dual mode instruction */ + if (dual_mode == DUAL_DDOT) + dual_mode = DUAL_OFF; + if (dual_mode == DUAL_ONDDOT) + dual_mode = DUAL_ON; + if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f))) + as_warn ("Fsr1 equals fdest with Pipelining"); + continue; + } + } + break; + + case 'c': /* next operand must be a control register */ + if (strncmp (s, "fir", 3) == 0) + { + opcode |= 0x0 << 21; + s += 3; + continue; + } + if (strncmp (s, "psr", 3) == 0) + { + opcode |= 0x1 << 21; + s += 3; + continue; + } + if (strncmp (s, "dirbase", 7) == 0) + { + opcode |= 0x2 << 21; + s += 7; + continue; + } + if (strncmp (s, "db", 2) == 0) + { + opcode |= 0x3 << 21; + s += 2; + continue; + } + if (strncmp (s, "fsr", 3) == 0) + { + opcode |= 0x4 << 21; + s += 3; + continue; + } + if (strncmp (s, "epsr", 4) == 0) + { + opcode |= 0x5 << 21; + s += 4; + continue; + } + break; + + case '5': /* 5 bit immediate in src1 */ + memset (&the_insn, '\0', sizeof (the_insn)); + if (!getExpression (s)) + { + s = expr_end; + if (the_insn.exp.X_add_number & ~0x1f) + as_bad ("5-bit immediate too large"); + opcode |= (the_insn.exp.X_add_number & 0x1f) << 11; + memset (&the_insn, '\0', sizeof (the_insn)); + the_insn.reloc = NO_RELOC; + continue; + } + break; + + case 'l': /* 26 bit immediate, relative branch */ + the_insn.reloc = BRADDR; + the_insn.pcrel = 1; + goto immediate; + + case 's': /* 16 bit immediate, split relative branch */ + /* upper 5 bits of offset in dest field */ + the_insn.pcrel = 1; + the_insn.reloc = SPLIT0; + goto immediate; + + case 'S': /* 16 bit immediate, split (st), aligned */ + if (opcode & (1 << 28)) + if (opcode & 0x1) + the_insn.reloc = SPLIT2; + else + the_insn.reloc = SPLIT1; + else + the_insn.reloc = SPLIT0; + goto immediate; + + case 'I': /* 16 bit immediate, aligned */ + if (opcode & (1 << 28)) + if (opcode & 0x1) + the_insn.reloc = LOW2; + else + the_insn.reloc = LOW1; + else + the_insn.reloc = LOW0; + goto immediate; + + case 'i': /* 16 bit immediate */ + the_insn.reloc = LOW0; + + /*FALLTHROUGH*/ + + immediate: + if (*s == ' ') + s++; + if (strncmp (s, "ha%", 3) == 0) + { + the_insn.highlow = HIGHADJ; + s += 3; + } + else if (strncmp (s, "h%", 2) == 0) + { + the_insn.highlow = HIGH; + s += 2; + } + else if (strncmp (s, "l%", 2) == 0) + { + the_insn.highlow = PAIR; + s += 2; + } + the_insn.expand = insn->expand; + + /* Note that if the getExpression() fails, we will still have created U entries in the symbol table for the 'symbols' in the input string. Try not to create U symbols for registers, etc. */ - - if ( !getExpression(s)) { - s = expr_end; - continue; - } - break; - - default: - as_fatal("failed sanity check."); - } - break; + + if (!getExpression (s)) + { + s = expr_end; + continue; } - error: - if (match == 0) - { - /* Args don't match. */ - if (&insn[1] - i860_opcodes < NUMOPCODES - && !strcmp(insn->name, insn[1].name)) - { - ++insn; - s = argsStart; - continue; - } - else - { - as_bad("Illegal operands"); - return; - } - } - break; + break; + + default: + as_fatal ("failed sanity check."); + } + break; } - - the_insn.opcode = opcode; - return; + error: + if (match == 0) + { + /* Args don't match. */ + if (&insn[1] - i860_opcodes < NUMOPCODES + && !strcmp (insn->name, insn[1].name)) + { + ++insn; + s = argsStart; + continue; + } + else + { + as_bad ("Illegal operands"); + return; + } + } + break; + } + + the_insn.opcode = opcode; + return; } static int - getExpression(str) -char *str; +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_ABSENT: - break; - - default: - 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; + 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_ABSENT: + break; + + default: + 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; } /* 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. @@ -779,221 +801,225 @@ char *str; #define MAX_LITTLENUMS 6 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 ""; /* Someone should teach Dean about null pointers */ } /* * Write out big-endian. */ void - md_number_to_chars(buf,val,n) -char *buf; -long val; -int n; +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: - as_fatal("failed sanity check."); - } - return; + switch (n) + { + + case 4: + *buf++ = val >> 24; + *buf++ = val >> 16; + case 2: + *buf++ = val >> 8; + case 1: + *buf = val; + break; + + default: + as_fatal ("failed sanity check."); + } + return; } -void md_number_to_imm(buf,val,n, fixP) -char *buf; -long val; -int n; -fixS *fixP; +void +md_number_to_imm (buf, val, n, fixP) + char *buf; + long val; + int n; + fixS *fixP; { - enum reloc_type reloc = fixP->fx_r_type & 0xf; - enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3; - - assert(buf); - assert(n == 4); /* always on i860 */ - - switch(highlow) - { - - case HIGHADJ: /* adjusts the high-order 16-bits */ - if (val & (1 << 15)) - val += (1 << 16); - - /*FALLTHROUGH*/ - - case HIGH: /* selects the high-order 16-bits */ - val >>= 16; - break; - - case PAIR: /* selects the low-order 16-bits */ - val = val & 0xffff; - break; - - default: - break; - } - - switch(reloc) - { - - case BRADDR: /* br,call,bc,bc.t,bnc,bnc.t w/26-bit immediate */ - if (fixP->fx_pcrel != 1) - as_bad("26-bit branch w/o pc relative set: 0x%08x", val); - val >>= 2; /* align pcrel offset, see manual */ - - if (val >= (1 << 25) || val < -(1 << 25)) /* check for overflow */ - as_bad("26-bit branch offset overflow: 0x%08x", val); - buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3); - buf[1] = val >> 16; - buf[2] = val >> 8; - buf[3] = val; - break; - - case SPLIT2: /* 16 bit immediate, 4-byte aligned */ - if (val & 0x3) - as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val); - val &= ~0x3; /* 4-byte align value */ - /*FALLTHROUGH*/ - case SPLIT1: /* 16 bit immediate, 2-byte aligned */ - if (val & 0x1) - as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val); - val &= ~0x1; /* 2-byte align value */ - /*FALLTHROUGH*/ - case SPLIT0: /* st,bla,bte,btne w/16-bit immediate */ - if (fixP->fx_pcrel == 1) - val >>= 2; /* align pcrel offset, see manual */ - /* check for bounds */ - if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15))) - as_bad("16-bit branch offset overflow: 0x%08x", val); - buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f); - buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7); - buf[3] |= val; /* perserve bottom opcode bits */ - break; - - case LOW4: /* fld,pfld,pst,flush 16-byte aligned */ - if (val & 0xf) - as_bad("16-bit immediate 16-byte alignment error: 0x%08x", val); - val &= ~0xf; /* 16-byte align value */ - /*FALLTHROUGH*/ - case LOW3: /* fld,pfld,pst,flush 8-byte aligned */ - if (val & 0x7) - as_bad("16-bit immediate 8-byte alignment error: 0x%08x", val); - val &= ~0x7; /* 8-byte align value */ - /*FALLTHROUGH*/ - case LOW2: /* 16 bit immediate, 4-byte aligned */ - if (val & 0x3) - as_bad("16-bit immediate 4-byte alignment error: 0x%08x", val); - val &= ~0x3; /* 4-byte align value */ - /*FALLTHROUGH*/ - case LOW1: /* 16 bit immediate, 2-byte aligned */ - if (val & 0x1) - as_bad("16-bit immediate 2-byte alignment error: 0x%08x", val); - val &= ~0x1; /* 2-byte align value */ - /*FALLTHROUGH*/ - case LOW0: /* 16 bit immediate, byte aligned */ - /* check for bounds */ - if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15))) - as_bad("16-bit immediate overflow: 0x%08x", val); - buf[2] = val >> 8; - buf[3] |= val; /* perserve bottom opcode bits */ - break; - - case NO_RELOC: - default: - as_bad("bad relocation type: 0x%02x", reloc); - break; - } - return; + enum reloc_type reloc = fixP->fx_r_type & 0xf; + enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3; + + assert (buf); + assert (n == 4); /* always on i860 */ + + switch (highlow) + { + + case HIGHADJ: /* adjusts the high-order 16-bits */ + if (val & (1 << 15)) + val += (1 << 16); + + /*FALLTHROUGH*/ + + case HIGH: /* selects the high-order 16-bits */ + val >>= 16; + break; + + case PAIR: /* selects the low-order 16-bits */ + val = val & 0xffff; + break; + + default: + break; + } + + switch (reloc) + { + + case BRADDR: /* br,call,bc,bc.t,bnc,bnc.t w/26-bit immediate */ + if (fixP->fx_pcrel != 1) + as_bad ("26-bit branch w/o pc relative set: 0x%08x", val); + val >>= 2; /* align pcrel offset, see manual */ + + if (val >= (1 << 25) || val < -(1 << 25)) /* check for overflow */ + as_bad ("26-bit branch offset overflow: 0x%08x", val); + buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3); + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; + break; + + case SPLIT2: /* 16 bit immediate, 4-byte aligned */ + if (val & 0x3) + as_bad ("16-bit immediate 4-byte alignment error: 0x%08x", val); + val &= ~0x3; /* 4-byte align value */ + /*FALLTHROUGH*/ + case SPLIT1: /* 16 bit immediate, 2-byte aligned */ + if (val & 0x1) + as_bad ("16-bit immediate 2-byte alignment error: 0x%08x", val); + val &= ~0x1; /* 2-byte align value */ + /*FALLTHROUGH*/ + case SPLIT0: /* st,bla,bte,btne w/16-bit immediate */ + if (fixP->fx_pcrel == 1) + val >>= 2; /* align pcrel offset, see manual */ + /* check for bounds */ + if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15))) + as_bad ("16-bit branch offset overflow: 0x%08x", val); + buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f); + buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7); + buf[3] |= val; /* perserve bottom opcode bits */ + break; + + case LOW4: /* fld,pfld,pst,flush 16-byte aligned */ + if (val & 0xf) + as_bad ("16-bit immediate 16-byte alignment error: 0x%08x", val); + val &= ~0xf; /* 16-byte align value */ + /*FALLTHROUGH*/ + case LOW3: /* fld,pfld,pst,flush 8-byte aligned */ + if (val & 0x7) + as_bad ("16-bit immediate 8-byte alignment error: 0x%08x", val); + val &= ~0x7; /* 8-byte align value */ + /*FALLTHROUGH*/ + case LOW2: /* 16 bit immediate, 4-byte aligned */ + if (val & 0x3) + as_bad ("16-bit immediate 4-byte alignment error: 0x%08x", val); + val &= ~0x3; /* 4-byte align value */ + /*FALLTHROUGH*/ + case LOW1: /* 16 bit immediate, 2-byte aligned */ + if (val & 0x1) + as_bad ("16-bit immediate 2-byte alignment error: 0x%08x", val); + val &= ~0x1; /* 2-byte align value */ + /*FALLTHROUGH*/ + case LOW0: /* 16 bit immediate, byte aligned */ + /* check for bounds */ + if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15))) + as_bad ("16-bit immediate overflow: 0x%08x", val); + buf[2] = val >> 8; + buf[3] |= val; /* perserve bottom opcode bits */ + break; + + case NO_RELOC: + default: + as_bad ("bad relocation type: 0x%02x", reloc); + break; + } + return; } /* should never be called for i860 */ void - md_create_short_jump(ptr, from_addr, to_addr, frag, to_symbol) -char *ptr; -long from_addr, to_addr; -fragS *frag; -symbolS *to_symbol; +md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; { - as_fatal("i860_create_short_jmp\n"); + as_fatal ("i860_create_short_jmp\n"); } /* should never be called for i860 */ void - md_number_to_disp(buf,val,n) -char *buf; -long val; +md_number_to_disp (buf, val, n) + char *buf; + long val; { - as_fatal("md_number_to_disp\n"); + as_fatal ("md_number_to_disp\n"); } /* should never be called for i860 */ void - md_number_to_field(buf,val,fix) -char *buf; -long val; -void *fix; +md_number_to_field (buf, val, fix) + char *buf; + long val; + void *fix; { - as_fatal("i860_number_to_field\n"); + as_fatal ("i860_number_to_field\n"); } -/* the bit-field entries in the relocation_info struct plays hell +/* 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 */ @@ -1003,170 +1029,250 @@ void *fix; relocation type (highlow 5-4). Next 4 bytes are long addend. */ /* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */ void - md_ri_to_chars(ri_p, ri) -struct relocation_info *ri_p, ri; +md_ri_to_chars (ri_p, ri) + struct relocation_info *ri_p, ri; { #if 0 - unsigned char the_bytes[sizeof(*ri_p)]; - - /* this is easy */ - md_number_to_chars(the_bytes, ri.r_address, sizeof(ri.r_address)); - /* now the fun stuff */ - the_bytes[4] = (ri.r_index >> 16) & 0x0ff; - the_bytes[5] = (ri.r_index >> 8) & 0x0ff; - the_bytes[6] = ri.r_index & 0x0ff; - the_bytes[7] = ((ri.r_extern << 7) & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F); - /* Also easy */ - md_number_to_chars(&the_bytes[8], ri.r_addend, sizeof(ri.r_addend)); - /* now put it back where you found it, Junior... */ - memcpy((char *) ri_p, the_bytes, sizeof(*ri_p)); + unsigned char the_bytes[sizeof (*ri_p)]; + + /* this is easy */ + md_number_to_chars (the_bytes, ri.r_address, sizeof (ri.r_address)); + /* now the fun stuff */ + the_bytes[4] = (ri.r_index >> 16) & 0x0ff; + the_bytes[5] = (ri.r_index >> 8) & 0x0ff; + the_bytes[6] = ri.r_index & 0x0ff; + the_bytes[7] = ((ri.r_extern << 7) & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F); + /* Also easy */ + md_number_to_chars (&the_bytes[8], ri.r_addend, sizeof (ri.r_addend)); + /* now put it back where you found it, Junior... */ + memcpy ((char *) ri_p, the_bytes, sizeof (*ri_p)); #endif } /* should never be called for i860 */ void - md_convert_frag(headers, fragP) -object_headers *headers; -register fragS *fragP; +md_convert_frag (headers, fragP) + object_headers *headers; + register fragS *fragP; { - as_fatal("i860_convert_frag\n"); + as_fatal ("i860_convert_frag\n"); } /* should never be called for i860 */ 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("i860_create_long_jump\n"); + as_fatal ("i860_create_long_jump\n"); } /* should never be called for i860 */ int - md_estimate_size_before_relax(fragP, segtype) -register fragS *fragP; -segT segtype; +md_estimate_size_before_relax (fragP, segtype) + register fragS *fragP; + segT segtype; { - as_fatal("i860_estimate_size_before_relax\n"); + as_fatal ("i860_estimate_size_before_relax\n"); } /* for debugging only, must match enum reloc_type */ -static char *Reloc[] = { - "NO_RELOC", - "BRADDR", - "LOW0", - "LOW1", - "LOW2", - "LOW3", - "LOW4", - "SPLIT0", - "SPLIT1", - "SPLIT2", - "RELOC_32", +static char *Reloc[] = +{ + "NO_RELOC", + "BRADDR", + "LOW0", + "LOW1", + "LOW2", + "LOW3", + "LOW4", + "SPLIT0", + "SPLIT1", + "SPLIT2", + "RELOC_32", }; -static char *Highlow[] = { - "NO_SPEC", - "PAIR", - "HIGH", - "HIGHADJ", +static char *Highlow[] = +{ + "NO_SPEC", + "PAIR", + "HIGH", + "HIGHADJ", }; static void - print_insn(insn) -struct i860_it *insn; +print_insn (insn) + struct i860_it *insn; { - if (insn->error) { - fprintf(stderr, "ERROR: %s\n"); - } - fprintf(stderr, "opcode=0x%08x\t", insn->opcode); - fprintf(stderr, "expand=0x%08x\t", insn->expand); - fprintf(stderr, "reloc = %s\t", Reloc[insn->reloc]); - fprintf(stderr, "highlow = %s\n", Highlow[insn->highlow]); - fprintf(stderr, "exp = {\n"); - fprintf(stderr, "\t\tX_add_symbol = %s\n", - insn->exp.X_add_symbol ? - (S_GET_NAME(insn->exp.X_add_symbol) ? - S_GET_NAME(insn->exp.X_add_symbol) : "???") : "0"); - fprintf(stderr, "\t\tX_sub_symbol = %s\n", - insn->exp.X_subtract_symbol ? - (S_GET_NAME(insn->exp.X_subtract_symbol) ? - S_GET_NAME(insn->exp.X_subtract_symbol) : "???") : "0"); - fprintf(stderr, "\t\tX_add_number = %d\n", - insn->exp.X_add_number); - fprintf(stderr, "}\n"); - return; + if (insn->error) + { + fprintf (stderr, "ERROR: %s\n"); + } + fprintf (stderr, "opcode=0x%08x\t", insn->opcode); + fprintf (stderr, "expand=0x%08x\t", insn->expand); + fprintf (stderr, "reloc = %s\t", Reloc[insn->reloc]); + fprintf (stderr, "highlow = %s\n", Highlow[insn->highlow]); + fprintf (stderr, "exp = {\n"); + fprintf (stderr, "\t\tX_add_symbol = %s\n", + insn->exp.X_add_symbol ? + (S_GET_NAME (insn->exp.X_add_symbol) ? + S_GET_NAME (insn->exp.X_add_symbol) : "???") : "0"); + fprintf (stderr, "\t\tX_sub_symbol = %s\n", + insn->exp.X_subtract_symbol ? + (S_GET_NAME (insn->exp.X_subtract_symbol) ? + S_GET_NAME (insn->exp.X_subtract_symbol) : "???") : "0"); + fprintf (stderr, "\t\tX_add_number = %d\n", + insn->exp.X_add_number); + fprintf (stderr, "}\n"); + 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 1; + return 1; } +#ifdef comment /* * I860 relocations are completely different, so it needs * this machine dependent routine to emit them. */ void - emit_machine_reloc(fixP, segment_address_in_file) -register fixS *fixP; -relax_addressT segment_address_in_file; +emit_machine_reloc (fixP, segment_address_in_file) + register fixS *fixP; + relax_addressT segment_address_in_file; { - struct reloc_info_i860 ri; - register symbolS *symbolP; - extern char *next_object_file_charP; - long add_number; - - memset((char *) &ri, '\0', sizeof(ri)); - for (; fixP; fixP = fixP->fx_next) { - - if (fixP->fx_r_type & ~0x3f) { - as_fatal("fixP->fx_r_type = %d\n", fixP->fx_r_type); - } - ri.r_pcrel = fixP->fx_pcrel; - ri.r_type = fixP->fx_r_type; - - if ((symbolP = fixP->fx_addsy) != NULL) { - ri.r_address = fixP->fx_frag->fr_address + - fixP->fx_where - segment_address_in_file; - if ((symbolP->sy_type & N_TYPE) == N_UNDF) { - ri.r_extern = 1; - ri.r_symbolnum = symbolP->sy_number; - } else { - ri.r_extern = 0; - ri.r_symbolnum = symbolP->sy_type & N_TYPE; - } - if (symbolP && symbolP->sy_frag) { - ri.r_addend = symbolP->sy_frag->fr_address; - } - ri.r_type = fixP->fx_r_type; - if (fixP->fx_pcrel) { - /* preserve actual offset vs. pc + 4 */ - ri.r_addend -= (ri.r_address + 4); - } else { - ri.r_addend = fixP->fx_addnumber; - } - - md_ri_to_chars((char *) &ri, ri); - append(&next_object_file_charP, (char *)& ri, sizeof(ri)); - } + struct reloc_info_i860 ri; + register symbolS *symbolP; + extern char *next_object_file_charP; + long add_number; + + memset ((char *) &ri, '\0', sizeof (ri)); + for (; fixP; fixP = fixP->fx_next) + { + + if (fixP->fx_r_type & ~0x3f) + { + as_fatal ("fixP->fx_r_type = %d\n", fixP->fx_r_type); } - return; + ri.r_pcrel = fixP->fx_pcrel; + ri.r_type = fixP->fx_r_type; + + if ((symbolP = fixP->fx_addsy) != NULL) + { + ri.r_address = fixP->fx_frag->fr_address + + fixP->fx_where - segment_address_in_file; + if (!S_IS_DEFINED (symbolP)) + { + ri.r_extern = 1; + ri.r_symbolnum = symbolP->sy_number; + } + else + { + ri.r_extern = 0; + ri.r_symbolnum = S_GET_TYPE (symbolP); + } + if (symbolP && symbolP->sy_frag) + { + ri.r_addend = symbolP->sy_frag->fr_address; + } + ri.r_type = fixP->fx_r_type; + if (fixP->fx_pcrel) + { + /* preserve actual offset vs. pc + 4 */ + ri.r_addend -= (ri.r_address + 4); + } + else + { + ri.r_addend = fixP->fx_addnumber; + } + + md_ri_to_chars ((char *) &ri, ri); + append (&next_object_file_charP, (char *) &ri, sizeof (ri)); + } + } + return; } -/* Parse an operand that is machine-specific. +#endif /* comment */ + +#ifdef OBJ_AOUT + +/* on i860: 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 pcrel, bit 6 as extern, and the lower six bits as + relocation type (highlow 5-4). Next 4 bytes are long addend. */ + +void +tc_aout_fix_to_chars (where, fixP, segment_address_in_file) + char *where; + fixS *fixP; + relax_addressT segment_address_in_file; +{ + long r_index; + long r_extern; + long r_addend = 0; + long r_address; + + know (fixP->fx_addsy); + know (!(fixP->fx_r_type & ~0x3f)); + + if (!S_IS_DEFINED (fixP->fx_addsy)) + { + r_extern = 1; + r_index = fixP->fx_addsy->sy_number; + } + else + { + r_extern = 0; + r_index = S_GET_TYPE (fixP->fx_addsy); + } + + md_number_to_chars (where, + r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, + 4); + + where[4] = (r_index >> 16) & 0x0ff; + where[5] = (r_index >> 8) & 0x0ff; + where[6] = r_index & 0x0ff; + where[7] = (((fixP->fx_pcrel << 7) & 0x80) + | ((r_extern << 6) & 0x40) + | (fixP->fx_r_type & 0x3F)); + + if (fixP->fx_addsy->sy_frag) + { + r_addend = fixP->fx_addsy->sy_frag->fr_address; + } + + if (fixP->fx_pcrel) + { + /* preserve actual offset vs. pc + 4 */ + r_addend -= (r_address + 4); + } + else + { + r_addend = fixP->fx_addnumber; + } + + md_number_to_chars (&where[8], r_addend, 4); + + return; +} /* tc_aout_fix_to_chars() */ + +#endif /* OBJ_AOUT */ + +/* 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; +md_operand (expressionP) + expressionS *expressionP; { } @@ -1174,67 +1280,76 @@ expressionS *expressionP; /* ARGSUSED */ symbolS * - md_undefined_symbol (name) -char *name; +md_undefined_symbol (name) + char *name; { - return 0; + return 0; } /* Round up a section size to the appropriate boundary. */ -long - md_section_align (segment, size) -segT segment; -long size; +valueT +md_section_align (segment, size) + segT segment; + valueT size; { - return size; /* Byte alignment is fine */ + return size; /* Byte alignment is fine */ } /* Exactly what point is a PC-relative offset relative TO? On the i860, they're relative to the address of the offset, plus its size. (??? Is this right? FIXME-SOON!) */ long - md_pcrel_from (fixP) -fixS *fixP; +md_pcrel_from (fixP) + fixS *fixP; { - return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; } void - md_apply_fix(fixP, val) -fixS *fixP; -long val; +md_apply_fix (fixP, val) + fixS *fixP; + long val; { - char *place = fixP->fx_where + fixP->fx_frag->fr_literal; - - if (!fixP->fx_bit_fixP) { - - switch (fixP->fx_im_disp) { - case 0: - fixP->fx_addnumber = val; - md_number_to_imm(place, val, fixP->fx_size, fixP); - break; - case 1: - md_number_to_disp (place, - fixP->fx_pcrel ? val+fixP->fx_pcrel_adjust:val, - fixP->fx_size); - break; - case 2: /* fix requested for .long .word etc */ - md_number_to_chars (place, val, fixP->fx_size); - break; - default: - as_fatal("Internal error in md_apply_fix() in file \"%s\"", __FILE__); - } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */ - } else { - md_number_to_field (place, val, fixP->fx_bit_fixP); - } - - return; -} /* md_apply_fix() */ + char *place = fixP->fx_where + fixP->fx_frag->fr_literal; + + /* looks to me like i860 never has bit fixes. Let's see. xoxorich. */ + know (fixP->fx_bit_fixP == NULL); + if (!fixP->fx_bit_fixP) + { + + /* also looks like fx_im_disp is always 0. Let's see. xoxorich. */ + know (fixP->fx_im_disp == 0); + switch (fixP->fx_im_disp) + { + case 0: + fixP->fx_addnumber = val; + md_number_to_imm (place, val, fixP->fx_size, fixP); + break; + case 1: + md_number_to_disp (place, + fixP->fx_pcrel ? val + fixP->fx_pcrel_adjust : val, + fixP->fx_size); + break; + case 2: /* fix requested for .long .word etc */ + md_number_to_chars (place, val, fixP->fx_size); + break; + default: + as_fatal ("Internal error in md_apply_fix() in file \"%s\"", __FILE__); + } /* OVE: maybe one ought to put _imm _disp _chars in one md-func */ + } + else + { + md_number_to_field (place, val, fixP->fx_bit_fixP); + } + + return; +} /* md_apply_fix() */ /* * Local Variables: * fill-column: 131 * comment-column: 0 + * End: */ /* end of tc-i860.c */ diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c index f916fa7..d176838 100644 --- a/gas/config/tc-m68k.c +++ b/gas/config/tc-m68k.c @@ -3585,7 +3585,8 @@ md_assemble (str) current_architecture |= m68881; } if (!no_68851 - && (cpu_of_arch (current_architecture) & m68020up) != 0) + && (cpu_of_arch (current_architecture) & m68020up) != 0 + && cpu_of_arch (current_architecture) != m68040) { current_architecture |= m68851; } @@ -3942,7 +3943,7 @@ md_atof (type, litP, sizeP) void md_number_to_chars (buf, val, n) char *buf; - long val; + valueT val; int n; { switch (n) @@ -4535,40 +4536,40 @@ CONST int md_long_jump_size = 6; void md_create_short_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; { - long offset; + valueT offset; offset = to_addr - (from_addr + 2); - md_number_to_chars (ptr, (long) 0x6000, 2); - md_number_to_chars (ptr + 2, (long) offset, 2); + md_number_to_chars (ptr, (valueT) 0x6000, 2); + md_number_to_chars (ptr + 2, (valueT) offset, 2); } 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; { - long offset; + valueT offset; if (cpu_of_arch (current_architecture) < m68020) { offset = to_addr - S_GET_VALUE (to_symbol); - md_number_to_chars (ptr, (long) 0x4EF9, 2); - md_number_to_chars (ptr + 2, (long) offset, 4); + md_number_to_chars (ptr, (valueT) 0x4EF9, 2); + md_number_to_chars (ptr + 2, (valueT) offset, 4); fix_new (frag, (ptr + 2) - frag->fr_literal, 4, to_symbol, (symbolS *) 0, (long) 0, 0, NO_RELOC); } else { offset = to_addr - (from_addr + 2); - md_number_to_chars (ptr, (long) 0x60ff, 2); - md_number_to_chars (ptr + 2, (long) offset, 4); + md_number_to_chars (ptr, (valueT) 0x60ff, 2); + md_number_to_chars (ptr + 2, (valueT) offset, 4); } } @@ -5095,10 +5096,10 @@ md_operand (expressionP) } /* Round up a section size to the appropriate boundary. */ -long +valueT md_section_align (segment, size) segT segment; - long size; + valueT size; { return size; /* Byte alignment is fine */ } diff --git a/gas/config/tc-ns32k.c b/gas/config/tc-ns32k.c index db49ef3..db0d4f11 100644 --- a/gas/config/tc-ns32k.c +++ b/gas/config/tc-ns32k.c @@ -21,15 +21,9 @@ #include <stdio.h> #include <ctype.h> -#ifdef USG -#include <string.h> -#else -#include <strings.h> -#endif #include "opcode/ns32k.h" #include "as.h" -#include "read.h" #include "obstack.h" @@ -1536,7 +1530,7 @@ md_atof (type, litP, sizeP) void md_number_to_chars (buf, value, nbytes) char *buf; - long value; + valueT value; int nbytes; { while (nbytes--) @@ -1709,12 +1703,11 @@ tc_aout_fix_to_chars (where, fixP, segment_address_in_file) relax_addressT segment_address_in_file; { /* - * In: length of relocation (or of address) in chars: 1, 2 or 4. - * Out: GNU LD relocation length code: 0, 1, or 2. - */ + * In: length of relocation (or of address) in chars: 1, 2 or 4. + * Out: GNU LD relocation length code: 0, 1, or 2. + */ - static unsigned char nbytes_r_length[] = - {42, 0, 1, 42, 2}; + static unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2}; long r_symbolnum; know (fixP->fx_addsy != NULL); @@ -1735,9 +1728,7 @@ tc_aout_fix_to_chars (where, fixP, segment_address_in_file) | (long) (fixP->fx_bsr << 28) | (long) (fixP->fx_im_disp << 29)), 4); - - return; -} /* tc_aout_fix_to_chars() */ +} #endif /* OBJ_AOUT */ @@ -1977,34 +1968,34 @@ md_estimate_size_before_relax (fragP, segment) int md_short_jump_size = 3; int md_long_jump_size = 5; -int md_reloc_size = 8; /* Size of relocation record */ +const int md_reloc_size = 8; /* Size of relocation record */ void md_create_short_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; { - long offset; + valueT offset; offset = to_addr - from_addr; - md_number_to_chars (ptr, (long) 0xEA, 1); - md_number_to_disp (ptr + 1, (long) offset, 2); + md_number_to_chars (ptr, (valueT) 0xEA, 1); + md_number_to_disp (ptr + 1, (valueT) offset, 2); } 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; { - long offset; + valueT offset; offset = to_addr - from_addr; - md_number_to_chars (ptr, (long) 0xEA, 2); - md_number_to_disp (ptr + 2, (long) offset, 4); + md_number_to_chars (ptr, (valueT) 0xEA, 2); + md_number_to_disp (ptr + 2, (valueT) offset, 4); } /* JF this is a new function to parse machine-dep options */ @@ -2099,6 +2090,20 @@ fix_new_ns32k (frag, where, size, add_symbol, sub_symbol, offset, pcrel, fixP->fx_bsr = bsr; } /* fix_new_ns32k() */ +/* This is TC_CONS_FIX_NEW, called by emit_expr in read.c. */ + +void +cons_fix_new_ns32k (frag, where, size, exp) + fragS *frag; /* Which frag? */ + int where; /* Where in that frag? */ + int size; /* 1, 2 or 4 usually. */ + expressionS *exp; /* Expression. */ +{ + fix_new_ns32k (frag, where, size, exp->X_add_symbol, + exp->X_subtract_symbol, exp->X_add_number, + 0, 0, 2, 0, 0); +} + /* We have no need to default values of symbols. */ symbolS * @@ -2120,10 +2125,10 @@ md_operand (expressionP) } /* Round up a section size to the appropriate boundary. */ -long +valueT md_section_align (segment, size) segT segment; - long size; + valueT size; { return size; /* Byte alignment is fine */ } diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c new file mode 100644 index 0000000..fe6c2a6 --- /dev/null +++ b/gas/config/tc-sh.c @@ -0,0 +1,1390 @@ +/* tc-sh.c -- Assemble code for the Hitachi Super-H + + Copyright (C) 1993 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 + */ + +#include <stdio.h> +#include "as.h" +#include "bfd.h" +#include "subsegs.h" +#define DEFINE_TABLE +#include "../opcodes/sh-opc.h" +#include <ctype.h> + +const char comment_chars[] = "!"; +const char line_separator_chars[] = ";"; +const char line_comment_chars[] = "!"; + +/* This table describes all the machine specific pseudo-ops the assembler + has to support. The fields are: + pseudo-op name without dot + function to call to execute this pseudo-op + Integer arg to pass to the function + */ + +void cons (); +void s_align_bytes (); + +const pseudo_typeS md_pseudo_table[] = +{ + {"int", cons, 4}, + {"word", cons, 2}, + {"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;*/ + +static int relax; /* set if -relax seen */ + +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"; + +#define C(a,b) ENCODE_RELAX(a,b) + +#define JREG 14 /* Register used as a temp when relaxing */ +#define ENCODE_RELAX(what,length) (((what) << 4) + (length)) +#define GET_WHAT(x) ((x>>4)) + +/* These are the two types of relaxable instrction */ +#define COND_JUMP 1 +#define UNCOND_JUMP 2 + +#define UNDEF_DISP 0 +#define COND8 1 +#define COND12 2 +#define COND32 3 +#define UNCOND12 1 +#define UNCOND32 2 +#define UNDEF_WORD_DISP 4 +#define END 5 + +#define UNCOND12 1 +#define UNCOND32 2 + +#define COND8_F 254 +#define COND8_M -256 +#define COND8_LENGTH 2 +#define COND12_F (4094 - 4) /* -4 since there are two extra */ +/* instructions needed */ +#define COND12_M -4096 +#define COND12_LENGTH 6 +#define COND32_F (1<<30) +#define COND32_M -(1<<30) +#define COND32_LENGTH 14 + +#define COND8_RANGE(x) ((x) > COND8_M && (x) < COND8_F) +#define COND12_RANGE(x) ((x) > COND12_M && (x) < COND12_F) + +#define UNCOND12_F 4094 +#define UNCOND12_M -4096 +#define UNCOND12_LENGTH 2 + +#define UNCOND32_F (1<<30) +#define UNCOND32_M -(1<<30) +#define UNCOND32_LENGTH 14 + + +const relax_typeS md_relax_table[C (END, 0)]; + +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 + */ + +void +md_begin () +{ + sh_opcode_info *opcode; + char *prev_name = ""; + + opcode_hash_control = hash_new (); + + /* Insert unique names into hash table */ + for (opcode = sh_table; opcode->name; opcode++) + { + if (strcmp (prev_name, opcode->name)) + { + prev_name = opcode->name; + hash_insert (opcode_hash_control, opcode->name, (char *) opcode); + } + else + { + /* Make all the opcodes with the same name point to the same + string */ + opcode->name = prev_name; + } + } + + /* Initialize the relax table */ + md_relax_table[C (COND_JUMP, COND8)].rlx_forward = COND8_F; + md_relax_table[C (COND_JUMP, COND8)].rlx_backward = COND8_M; + md_relax_table[C (COND_JUMP, COND8)].rlx_length = COND8_LENGTH; + md_relax_table[C (COND_JUMP, COND8)].rlx_more = C (COND_JUMP, COND12); + + md_relax_table[C (COND_JUMP, COND12)].rlx_forward = COND12_F; + md_relax_table[C (COND_JUMP, COND12)].rlx_backward = COND12_M; + md_relax_table[C (COND_JUMP, COND12)].rlx_length = COND12_LENGTH; + md_relax_table[C (COND_JUMP, COND12)].rlx_more = C (COND_JUMP, COND32); + + md_relax_table[C (COND_JUMP, COND32)].rlx_forward = COND32_F; + md_relax_table[C (COND_JUMP, COND32)].rlx_backward = COND32_M; + md_relax_table[C (COND_JUMP, COND32)].rlx_length = COND32_LENGTH; + md_relax_table[C (COND_JUMP, COND32)].rlx_more = 0; + + + md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_forward = UNCOND12_F; + md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_backward = UNCOND12_M; + md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length = UNCOND12_LENGTH; + md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_more = C (UNCOND_JUMP, UNCOND32); + + md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_forward = UNCOND32_F; + md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_backward = UNCOND32_M; + md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length = UNCOND32_LENGTH; + md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_more = 0; + + +} + +static int reg_m; +static int reg_n; +static expressionS immediate; /* absolute expression */ + +typedef struct +{ + sh_arg_type type; + int reg; +} + +sh_operand_info; + +/* try and parse a reg name, returns number of chars consumed */ +static int +parse_reg (src, mode, reg) + char *src; + int *mode; + int *reg; +{ + if (src[0] == 'r') + { + if (src[1] == '1') + { + if (src[2] >= '0' && src[2] <= '5') + { + *mode = A_REG_N; + *reg = 10 + src[2] - '0'; + return 3; + } + } + if (src[1] >= '0' && src[1] <= '9') + { + *mode = A_REG_N; + *reg = (src[1] - '0'); + return 2; + } + } + + if (src[0] == 's' && src[1] == 'r') + { + *mode = A_SR; + return 2; + } + + if (src[0] == 's' && src[1] == 'p') + { + *mode = A_REG_N; + *reg = 15; + return 2; + } + + if (src[0] == 'p' && src[1] == 'r') + { + *mode = A_PR; + return 2; + } + if (src[0] == 'p' && src[1] == 'c') + { + *mode = A_DISP_PC; + return 2; + } + if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r') + { + *mode = A_GBR; + return 3; + } + if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r') + { + *mode = A_VBR; + return 3; + } + + if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c') + { + if (src[3] == 'l') + { + *mode = A_MACL; + return 4; + } + if (src[3] == 'h') + { + *mode = A_MACH; + return 4; + } + } + + return 0; +} + +static +char * +parse_exp (s) + char *s; +{ + char *save; + char *new; + segT seg; + + save = input_line_pointer; + + + input_line_pointer = s; + + seg = expr (0, &immediate); + 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; + } +} + + +/* The many forms of operand: + + Rn Register direct + @Rn Register indirect + @Rn+ Autoincrement + @-Rn Autodecrement + @(disp:4,Rn) + @(disp:8,GBR) + @(disp:8,PC) + + @(R0,Rn) + @(R0,GBR) + + disp:8 + disp:12 + #imm8 + pr, gbr, vbr, macl, mach + + */ + +static +char * +parse_at (src, op) + char *src; + sh_operand_info *op; +{ + int len; + int mode; + src++; + if (src[0] == '-') + { + /* Must be predecrement */ + src++; + + len = parse_reg (src, &mode, &(op->reg)); + if (mode != A_REG_N) + as_bad ("illegal register after @-"); + + op->type = A_DEC_N; + src += len; + } + else if (src[0] == '(') + { + /* Could be @(disp, rn), @(disp, gbr), @(disp, pc), @(r0, gbr) or + @(r0, rn) */ + src++; + len = parse_reg (src, &mode, &(op->reg)); + if (len && mode == A_REG_N) + { + src += len; + if (op->reg != 0) + { + as_bad ("must be @(r0,...)"); + } + if (src[0] == ',') + src++; + /* Now can be rn or gbr */ + len = parse_reg (src, &mode, &(op->reg)); + if (mode == A_GBR) + { + op->type = A_R0_GBR; + } + else if (mode == A_REG_N) + { + op->type = A_IND_R0_REG_N; + } + else + { + as_bad ("syntax error in @(r0,...)"); + } + } + else + { + /* Must be an @(disp,.. thing) */ + src = parse_exp (src); + if (src[0] == ',') + src++; + /* Now can be rn, gbr or pc */ + len = parse_reg (src, &mode, &op->reg); + if (len) + { + if (mode == A_REG_N) + { + op->type = A_DISP_REG_N; + } + else if (mode == A_GBR) + { + op->type = A_DISP_GBR; + } + else if (mode == A_DISP_PC) + { + op->type = A_DISP_PC; + } + else + { + as_bad ("syntax error in @(disp,[Rn, gbr, pc])"); + } + } + else + { + as_bad ("syntax error in @(disp,[Rn, gbr, pc])"); + } + } + src += len; + if (src[0] != ')') + as_bad ("expecting )"); + else + src++; + } + else + { + src += parse_reg (src, &mode, &(op->reg)); + if (mode != A_REG_N) + { + as_bad ("illegal register after @"); + } + if (src[0] == '+') + { + op->type = A_INC_N; + src++; + } + else + { + op->type = A_IND_N; + } + } + return src; +} + +static void +get_operand (ptr, op) + char **ptr; + sh_operand_info *op; +{ + char *src = *ptr; + int mode = -1; + unsigned int len; + + if (src[0] == '#') + { + src++; + *ptr = parse_exp (src); + op->type = A_IMM; + return; + } + + else if (src[0] == '@') + { + *ptr = parse_at (src, op); + return; + } + len = parse_reg (src, &mode, &(op->reg)); + if (len) + { + *ptr = src + len; + op->type = mode; + return; + } + else + { + /* Not a reg, the only thing left is a displacement */ + *ptr = parse_exp (src); + op->type = A_DISP_PC; + return; + } +} + +static +char * +get_operands (info, args, operand) + sh_opcode_info *info; + char *args; + sh_operand_info *operand; + +{ + char *ptr = args; + if (info->arg[0]) + { + ptr++; + + get_operand (&ptr, operand + 0); + if (info->arg[1]) + { + if (*ptr == ',') + { + ptr++; + } + get_operand (&ptr, operand + 1); + } + else + { + operand[1].type = 0; + } + } + else + { + operand[0].type = 0; + operand[1].type = 0; + } + return ptr; +} + +/* Passed a pointer to a list of opcodes which use different + addressing modes, return the opcode which matches the opcodes + provided + */ + +static +sh_opcode_info * +get_specific (opcode, operands) + sh_opcode_info *opcode; + sh_operand_info *operands; +{ + sh_opcode_info *this_try = opcode; + char *name = opcode->name; + int arg_to_test = 0; + int n = 0; + while (opcode->name) + { + this_try = opcode++; + if (this_try->name != name) + { + /* We've looked so far down the table that we've run out of + opcodes with the same name */ + return 0; + } + /* look at both operands needed by the opcodes and provided by + the user - since an arg test will often fail on the same arg + again and again, we'll try and test the last failing arg the + first on each opcode try */ + + for (n = 0; this_try->arg[n]; n++) + { + sh_operand_info *user = operands + arg_to_test; + sh_arg_type arg = this_try->arg[arg_to_test]; + switch (arg) + { + case A_IMM: + case A_BDISP12: + case A_BDISP8: + case A_DISP_GBR: + case A_DISP_PC: + case A_MACH: + case A_PR: + case A_MACL: + if (user->type != arg) + goto fail; + break; + case A_R0: + /* opcode needs r0 */ + if (user->type != A_REG_N || user->reg != 0) + goto fail; + break; + case A_R0_GBR: + if (user->type != A_R0_GBR || user->reg != 0) + goto fail; + break; + + case A_REG_N: + case A_INC_N: + case A_DEC_N: + case A_IND_N: + case A_IND_R0_REG_N: + case A_DISP_REG_N: + /* Opcode needs rn */ + if (user->type != arg) + goto fail; + reg_n = user->reg; + break; + case A_GBR: + case A_SR: + case A_VBR: + if (user->type != arg) + goto fail; + break; + + case A_REG_M: + case A_INC_M: + case A_DEC_M: + case A_IND_M: + case A_IND_R0_REG_M: + case A_DISP_REG_M: + /* Opcode needs rn */ + if (user->type != arg - A_REG_M + A_REG_N) + goto fail; + reg_m = user->reg; + break; + default: + printf ("unhandled %d\n", arg); + goto fail; + } + /* If we did 0, test 1 next, else 0 */ + arg_to_test = 1 - arg_to_test; + } + return this_try; + fail:; + } + + return 0; +} + +int +check (operand, low, high) + expressionS *operand; + int low; + int high; +{ + if (operand->X_seg != SEG_ABSOLUTE + || operand->X_add_number < low + || operand->X_add_number > high) + { + as_bad ("operand must be absolute in range %d..%d", low, high); + } + return operand->X_add_number; +} + + +static void +insert (where, how, pcrel) + char *where; + int how; + int pcrel; +{ + fix_new (frag_now, + where - frag_now->fr_literal, + 4, + immediate.X_add_symbol, + immediate.X_subtract_symbol, + immediate.X_add_number, + pcrel, + how); + +} + +static void +build_relax (opcode) + sh_opcode_info *opcode; +{ + int len; + char *p; + if (opcode->arg[0] == A_BDISP8) + { + p = frag_var (rs_machine_dependent, + md_relax_table[C (COND_JUMP, COND32)].rlx_length, + len = md_relax_table[C (COND_JUMP, COND8)].rlx_length, + C (COND_JUMP, 0), + immediate.X_add_symbol, + immediate.X_add_number, + 0); + p[0] = (opcode->nibbles[0] << 4) | (opcode->nibbles[1]); + } + else if (opcode->arg[0] == A_BDISP12) + { + p = frag_var (rs_machine_dependent, + md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length, + len = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length, + C (UNCOND_JUMP, 0), + immediate.X_add_symbol, + immediate.X_add_number, + 0); + p[0] = (opcode->nibbles[0] << 4); + } + +} + +/* Now we know what sort of opcodes it is, lets build the bytes - + */ +static void +build_Mytes (opcode, operand) + sh_opcode_info *opcode; + sh_operand_info *operand; + +{ + int index; + char nbuf[4]; + char *output = frag_more (2); + + nbuf[0] = 0; + nbuf[1] = 0; + nbuf[2] = 0; + nbuf[3] = 0; + + for (index = 0; index < 4; index++) + { + sh_nibble_type i = opcode->nibbles[index]; + if (i < 16) + { + nbuf[index] = i; + } + else + { + switch (i) + { + case REG_N: + nbuf[index] = reg_n; + break; + case REG_M: + nbuf[index] = reg_m; + break; + case DISP_4: + insert (output + 1, R_SH_IMM4, 0); + break; + case IMM_4BY4: + insert (output + 1, R_SH_IMM4BY4, 0); + break; + case IMM_4BY2: + insert (output + 1, R_SH_IMM4BY2, 0); + break; + case IMM_4: + insert (output + 1, R_SH_IMM4, 0); + break; + case IMM_8BY4: + insert (output + 1, R_SH_IMM8BY4, 0); + break; + case IMM_8BY2: + insert (output + 1, R_SH_IMM8BY2, 0); + break; + case IMM_8: + insert (output + 1, R_SH_IMM8, 0); + break; + case PCRELIMM_8BY4: + insert (output + 1, R_SH_PCRELIMM8BY4, 0); + break; + case PCRELIMM_8BY2: + insert (output + 1, R_SH_PCRELIMM8BY2, 0); + break; + default: + printf ("failed for %d\n", i); + } + } + } + output[0] = (nbuf[0] << 4) | (nbuf[1]); + output[1] = (nbuf[2] << 4) | (nbuf[3]); +} + +/* This is the guts of the machine-dependent assembler. STR points to a + machine dependent instruction. This function is supposed to emit + the frags/bytes it assembles to. + */ + +void +md_assemble (str) + char *str; +{ + unsigned char *op_start; + unsigned char *op_end; + sh_operand_info operand[2]; + sh_opcode_info *opcode; + unsigned char *name; + + int nlen = 0; + + /* Drop leading whitespace */ + while (*str == ' ') + str++; + + /* find the op code end */ + for (name = op_start = op_end = (unsigned char *) (str); + *op_end && + !is_end_of_line[*op_end] && *op_end != ' '; + op_end++) + { + nlen++; + } + name[nlen] = 0; + + if (op_end == op_start) + { + as_bad ("can't find opcode "); + } + + opcode = (sh_opcode_info *) hash_find (opcode_hash_control, name); + + if (opcode == NULL) + { + as_bad ("unknown opcode"); + return; + } + + if (opcode->arg[0] == A_BDISP12 + || opcode->arg[0] == A_BDISP8) + { + input_line_pointer = parse_exp (op_end + 1); + build_relax (opcode); + } + else + { + input_line_pointer = get_operands (opcode, op_end, operand); + + 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; + as_bad ("invalid operands for opcode"); + return; + } + + build_Mytes (opcode, operand); + } + +} + +void +DEFUN (tc_crawl_symbol_chain, (headers), + object_headers * headers) +{ + printf ("call to tc_crawl_symbol_chain \n"); +} + +symbolS * +DEFUN (md_undefined_symbol, (name), + char *name) +{ + return 0; +} + +void +DEFUN (tc_headers_hook, (headers), + object_headers * headers) +{ + printf ("call to tc_headers_hook \n"); +} + +void +DEFUN_VOID (md_end) +{ +} + +/* Various routines to kill one day */ +/* Equal to MAX_PRECISION in atof-ieee.c */ +#define MAX_LITTLENUMS 6 + +/* 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. + */ +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_NTOF()"; + } + 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 +md_parse_option (argP, cntP, vecP) + char **argP; + int *cntP; + char ***vecP; + +{ + if (!strcmp (*argP, "relax")) + { + relax = 1; + **argP = 0; + } + return 1; +} + +int md_short_jump_size; + +void +tc_Nout_fix_to_chars () +{ + printf ("call to tc_Nout_fix_to_chars \n"); + abort (); +} + +void +md_create_short_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol) + char *ptr; + addressT from_Nddr; + addressT to_Nddr; + fragS *frag; + symbolS *to_symbol; +{ + as_fatal ("failed sanity check."); +} + +void +md_create_long_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol) + char *ptr; + addressT from_Nddr, to_Nddr; + fragS *frag; + symbolS *to_symbol; +{ + as_fatal ("failed sanity check."); +} + +/* +called after relaxing, change the frags so they know how big they are +*/ +void +md_convert_frag (headers, fragP) + object_headers *headers; + fragS *fragP; + +{ + unsigned char *buffer = (unsigned char *) (fragP->fr_fix + fragP->fr_literal); + int donerelax = 0; + int targ_addr = ((fragP->fr_symbol ? S_GET_VALUE (fragP->fr_symbol) : 0) + fragP->fr_offset); + switch (fragP->fr_subtype) + { + case C (COND_JUMP, COND8): + { + /* Get the address of the end of the instruction */ + int next_inst = fragP->fr_fix + fragP->fr_address + 2; + + int disp = targ_addr - next_inst - 2; + disp /= 2; + md_number_to_chars (buffer + 1, disp, 1); + fragP->fr_fix += 2; + fragP->fr_var = 0; + } + break; + + case C (UNCOND_JUMP, UNCOND12): + { + /* Get the address of the end of the instruction */ + int next_inst = fragP->fr_fix + fragP->fr_address + 2; + + int t; + int disp = targ_addr - next_inst - 2; + + disp /= 2; + t = buffer[0] & 0xf0; + md_number_to_chars (buffer, disp, 2); + buffer[0] = (buffer[0] & 0xf) | t; + fragP->fr_fix += 2; + fragP->fr_var = 0; + } + break; + + case C (UNCOND_JUMP, UNCOND32): + case C (UNCOND_JUMP, UNDEF_WORD_DISP): + { + /* A jump wont fit in 12 bits, make code which looks like + bra foo + mov.w @(0, PC), r14 + .long disp + foo: bra @r14 + */ + + int next_inst = + fragP->fr_fix + fragP->fr_address + UNCOND32_LENGTH; + + int disp = targ_addr - next_inst; + int t = buffer[0] & 0x10; + + disp /= 2; + + buffer[0] = 0xa0; /* branch over move and disp */ + buffer[1] = 3; + buffer[2] = 0xd0 | JREG;/* Build mov insn */ + buffer[3] = 0x00; + + buffer[4] = 0; /* space for 32 bit jump disp */ + buffer[5] = 0; + buffer[6] = 0; + buffer[7] = 0; + + buffer[10] = 0x40 | JREG; /* Build jmp @JREG */ + buffer[11] = t ? 0xb : 0x2b; + + buffer[12] = 0x20; /* build nop */ + buffer[13] = 0x0b; + + /* Make reloc for the long disp */ + fix_new (fragP, + fragP->fr_fix + 4, + 4, + fragP->fr_symbol, + 0, + fragP->fr_offset, + 0, + R_SH_IMM32); + fragP->fr_fix += UNCOND32_LENGTH; + fragP->fr_var = 0; + donerelax = 1; + + } + break; + + case C (COND_JUMP, COND12): + { + /* A bcond won't fit, so turn it into a b!cond; bra disp; nop */ + int next_inst = + fragP->fr_fix + fragP->fr_address + 6; + + int disp = targ_addr - next_inst; + disp /= 2; + md_number_to_chars (buffer + 2, disp, 2); + buffer[0] ^= 0x2; /* Toggle T/F bit */ + buffer[1] = 1; /* branch over jump and nop */ + buffer[2] = (buffer[2] & 0xf) | 0xa0; /* Build jump insn */ + buffer[4] = 0x20; /* Build nop */ + buffer[5] = 0x0b; + fragP->fr_fix += 6; + fragP->fr_var = 0; + donerelax = 1; + } + break; + + case C (COND_JUMP, COND32): + case C (COND_JUMP, UNDEF_WORD_DISP): + { + /* A bcond won't fit and it won't go into a 12 bit + displacement either, the code sequence looks like: + b!cond foop + mov.w @(n, PC), r14 + jmp @r14 + nop + .long where + foop: + */ + + int next_inst = + fragP->fr_fix + fragP->fr_address + COND32_LENGTH; + + int disp = targ_addr - next_inst; + disp /= 2; + + buffer[0] ^= 0x2; /* Toggle T/F bit */ +#define JREG 14 + buffer[1] = 5; /* branch over mov, jump, nop and ptr */ + buffer[2] = 0xd0 | JREG;/* Build mov insn */ + buffer[3] = 0x2; + buffer[4] = 0x40 | JREG;/* Build jmp @JREG */ + buffer[5] = 0x0b; + buffer[6] = 0x20; /* build nop */ + buffer[7] = 0x0b; + buffer[8] = 0; /* space for 32 bit jump disp */ + buffer[9] = 0; + buffer[10] = 0; + buffer[11] = 0; + buffer[12] = 0; + buffer[13] = 0; + /* Make reloc for the long disp */ + fix_new (fragP, + fragP->fr_fix + 8, + 4, + fragP->fr_symbol, + 0, + fragP->fr_offset, + 0, + R_SH_IMM32); + fragP->fr_fix += COND32_LENGTH; + fragP->fr_var = 0; + donerelax = 1; + } + break; + + default: + abort (); + } + + if (donerelax && !relax) + { + as_bad ("Offset doesn't fit at 0x%x, trying to get to 0x%x", + fragP->fr_address, + targ_addr); + } + +} + +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])); + +} + +void +md_apply_fix (fixP, val) + fixS *fixP; + long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + int addr = fixP->fx_frag->fr_address + fixP->fx_where; + if (fixP->fx_r_type == 0) + { + fixP->fx_r_type = R_SH_IMM32; + } + + switch (fixP->fx_r_type) + { + + case R_SH_IMM4: + *buf = (*buf & 0xf0) | (val & 0xf); + break; + + case R_SH_IMM4BY2: + *buf = (*buf & 0xf0) | ((val >> 1) & 0xf); + break; + + case R_SH_IMM4BY4: + *buf = (*buf & 0xf0) | ((val >> 2) & 0xf); + break; + + case R_SH_IMM8BY2: + *buf = val >> 1; + break; + + case R_SH_IMM8BY4: + *buf = val >> 2; + break; + + case R_SH_IMM8: + *buf++ = val; + break; + + case R_SH_PCRELIMM8BY4: + addr &= ~1; + + if (val & 0x3) + as_warn ("non aligned displacement at %x\n", addr); + val -= (addr + 4); + val += 3; + val /= 4; + if (val & ~0xff) + as_warn ("pcrel too far at %x\n", addr); + + *buf = val; + break; + + case R_SH_PCRELIMM8BY2: + addr &= ~1; + if (val & 0x1) + as_bad ("odd displacement at %x\n", addr); + val -= (addr + 4); + val++; + val /= 2; + if (val & ~0xff) + as_warn ("pcrel too far at %x\n", addr); + *buf = val; + break; + + case R_SH_IMM32: + *buf++ = val >> 24; + *buf++ = val >> 16; + *buf++ = val >> 8; + *buf++ = val >> 0; + break; + + default: + abort (); + } +} + +void +DEFUN (md_operand, (expressionP), expressionS * expressionP) +{ +} + +int md_long_jump_size; + +/* +called just before address relaxation, return the length +by which a fragment must grow to reach it's destination +*/ +int +md_estimate_size_before_relax (fragP, segment_type) + register fragS *fragP; + register segT segment_type; +{ + switch (fragP->fr_subtype) + { + case C (UNCOND_JUMP, UNDEF_DISP): + /* used to be a branch to somewhere which was unknown */ + if (!fragP->fr_symbol) + { + fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12); + fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length; + } + else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type) + { + fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12); + fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length; + } + else + { + fragP->fr_subtype = C (UNCOND_JUMP, UNDEF_WORD_DISP); + fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length; + return md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length; + } + break; + + default: + abort (); + case C (COND_JUMP, UNDEF_DISP): + /* used to be a branch to somewhere which was unknown */ + if (fragP->fr_symbol + && S_GET_SEGMENT (fragP->fr_symbol) == segment_type) + { + /* Got a symbol and it's defined in this segment, become byte + sized - maybe it will fix up */ + fragP->fr_subtype = C (COND_JUMP, COND8); + fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length; + } + else if (fragP->fr_symbol) + { + /* Its got a segment, but its not ours, so it will always be long */ + fragP->fr_subtype = C (COND_JUMP, UNDEF_WORD_DISP); + fragP->fr_var = md_relax_table[C (COND_JUMP, COND32)].rlx_length; + return md_relax_table[C (COND_JUMP, COND32)].rlx_length; + } + else + { + /* We know the abs value */ + fragP->fr_subtype = C (COND_JUMP, COND8); + fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length; + } + + break; + } + return fragP->fr_var; +} + +/* Put number into target byte order */ + +void +md_number_to_chars (ptr, use, nbytes) + char *ptr; + valueT use; + 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 (); + } +} +long +md_pcrel_from (fixP) + fixS *fixP; + +{ + int gap = fixP->fx_size + fixP->fx_where + + fixP->fx_frag->fr_address; + return gap; +} + +void +tc_coff_symbol_emit_hook () +{ +} + +short +tc_coff_fix2rtype (fix_ptr) + fixS *fix_ptr; +{ + return fix_ptr->fx_r_type; +} + +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_IMM16; + break; + case 1: + intr->r_type = R_IMM8; + break; + default: + abort (); + } + } + 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; + + /* Turn the segment of the symbol into an offset. */ + if (symbol_ptr) + { + symbolS *dot; + + dot = segment_info[S_GET_SEGMENT (symbol_ptr)].dot; + if (dot) + { + intr->r_offset += S_GET_VALUE (symbol_ptr); + intr->r_symndx = dot->sy_number; + } + else + { + intr->r_symndx = symbol_ptr->sy_number; + } + } + else + { + intr->r_symndx = -1; + } +} + +int +tc_coff_sizemachdep (frag) + fragS *frag; +{ + return md_relax_table[frag->fr_subtype].rlx_length; +} + + +/* end of tc-sh.c */ diff --git a/gas/config/tc-tahoe.c b/gas/config/tc-tahoe.c index 6897623..7bd97b5 100644 --- a/gas/config/tc-tahoe.c +++ b/gas/config/tc-tahoe.c @@ -455,11 +455,11 @@ md_parse_option (argP, cntP, vecP) void /* Knows about order of bytes in address. */ md_number_to_chars (con, value, nbytes) char con[]; /* Return 'nbytes' of chars here. */ - long int value; /* The value of the bits. */ + valueT value; /* The value of the bits. */ int nbytes; /* Number of bytes in the output. */ { int n = nbytes; - long int v = value; + valueT v = value; con += nbytes - 1; /* Tahoes is (Bleah!) big endian */ while (nbytes--) @@ -595,11 +595,11 @@ const int md_short_jump_size = 3; void md_create_short_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; { - long offset; + valueT offset; offset = to_addr - (from_addr + 1); *ptr++ = TAHOE_BRW; @@ -612,11 +612,11 @@ const int md_reloc_size = 8; /* Size of relocation record */ 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; { - long offset; + valueT offset; offset = to_addr - (from_addr + 4); *ptr++ = TAHOE_JMP; @@ -2044,10 +2044,10 @@ md_operand (expressionP) } /* md_operand() */ /* Round up a section size to the appropriate boundary. */ -long +valueT md_section_align (segment, size) segT segment; - long size; + valueT size; { return ((size + 7) & ~7); /* Round all sects to multiple of 8 */ } /* md_section_align() */ diff --git a/gas/config/tc-vax.c b/gas/config/tc-vax.c index 3d76647..38896ed 100644 --- a/gas/config/tc-vax.c +++ b/gas/config/tc-vax.c @@ -289,11 +289,11 @@ md_end () void /* Knows about order of bytes in address. */ md_number_to_chars (con, value, nbytes) char con[]; /* Return 'nbytes' of chars here. */ - long value; /* The value of the bits. */ + valueT value; /* The value of the bits. */ int nbytes; /* Number of bytes in the output. */ { int n; - long v; + valueT v; n = nbytes; v = value; @@ -3175,11 +3175,11 @@ const int md_reloc_size = 8; /* Size of relocation record */ void md_create_short_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; { - long offset; + valueT offset; offset = to_addr - (from_addr + 1); *ptr++ = 0x31; @@ -3189,11 +3189,11 @@ 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; { - long offset; + valueT offset; offset = to_addr - S_GET_VALUE (to_symbol); *ptr++ = 0x17; @@ -3258,10 +3258,13 @@ md_parse_option (argP, cntP, vecP) as_warn ("I don't use an interpass file! -V ignored"); break; -#ifdef VMS +#ifdef OBJ_VMS case '+': /* For g++ */ break; + case '1': /* For backward compatibility */ + break; + case 'h': /* No hashing of mixed-case names */ break; @@ -3298,10 +3301,10 @@ md_operand (expressionP) } /* Round up a section size to the appropriate boundary. */ -long +valueT md_section_align (segment, size) segT segment; - long size; + valueT size; { return size; /* Byte alignment is fine */ } diff --git a/gas/config/tc-z8k.c b/gas/config/tc-z8k.c index 44eaeeb..2fcc3f1 100644 --- a/gas/config/tc-z8k.c +++ b/gas/config/tc-z8k.c @@ -27,10 +27,8 @@ #include "../opcodes/z8k-opc.h" #include "as.h" -#include "read.h" #include "bfd.h" #include <ctype.h> -#include "listing.h" const char comment_chars[] = {'!', 0}; @@ -41,7 +39,7 @@ const char line_comment_chars[] = { '#', 0}; extern int machine; extern int coff_flags; int segmented_mode; -int md_reloc_size; +const int md_reloc_size; /* This table describes all the machine specific pseudo-ops the assembler has to support. The fields are: @@ -1170,8 +1168,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; { @@ -1181,7 +1179,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; { @@ -1198,10 +1196,10 @@ md_convert_frag (headers, fragP) abort (); } -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])); @@ -1274,7 +1272,7 @@ md_estimate_size_before_relax (fragP, segment_type) void DEFUN (md_number_to_chars, (ptr, use, nbytes), char *ptr AND - long use AND + valueT use AND int nbytes) { switch (nbytes) |