diff -r a5bc612212ff bfd/ChangeLog.ggx --- a/bfd/ChangeLog.ggx Wed Mar 12 07:43:30 2008 -0700 +++ b/bfd/ChangeLog.ggx Thu Mar 13 14:10:00 2008 -0700 @@ -1,3 +1,11 @@ 2008-02-20 Anthony Green + + * elf32-ggx.c (ggx_elf_reloc, ggx_elf_howto_table, + ggx_elf_info_to_howto, ggx_elf_reloc_name_lookup, + ggx_elf_reloc_type_lookup, ggx_reloc_map): Define. + (bfd_elf32_bfd_reloc_type_lookup, bfd_elf32_bfd_reloc_name_lookup, + elf_info_to_howto): Redefine. + 2008-02-20 Anthony Green * targets.c: Add ggx support. diff -r a5bc612212ff bfd/elf32-ggx.c --- a/bfd/elf32-ggx.c Wed Mar 12 07:43:30 2008 -0700 +++ b/bfd/elf32-ggx.c Thu Mar 13 14:10:00 2008 -0700 @@ -22,14 +22,167 @@ #include "bfd.h" #include "libbfd.h" #include "elf-bfd.h" +#include "elf/ggx.h" + +/* This function is used for normal relocs. This is like the COFF + function, and is almost certainly incorrect for other ELF targets. */ + +static bfd_reloc_status_type +ggx_elf_reloc (bfd *abfd, + arelent *reloc_entry, + asymbol *symbol_in, + void * data, + asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + unsigned long insn; + bfd_vma sym_value; + enum elf_ggx_reloc_type r_type; + bfd_vma addr = reloc_entry->address; + bfd_byte *hit_data = addr + (bfd_byte *) data; + + r_type = (enum elf_ggx_reloc_type) reloc_entry->howto->type; + + if (output_bfd != NULL) + { + /* Partial linking--do nothing. */ + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (symbol_in != NULL + && bfd_is_und_section (symbol_in->section)) + return bfd_reloc_undefined; + + if (bfd_is_com_section (symbol_in->section)) + sym_value = 0; + else + sym_value = (symbol_in->value + + symbol_in->section->output_section->vma + + symbol_in->section->output_offset); + + switch (r_type) + { + case R_GGX_DIR32: + insn = bfd_get_32 (abfd, hit_data); + insn += sym_value + reloc_entry->addend; + bfd_put_32 (abfd, (bfd_vma) insn, hit_data); + break; + + default: + abort (); + break; + } + + return bfd_reloc_ok; +} + +static reloc_howto_type ggx_elf_howto_table[] = +{ + /* No relocation. */ + HOWTO (R_GGX_NONE, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ggx_elf_reloc, /* special_function */ + "R_GGX_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* 32 bit absolute relocation. Setting partial_inplace to TRUE and + src_mask to a non-zero value is similar to the COFF toolchain. */ + HOWTO (R_GGX_DIR32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + ggx_elf_reloc, /* special_function */ + "R_GGX_DIR32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ +}; + +/* This structure is used to map BFD reloc codes to ggx elf relocs. */ + +struct elf_reloc_map +{ + bfd_reloc_code_real_type bfd_reloc_val; + unsigned char elf_reloc_val; +}; + +/* An array mapping BFD reloc codes to ggx elf relocs. */ + +static const struct elf_reloc_map ggx_reloc_map[] = +{ + { BFD_RELOC_NONE, R_GGX_NONE }, + { BFD_RELOC_32, R_GGX_DIR32 } +}; + +/* Given a BFD reloc code, return the howto structure for the + corresponding ggx elf reloc. */ + +static reloc_howto_type * +ggx_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + unsigned int i; + + for (i = 0; i < sizeof (ggx_reloc_map) / sizeof (struct elf_reloc_map); i++) + if (ggx_reloc_map[i].bfd_reloc_val == code) + return & ggx_elf_howto_table[(int) ggx_reloc_map[i].elf_reloc_val]; + + return NULL; +} + +static reloc_howto_type * +ggx_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < sizeof (ggx_elf_howto_table) / sizeof (ggx_elf_howto_table[0]); + i++) + if (ggx_elf_howto_table[i].name != NULL + && strcasecmp (ggx_elf_howto_table[i].name, r_name) == 0) + return &ggx_elf_howto_table[i]; + + return NULL; +} + +/* Given an ELF reloc, fill in the howto field of a relent. */ + +static void +ggx_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, + arelent *cache_ptr, + Elf_Internal_Rela *dst) +{ + unsigned int r; + + r = ELF32_R_TYPE (dst->r_info); + + BFD_ASSERT (r < (unsigned int) R_GGX_max); + + cache_ptr->howto = &ggx_elf_howto_table[r]; +} #define TARGET_BIG_SYM bfd_elf32_ggx_vec #define TARGET_BIG_NAME "elf32-ggx" #define ELF_ARCH bfd_arch_ggx #define ELF_MACHINE_CODE EM_GGX #define ELF_MAXPAGESIZE 1 -#define bfd_elf32_bfd_reloc_type_lookup bfd_default_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup -#define elf_info_to_howto _bfd_elf_no_info_to_howto +#define bfd_elf32_bfd_reloc_type_lookup ggx_elf_reloc_type_lookup +#define bfd_elf32_bfd_reloc_name_lookup ggx_elf_reloc_name_lookup +#define elf_info_to_howto ggx_elf_info_to_howto #include "elf32-target.h" diff -r a5bc612212ff gas/ChangeLog.ggx --- a/gas/ChangeLog.ggx Wed Mar 12 07:43:30 2008 -0700 +++ b/gas/ChangeLog.ggx Thu Mar 13 14:10:00 2008 -0700 @@ -1,3 +1,16 @@ 2008-02-20 Anthony Green + + * config/tc-ggx.c (md_assemble): Encode different forms of + instructions. + (parse_exp_save_ilp): Define. + (md_assemble): Process GGX_F1_A4 instructions. + (md_apply_fix): Apply BFD_RELOC_32 relocations. + +2008-02-20 Anthony Green + + * config/tc-gcore.c (md_assemble): Encode different forms of + instructions. + 2008-02-20 Anthony Green * config/tc-ggx.c (md_begin): Populate the insn hash table with diff -r a5bc612212ff gas/config/tc-ggx.c --- a/gas/config/tc-ggx.c Wed Mar 12 07:43:30 2008 -0700 +++ b/gas/config/tc-ggx.c Thu Mar 13 14:10:00 2008 -0700 @@ -69,6 +69,20 @@ md_begin (void) bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0); } +/* Parse an expression and then restore the input line pointer. */ + +static char * +parse_exp_save_ilp (char *s, expressionS *op) +{ + char *save = input_line_pointer; + + input_line_pointer = s; + expression (op); + s = input_line_pointer; + input_line_pointer = save; + return s; +} + /* 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. */ @@ -80,9 +94,10 @@ md_assemble (char *str) char *op_end; ggx_opc_info_t *opcode; - char *output; - int idx = 0; + char *p; char pend; + + unsigned short iword = 0; int nlen = 0; @@ -112,9 +127,89 @@ md_assemble (char *str) return; } - output = frag_more (1); - output[idx++] = opcode->opcode; - + p = frag_more (2); + + switch (opcode->itype) + { + case GGX_F1_NARG: + iword = opcode->opcode << 9; + while (ISSPACE (*op_end)) + op_end++; + if (*op_end != 0) + as_warn ("extra stuff on line ignored"); + break; + case GGX_F1_A: + iword = opcode->opcode << 9; + break; + case GGX_F1_AB: + iword = opcode->opcode << 9; + break; + case GGX_F1_ABC: + iword = opcode->opcode << 9; + break; + case GGX_F1_A4: + iword = opcode->opcode << 9; + while (ISSPACE (*op_end)) + op_end++; + { + expressionS arg; + char *where; + int regnum; + + if ((*op_end != '$') || (*(op_end+1) != 'r')) + { + as_bad ("expecting register"); + ignore_rest_of_line (); + return; + } + regnum = op_end[2] - '0'; + if ((regnum < 1) || (regnum > 7)) + { + as_bad ("illegal register number"); + ignore_rest_of_line (); + return; + } + + op_end += 3; + while (ISSPACE (*op_end)) + op_end++; + + iword += (regnum << 6); + + if (*op_end != ',') + { + as_bad ("expecting comma delimited operands"); + ignore_rest_of_line (); + return; + } + op_end++; + + op_end = parse_exp_save_ilp (op_end, &arg); + where = frag_more (4); + fix_new_exp (frag_now, + (where - frag_now->fr_literal), + 4, + &arg, + 0, + BFD_RELOC_32); + } + break; + case GGX_F2_NARG: + iword = opcode->opcode << 12; + while (ISSPACE (*op_end)) + op_end++; + if (*op_end != 0) + as_warn ("extra stuff on line ignored"); + break; + case GGX_F2_12V: + iword = opcode->opcode << 12; + break; + default: + abort(); + } + + md_number_to_chars (p, iword, 2); + while (ISSPACE (*op_end)) op_end++; @@ -194,7 +289,31 @@ void void md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED, valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED) { - /* Empty for now. */ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + long val = *valP; + long max, min; + int shift; + + max = min = 0; + shift = 0; + switch (fixP->fx_r_type) + { + case BFD_RELOC_32: + *buf++ = val >> 24; + *buf++ = val >> 16; + *buf++ = val >> 8; + *buf++ = val >> 0; + break; + + default: + abort (); + } + + if (max != 0 && (val < min || val > max)) + as_bad_where (fixP->fx_file, fixP->fx_line, _("offset out of range")); + + if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) + fixP->fx_done = 1; } /* Put number into target byte order (big endian). */ @@ -235,3 +354,22 @@ tc_gen_reloc (asection *section ATTRIBUT return rel; } + +/* Decide from what point a pc-relative relocation is relative to, + relative to the pc-relative fixup. Er, relatively speaking. */ +long +md_pcrel_from (fixS *fixP) +{ + valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; + + fprintf (stderr, "md_pcrel_from 0x%d\n", fixP->fx_r_type); + + switch (fixP->fx_r_type) + { + case BFD_RELOC_32: + return addr + 4; + default: + abort(); + return addr; + } +} diff -r a5bc612212ff gas/config/tc-ggx.h --- a/gas/config/tc-ggx.h Wed Mar 12 07:43:30 2008 -0700 +++ b/gas/config/tc-ggx.h Thu Mar 13 14:10:00 2008 -0700 @@ -36,9 +36,12 @@ #define md_estimate_size_before_relax(A, B) (as_fatal (_("estimate size\n")),0) #define md_convert_frag(B, S, F) (as_fatal (_("convert_frag\n")), 0) -/* PC relative operands are relative to the start of the opcode, and - the operand is always one byte into the opcode. */ -#define md_pcrel_from(FIX) \ - ((FIX)->fx_where + (FIX)->fx_frag->fr_address - 1) +/* If you define this macro, it should return the offset between the + address of a PC relative fixup and the position from which the PC + relative adjustment should be made. On many processors, the base + of a PC relative instruction is the next instruction, so this + macro would return the length of an instruction. */ +#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from (FIX) +extern long md_pcrel_from (struct fix *); #define md_section_align(SEGMENT, SIZE) (SIZE) diff -r a5bc612212ff include/elf/ChangeLog.ggx --- a/include/elf/ChangeLog.ggx Wed Mar 12 07:43:30 2008 -0700 +++ b/include/elf/ChangeLog.ggx Thu Mar 13 14:10:00 2008 -0700 @@ -1,3 +1,7 @@ 2008-02-20 Anthony Green + + * ggx.h (R_GGX_DATA_DIR32): Define. + 2008-02-20 Anthony Green * common.h (EM_GGX): Define. diff -r a5bc612212ff include/elf/ggx.h --- a/include/elf/ggx.h Wed Mar 12 07:43:30 2008 -0700 +++ b/include/elf/ggx.h Thu Mar 13 14:10:00 2008 -0700 @@ -25,6 +25,7 @@ /* Relocation types. */ START_RELOC_NUMBERS (elf_ggx_reloc_type) RELOC_NUMBER (R_GGX_NONE, 0) + RELOC_NUMBER (R_GGX_DIR32, 1) END_RELOC_NUMBERS (R_GGX_max) #endif diff -r a5bc612212ff include/opcode/ChangeLog.ggx --- a/include/opcode/ChangeLog.ggx Wed Mar 12 07:43:30 2008 -0700 +++ b/include/opcode/ChangeLog.ggx Thu Mar 13 14:10:00 2008 -0700 @@ -1,3 +1,7 @@ 2008-02-20 Anthony Green + + * ggx.h (GGX_F1_A4): Define. + 2008-02-20 Anthony Green * ggx.h (ggx_opc_info_t): Add itype element. diff -r a5bc612212ff include/opcode/ggx.h --- a/include/opcode/ggx.h Wed Mar 12 07:43:30 2008 -0700 +++ b/include/opcode/ggx.h Thu Mar 13 14:10:00 2008 -0700 @@ -20,10 +20,11 @@ 02110-1301, USA. */ /* Form 1 instructions come in different flavors: - Some have no arguments (GGX_F1_NARG) - Some only use the A operand (GGX_F1_A) - Some use A and B registers (GGX_F1_AB) - Some use A, B and C registers (GGX_F1_ABC) + Some have no arguments (GGX_F1_NARG) + Some only use the A operand (GGX_F1_A) + Some use A and B registers (GGX_F1_AB) + Some use A, B and C registers (GGX_F1_ABC) + Some use A and consume a 4 byte immediate value (GGX_F1_A4) Form 2 instructions also come in different flavors: @@ -35,6 +36,7 @@ 02110-1301, USA. */ #define GGX_F1_A 0x101 #define GGX_F1_AB 0x102 #define GGX_F1_ABC 0x103 +#define GGX_F1_A4 0x104 #define GGX_F2_NARG 0x200 #define GGX_F2_12V 0x201 diff -r a5bc612212ff opcodes/ChangeLog.ggx --- a/opcodes/ChangeLog.ggx Wed Mar 12 07:43:30 2008 -0700 +++ b/opcodes/ChangeLog.ggx Thu Mar 13 14:10:00 2008 -0700 @@ -1,3 +1,10 @@ 2008-02-20 Anthony Green + + * ggx-dis.c (OP_A, OP_B, OP_C): Define. Disassemble GGX_F1_A4 + instructions. + (print_insn_ggx): Decode different forms of instructions. + * ggx-opc.c (ggx_form1_opc_info): Define ldi.l. + 2008-02-20 Anthony Green * ggx-opc.c, ggx-dis.c: Created. diff -r a5bc612212ff opcodes/ggx-dis.c --- a/opcodes/ggx-dis.c Wed Mar 12 07:43:30 2008 -0700 +++ b/opcodes/ggx-dis.c Thu Mar 13 14:10:00 2008 -0700 @@ -30,17 +30,25 @@ static fprintf_ftype fpr; static fprintf_ftype fpr; static void *stream; +/* Macros to extract operands from the instruction word. */ +#define OP_A(i) ((i >> 6) & 0x7) +#define OP_B(i) ((i >> 3) & 0x7) +#define OP_C(i) (i & 0x7) + int print_insn_ggx (bfd_vma addr, struct disassemble_info *info) { + int length = 2; int status; - stream = info->stream; + stream = info->stream; const ggx_opc_info_t *opcode; + bfd_byte buffer[4]; unsigned short iword; fpr = info->fprintf_func; - if ((status = info->read_memory_func (addr, (unsigned char*) &iword, 2, info))) + if ((status = info->read_memory_func (addr, buffer, 2, info))) goto fail; + iword = bfd_getb16 (buffer); /* Form 1 instructions have the high bit set to 0. */ if ((iword & (1<<15)) == 0) @@ -51,6 +59,16 @@ print_insn_ggx (bfd_vma addr, struct dis { case GGX_F1_NARG: fpr (stream, "%s", opcode->name); + break; + case GGX_F1_A4: + { + unsigned imm; + if ((status = info->read_memory_func (addr+2, buffer, 4, info))) + goto fail; + imm = bfd_getb32 (buffer); + fpr (stream, "%s\t$r%d, 0x%x", opcode->name, OP_A(iword), imm); + length = 6; + } break; default: abort(); @@ -70,7 +88,7 @@ print_insn_ggx (bfd_vma addr, struct dis } } - return 2; + return length; fail: info->memory_error_func (status, addr, info); diff -r a5bc612212ff opcodes/ggx-opc.c --- a/opcodes/ggx-opc.c Wed Mar 12 07:43:30 2008 -0700 +++ b/opcodes/ggx-opc.c Thu Mar 13 14:10:00 2008 -0700 @@ -47,7 +47,7 @@ const ggx_opc_info_t ggx_form1_opc_info[64] = { - { 0x00, GGX_F1_NARG, "bad" }, + { 0x00, GGX_F1_A4, "ldi.l" }, { 0x01, GGX_F1_NARG, "bad" }, { 0x02, GGX_F1_NARG, "bad" }, { 0x03, GGX_F1_NARG, "bad" },