--- binutils-2.15/bfd/Makefile.am 2004-05-17 21:35:56.000000000 +0200 +++ binutils-2.15-nios2/bfd/Makefile.am 2005-05-17 12:20:13.000000000 +0200 @@ -82,6 +82,7 @@ ALL_MACHINES = \ cpu-mips.lo \ cpu-mmix.lo \ cpu-msp430.lo \ + cpu-nios2.lo \ cpu-or32.lo \ cpu-ns32k.lo \ cpu-openrisc.lo \ @@ -139,6 +140,7 @@ ALL_MACHINES_CFILES = \ cpu-msp430.c \ cpu-or32.c \ cpu-ns32k.c \ + cpu-nios2.c \ cpu-openrisc.c \ cpu-pdp11.c \ cpu-pj.c \ @@ -241,6 +243,7 @@ BFD32_BACKENDS = \ elfxx-mips.lo \ elf32-mips.lo \ elf32-msp430.lo \ + elf32-nios2.lo \ elf32-openrisc.lo \ elf32-or32.lo \ elf32-pj.lo \ @@ -405,6 +408,7 @@ BFD32_BACKENDS_CFILES = \ elfxx-mips.c \ elf32-mips.c \ elf32-msp430.c \ + elf32-nios2.c \ elf32-openrisc.c \ elf32-or32.c \ elf32-pj.c \ @@ -943,6 +947,7 @@ cpu-mcore.lo: cpu-mcore.c $(INCDIR)/file cpu-mips.lo: cpu-mips.c $(INCDIR)/filenames.h cpu-mmix.lo: cpu-mmix.c $(INCDIR)/filenames.h cpu-msp430.lo: cpu-msp430.c $(INCDIR)/filenames.h +cpu-nios2.lo: cpu-nios2.c $(INCDIR)/filenames.h cpu-or32.lo: cpu-or32.c $(INCDIR)/filenames.h cpu-ns32k.lo: cpu-ns32k.c $(INCDIR)/filenames.h ns32k.h cpu-openrisc.lo: cpu-openrisc.c $(INCDIR)/filenames.h @@ -1250,6 +1255,10 @@ elf32-msp430.lo: elf32-msp430.c $(INCDIR $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ $(INCDIR)/elf/msp430.h $(INCDIR)/elf/reloc-macros.h \ elf32-target.h +elf32-nios2.lo: elf32-nios2.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \ + genlink.h elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/elf/nios2.h \ + $(INCDIR)/elf/reloc-macros.h elf32-target.h elf32-openrisc.lo: elf32-openrisc.c $(INCDIR)/filenames.h \ elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(INCDIR)/elf/openrisc.h \ --- binutils-2.15/bfd/Makefile.in 2004-05-17 21:35:56.000000000 +0200 +++ binutils-2.15-nios2/bfd/Makefile.in 2005-05-17 12:20:13.000000000 +0200 @@ -210,6 +210,7 @@ ALL_MACHINES = \ cpu-mips.lo \ cpu-mmix.lo \ cpu-msp430.lo \ + cpu-nios2.lo \ cpu-or32.lo \ cpu-ns32k.lo \ cpu-openrisc.lo \ @@ -267,6 +268,7 @@ ALL_MACHINES_CFILES = \ cpu-mmix.c \ cpu-msp430.c \ cpu-or32.c \ + cpu-nios2.c \ cpu-ns32k.c \ cpu-openrisc.c \ cpu-pdp11.c \ @@ -371,6 +373,7 @@ BFD32_BACKENDS = \ elfxx-mips.lo \ elf32-mips.lo \ elf32-msp430.lo \ + elf32-nios2.lo \ elf32-openrisc.lo \ elf32-or32.lo \ elf32-pj.lo \ @@ -536,6 +539,7 @@ BFD32_BACKENDS_CFILES = \ elfxx-mips.c \ elf32-mips.c \ elf32-msp430.c \ + elf32-nios2.c \ elf32-openrisc.c \ elf32-or32.c \ elf32-pj.c \ @@ -1482,6 +1486,7 @@ cpu-mmix.lo: cpu-mmix.c $(INCDIR)/filena cpu-msp430.lo: cpu-msp430.c $(INCDIR)/filenames.h cpu-or32.lo: cpu-or32.c $(INCDIR)/filenames.h cpu-ns32k.lo: cpu-ns32k.c $(INCDIR)/filenames.h ns32k.h +cpu-nios2.lo: cpu-nios2.c $(INCDIR)/filenames.h cpu-openrisc.lo: cpu-openrisc.c $(INCDIR)/filenames.h cpu-pdp11.lo: cpu-pdp11.c $(INCDIR)/filenames.h cpu-pj.lo: cpu-pj.c $(INCDIR)/filenames.h @@ -1787,6 +1792,10 @@ elf32-msp430.lo: elf32-msp430.c $(INCDIR $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ $(INCDIR)/elf/msp430.h $(INCDIR)/elf/reloc-macros.h \ elf32-target.h +elf32-nios2.lo: elf32-nios2.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \ + genlink.h elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/elf/nios2.h \ + $(INCDIR)/elf/reloc-macros.h elf32-target.h elf32-openrisc.lo: elf32-openrisc.c $(INCDIR)/filenames.h \ elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(INCDIR)/elf/openrisc.h \ --- binutils-2.15/bfd/archures.c 2003-12-03 18:38:48.000000000 +0100 +++ binutils-2.15-nios2/bfd/archures.c 2005-05-17 12:20:13.000000000 +0200 @@ -330,6 +330,8 @@ DESCRIPTION .#define bfd_mach_msp44 44 . bfd_arch_xtensa, {* Tensilica's Xtensa cores. *} .#define bfd_mach_xtensa 1 +. bfd_arch_nios2, +.#define bfd_mach_nios2 1 . bfd_arch_last . }; */ @@ -422,6 +424,7 @@ extern const bfd_arch_info_type bfd_w65_ extern const bfd_arch_info_type bfd_xstormy16_arch; extern const bfd_arch_info_type bfd_xtensa_arch; extern const bfd_arch_info_type bfd_z8k_arch; +extern const bfd_arch_info_type bfd_nios2_arch; static const bfd_arch_info_type * const bfd_archures_list[] = { @@ -460,6 +463,7 @@ static const bfd_arch_info_type * const &bfd_mn10200_arch, &bfd_mn10300_arch, &bfd_msp430_arch, + &bfd_nios2_arch, &bfd_ns32k_arch, &bfd_openrisc_arch, &bfd_or32_arch, --- binutils-2.15/bfd/bfd-in2.h 2004-05-17 21:35:56.000000000 +0200 +++ binutils-2.15-nios2/bfd/bfd-in2.h 2005-05-17 12:20:13.000000000 +0200 @@ -830,37 +830,48 @@ extern void bfd_elf64_ia64_after_parse (int); /* Extracted from init.c. */ -void bfd_init (void); +void +bfd_init PARAMS ((void)); /* Extracted from opncls.c. */ -bfd *bfd_openr (const char *filename, const char *target); +bfd * +bfd_openr PARAMS ((const char *filename, const char *target)); -bfd *bfd_fdopenr (const char *filename, const char *target, int fd); +bfd * +bfd_fdopenr PARAMS ((const char *filename, const char *target, int fd)); -bfd *bfd_openstreamr (const char *, const char *, void *); +bfd * +bfd_openstreamr PARAMS ((const char *, const char *, void *)); -bfd *bfd_openw (const char *filename, const char *target); +bfd * +bfd_openw PARAMS ((const char *filename, const char *target)); -bfd_boolean bfd_close (bfd *abfd); +bfd_boolean +bfd_close PARAMS ((bfd *abfd)); -bfd_boolean bfd_close_all_done (bfd *); +bfd_boolean +bfd_close_all_done PARAMS ((bfd *)); -bfd *bfd_create (const char *filename, bfd *templ); +bfd * +bfd_create PARAMS ((const char *filename, bfd *templ)); -bfd_boolean bfd_make_writable (bfd *abfd); +bfd_boolean +bfd_make_writable PARAMS ((bfd *abfd)); -bfd_boolean bfd_make_readable (bfd *abfd); +bfd_boolean +bfd_make_readable PARAMS ((bfd *abfd)); -unsigned long bfd_calc_gnu_debuglink_crc32 - (unsigned long crc, const unsigned char *buf, bfd_size_type len); +unsigned long +bfd_calc_gnu_debuglink_crc32 PARAMS ((unsigned long crc, const unsigned char *buf, bfd_size_type len)); -char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); +char * +bfd_follow_gnu_debuglink PARAMS ((bfd *abfd, const char *dir)); -struct bfd_section *bfd_create_gnu_debuglink_section - (bfd *abfd, const char *filename); +struct bfd_section * +bfd_create_gnu_debuglink_section PARAMS ((bfd *abfd, const char *filename)); -bfd_boolean bfd_fill_in_gnu_debuglink_section - (bfd *abfd, struct bfd_section *sect, const char *filename); +bfd_boolean +bfd_fill_in_gnu_debuglink_section PARAMS ((bfd *abfd, struct bfd_section *sect, const char *filename)); /* Extracted from libbfd.c. */ @@ -976,9 +987,11 @@ bfd_boolean bfd_fill_in_gnu_debuglink_se /* Extracted from bfdio.c. */ -long bfd_get_mtime (bfd *abfd); +long +bfd_get_mtime PARAMS ((bfd *abfd)); -long bfd_get_size (bfd *abfd); +long +bfd_get_size PARAMS ((bfd *abfd)); /* Extracted from bfdwin.c. */ /* Extracted from section.c. */ @@ -1421,48 +1434,54 @@ extern const struct bfd_symbol * const b } \ while (0) -void bfd_section_list_clear (bfd *); +void +bfd_section_list_clear PARAMS ((bfd *)); -asection *bfd_get_section_by_name (bfd *abfd, const char *name); +asection * +bfd_get_section_by_name PARAMS ((bfd *abfd, const char *name)); -char *bfd_get_unique_section_name - (bfd *abfd, const char *templat, int *count); +char * +bfd_get_unique_section_name PARAMS ((bfd *abfd, const char *templat, int *count)); -asection *bfd_make_section_old_way (bfd *abfd, const char *name); +asection * +bfd_make_section_old_way PARAMS ((bfd *abfd, const char *name)); -asection *bfd_make_section_anyway (bfd *abfd, const char *name); +asection * +bfd_make_section_anyway PARAMS ((bfd *abfd, const char *name)); -asection *bfd_make_section (bfd *, const char *name); +asection * +bfd_make_section PARAMS ((bfd *, const char *name)); -bfd_boolean bfd_set_section_flags - (bfd *abfd, asection *sec, flagword flags); +bfd_boolean +bfd_set_section_flags PARAMS ((bfd *abfd, asection *sec, flagword flags)); -void bfd_map_over_sections - (bfd *abfd, +void +bfd_map_over_sections PARAMS ((bfd *abfd, void (*func) (bfd *abfd, asection *sect, void *obj), - void *obj); + void *obj)); -bfd_boolean bfd_set_section_size - (bfd *abfd, asection *sec, bfd_size_type val); +bfd_boolean +bfd_set_section_size PARAMS ((bfd *abfd, asection *sec, bfd_size_type val)); -bfd_boolean bfd_set_section_contents - (bfd *abfd, asection *section, const void *data, - file_ptr offset, bfd_size_type count); +bfd_boolean +bfd_set_section_contents PARAMS ((bfd *abfd, asection *section, const void *data, + file_ptr offset, bfd_size_type count)); -bfd_boolean bfd_get_section_contents - (bfd *abfd, asection *section, void *location, file_ptr offset, - bfd_size_type count); +bfd_boolean +bfd_get_section_contents PARAMS ((bfd *abfd, asection *section, void *location, file_ptr offset, + bfd_size_type count)); -bfd_boolean bfd_copy_private_section_data - (bfd *ibfd, asection *isec, bfd *obfd, asection *osec); +bfd_boolean +bfd_copy_private_section_data PARAMS ((bfd *ibfd, asection *isec, bfd *obfd, asection *osec)); #define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ BFD_SEND (obfd, _bfd_copy_private_section_data, \ (ibfd, isection, obfd, osection)) -void _bfd_strip_section_from_output - (struct bfd_link_info *info, asection *section); +void +_bfd_strip_section_from_output PARAMS ((struct bfd_link_info *info, asection *section)); -bfd_boolean bfd_generic_discard_group (bfd *abfd, asection *group); +bfd_boolean +bfd_generic_discard_group PARAMS ((bfd *abfd, asection *group)); /* Extracted from archures.c. */ enum bfd_architecture @@ -1728,6 +1747,8 @@ enum bfd_architecture #define bfd_mach_msp44 44 bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ #define bfd_mach_xtensa 1 + bfd_arch_nios2, +#define bfd_mach_nios2 1 bfd_arch_last }; @@ -1754,37 +1775,47 @@ typedef struct bfd_arch_info } bfd_arch_info_type; -const char *bfd_printable_name (bfd *abfd); +const char * +bfd_printable_name PARAMS ((bfd *abfd)); -const bfd_arch_info_type *bfd_scan_arch (const char *string); +const bfd_arch_info_type * +bfd_scan_arch PARAMS ((const char *string)); -const char **bfd_arch_list (void); +const char ** +bfd_arch_list PARAMS ((void)); -const bfd_arch_info_type *bfd_arch_get_compatible - (const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns); +const bfd_arch_info_type * +bfd_arch_get_compatible PARAMS ((const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns)); -void bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg); +void +bfd_set_arch_info PARAMS ((bfd *abfd, const bfd_arch_info_type *arg)); -enum bfd_architecture bfd_get_arch (bfd *abfd); +enum bfd_architecture +bfd_get_arch PARAMS ((bfd *abfd)); -unsigned long bfd_get_mach (bfd *abfd); +unsigned long +bfd_get_mach PARAMS ((bfd *abfd)); -unsigned int bfd_arch_bits_per_byte (bfd *abfd); +unsigned int +bfd_arch_bits_per_byte PARAMS ((bfd *abfd)); -unsigned int bfd_arch_bits_per_address (bfd *abfd); +unsigned int +bfd_arch_bits_per_address PARAMS ((bfd *abfd)); -const bfd_arch_info_type *bfd_get_arch_info (bfd *abfd); +const bfd_arch_info_type * +bfd_get_arch_info PARAMS ((bfd *abfd)); -const bfd_arch_info_type *bfd_lookup_arch - (enum bfd_architecture arch, unsigned long machine); +const bfd_arch_info_type * +bfd_lookup_arch PARAMS ((enum bfd_architecture arch, unsigned long machine)); -const char *bfd_printable_arch_mach - (enum bfd_architecture arch, unsigned long machine); +const char * +bfd_printable_arch_mach PARAMS ((enum bfd_architecture arch, unsigned long machine)); -unsigned int bfd_octets_per_byte (bfd *abfd); +unsigned int +bfd_octets_per_byte PARAMS ((bfd *abfd)); -unsigned int bfd_arch_mach_octets_per_byte - (enum bfd_architecture arch, unsigned long machine); +unsigned int +bfd_arch_mach_octets_per_byte PARAMS ((enum bfd_architecture arch, unsigned long machine)); /* Extracted from reloc.c. */ typedef enum bfd_reloc_status @@ -1967,7 +1998,8 @@ struct reloc_howto_struct } \ } -unsigned int bfd_get_reloc_size (reloc_howto_type *); +unsigned int +bfd_get_reloc_size PARAMS ((reloc_howto_type *)); typedef struct relent_chain { @@ -1976,27 +2008,27 @@ typedef struct relent_chain } arelent_chain; -bfd_reloc_status_type bfd_check_overflow - (enum complain_overflow how, +bfd_reloc_status_type +bfd_check_overflow PARAMS ((enum complain_overflow how, unsigned int bitsize, unsigned int rightshift, unsigned int addrsize, - bfd_vma relocation); + bfd_vma relocation)); -bfd_reloc_status_type bfd_perform_relocation - (bfd *abfd, +bfd_reloc_status_type +bfd_perform_relocation PARAMS ((bfd *abfd, arelent *reloc_entry, void *data, asection *input_section, bfd *output_bfd, - char **error_message); + char **error_message)); -bfd_reloc_status_type bfd_install_relocation - (bfd *abfd, +bfd_reloc_status_type +bfd_install_relocation PARAMS ((bfd *abfd, arelent *reloc_entry, void *data, bfd_vma data_start, asection *input_section, - char **error_message); + char **error_message)); enum bfd_reloc_code_real { _dummy_first_bfd_reloc_code_real, @@ -3439,6 +3471,23 @@ This is the 5 bits of a value. */ BFD_RELOC_MSP430_16_PCREL_BYTE, BFD_RELOC_MSP430_16_BYTE, +/* Relocations used by the Altera New Jersey core */ + BFD_RELOC_NIOS2_S16, + BFD_RELOC_NIOS2_U16, + BFD_RELOC_NIOS2_CALL26, + BFD_RELOC_NIOS2_IMM5, + BFD_RELOC_NIOS2_CACHE_OPX, + BFD_RELOC_NIOS2_IMM6, + BFD_RELOC_NIOS2_IMM8, + BFD_RELOC_NIOS2_HI16, + BFD_RELOC_NIOS2_LO16, + BFD_RELOC_NIOS2_HIADJ16, + BFD_RELOC_NIOS2_GPREL, + BFD_RELOC_NIOS2_UJMP, + BFD_RELOC_NIOS2_CJMP, + BFD_RELOC_NIOS2_CALLR, + BFD_RELOC_NIOS2_ALIGN, + /* IQ2000 Relocations. */ BFD_RELOC_IQ2000_OFFSET_16, BFD_RELOC_IQ2000_OFFSET_21, @@ -3477,10 +3526,11 @@ BFD_RELOC_XTENSA_ASM_EXPAND. */ BFD_RELOC_XTENSA_ASM_SIMPLIFY, BFD_RELOC_UNUSED }; typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; -reloc_howto_type *bfd_reloc_type_lookup - (bfd *abfd, bfd_reloc_code_real_type code); +reloc_howto_type * +bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); -const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); +const char * +bfd_get_reloc_code_name PARAMS ((bfd_reloc_code_real_type code)); /* Extracted from syms.c. */ @@ -3611,9 +3661,11 @@ asymbol; #define bfd_get_symtab_upper_bound(abfd) \ BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) -bfd_boolean bfd_is_local_label (bfd *abfd, asymbol *sym); +bfd_boolean +bfd_is_local_label PARAMS ((bfd *abfd, asymbol *sym)); -bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); +bfd_boolean +bfd_is_local_label_name PARAMS ((bfd *abfd, const char *name)); #define bfd_is_local_label_name(abfd, name) \ BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) @@ -3621,27 +3673,32 @@ bfd_boolean bfd_is_local_label_name (bfd #define bfd_canonicalize_symtab(abfd, location) \ BFD_SEND (abfd, _bfd_canonicalize_symtab, (abfd, location)) -bfd_boolean bfd_set_symtab - (bfd *abfd, asymbol **location, unsigned int count); +bfd_boolean +bfd_set_symtab PARAMS ((bfd *abfd, asymbol **location, unsigned int count)); -void bfd_print_symbol_vandf (bfd *abfd, void *file, asymbol *symbol); +void +bfd_print_symbol_vandf PARAMS ((bfd *abfd, void *file, asymbol *symbol)); #define bfd_make_empty_symbol(abfd) \ BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) -asymbol *_bfd_generic_make_empty_symbol (bfd *); +asymbol * +_bfd_generic_make_empty_symbol PARAMS ((bfd *)); #define bfd_make_debug_symbol(abfd,ptr,size) \ BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) -int bfd_decode_symclass (asymbol *symbol); +int +bfd_decode_symclass PARAMS ((asymbol *symbol)); -bfd_boolean bfd_is_undefined_symclass (int symclass); +bfd_boolean +bfd_is_undefined_symclass PARAMS ((int symclass)); -void bfd_symbol_info (asymbol *symbol, symbol_info *ret); +void +bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret)); -bfd_boolean bfd_copy_private_symbol_data - (bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); +bfd_boolean +bfd_copy_private_symbol_data PARAMS ((bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym)); #define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ @@ -3840,57 +3897,76 @@ typedef enum bfd_error } bfd_error_type; -bfd_error_type bfd_get_error (void); +bfd_error_type +bfd_get_error PARAMS ((void)); -void bfd_set_error (bfd_error_type error_tag); +void +bfd_set_error PARAMS ((bfd_error_type error_tag)); -const char *bfd_errmsg (bfd_error_type error_tag); +const char * +bfd_errmsg PARAMS ((bfd_error_type error_tag)); -void bfd_perror (const char *message); +void +bfd_perror PARAMS ((const char *message)); typedef void (*bfd_error_handler_type) (const char *, ...); -bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); +bfd_error_handler_type +bfd_set_error_handler PARAMS ((bfd_error_handler_type)); -void bfd_set_error_program_name (const char *); +void +bfd_set_error_program_name PARAMS ((const char *)); -bfd_error_handler_type bfd_get_error_handler (void); +bfd_error_handler_type +bfd_get_error_handler PARAMS ((void)); -const char *bfd_archive_filename (bfd *); +const char * +bfd_archive_filename PARAMS ((bfd *)); -long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); +long +bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect)); -long bfd_canonicalize_reloc - (bfd *abfd, asection *sec, arelent **loc, asymbol **syms); +long +bfd_canonicalize_reloc PARAMS ((bfd *abfd, asection *sec, arelent **loc, asymbol **syms)); -void bfd_set_reloc - (bfd *abfd, asection *sec, arelent **rel, unsigned int count); +void +bfd_set_reloc PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count)); -bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); +bfd_boolean +bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags)); -int bfd_get_arch_size (bfd *abfd); +int +bfd_get_arch_size PARAMS ((bfd *abfd)); -int bfd_get_sign_extend_vma (bfd *abfd); +int +bfd_get_sign_extend_vma PARAMS ((bfd *abfd)); -bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); +bfd_boolean +bfd_set_start_address PARAMS ((bfd *abfd, bfd_vma vma)); -unsigned int bfd_get_gp_size (bfd *abfd); +unsigned int +bfd_get_gp_size PARAMS ((bfd *abfd)); -void bfd_set_gp_size (bfd *abfd, unsigned int i); +void +bfd_set_gp_size PARAMS ((bfd *abfd, unsigned int i)); -bfd_vma bfd_scan_vma (const char *string, const char **end, int base); +bfd_vma +bfd_scan_vma PARAMS ((const char *string, const char **end, int base)); -bfd_boolean bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd); +bfd_boolean +bfd_copy_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); #define bfd_copy_private_bfd_data(ibfd, obfd) \ BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ (ibfd, obfd)) -bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd); +bfd_boolean +bfd_merge_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); #define bfd_merge_private_bfd_data(ibfd, obfd) \ BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ (ibfd, obfd)) -bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); +bfd_boolean +bfd_set_private_flags PARAMS ((bfd *abfd, flagword flags)); #define bfd_set_private_flags(abfd, flags) \ BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) @@ -3968,7 +4044,8 @@ extern bfd_byte *bfd_get_relocated_secti (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **); -bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); +bfd_boolean +bfd_alt_mach_code PARAMS ((bfd *abfd, int alternative)); struct bfd_preserve { @@ -3982,27 +4059,34 @@ struct bfd_preserve struct bfd_hash_table section_htab; }; -bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); +bfd_boolean +bfd_preserve_save PARAMS ((bfd *, struct bfd_preserve *)); -void bfd_preserve_restore (bfd *, struct bfd_preserve *); +void +bfd_preserve_restore PARAMS ((bfd *, struct bfd_preserve *)); -void bfd_preserve_finish (bfd *, struct bfd_preserve *); +void +bfd_preserve_finish PARAMS ((bfd *, struct bfd_preserve *)); /* Extracted from archive.c. */ -symindex bfd_get_next_mapent - (bfd *abfd, symindex previous, carsym **sym); +symindex +bfd_get_next_mapent PARAMS ((bfd *abfd, symindex previous, carsym **sym)); -bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head); +bfd_boolean +bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head)); -bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous); +bfd * +bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous)); /* Extracted from corefile.c. */ -const char *bfd_core_file_failing_command (bfd *abfd); +const char * +bfd_core_file_failing_command PARAMS ((bfd *abfd)); -int bfd_core_file_failing_signal (bfd *abfd); +int +bfd_core_file_failing_signal PARAMS ((bfd *abfd)); -bfd_boolean core_file_matches_executable_p - (bfd *core_bfd, bfd *exec_bfd); +bfd_boolean +core_file_matches_executable_p PARAMS ((bfd *core_bfd, bfd *exec_bfd)); /* Extracted from targets.c. */ #define BFD_SEND(bfd, message, arglist) \ @@ -4362,35 +4446,42 @@ typedef struct bfd_target } bfd_target; -bfd_boolean bfd_set_default_target (const char *name); +bfd_boolean +bfd_set_default_target PARAMS ((const char *name)); -const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); +const bfd_target * +bfd_find_target PARAMS ((const char *target_name, bfd *abfd)); -const char ** bfd_target_list (void); +const char ** +bfd_target_list PARAMS ((void)); -const bfd_target *bfd_search_for_target - (int (*search_func) (const bfd_target *, void *), - void *); +const bfd_target * +bfd_search_for_target PARAMS ((int (*search_func) (const bfd_target *, void *), + void *)); /* Extracted from format.c. */ -bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); +bfd_boolean +bfd_check_format PARAMS ((bfd *abfd, bfd_format format)); -bfd_boolean bfd_check_format_matches - (bfd *abfd, bfd_format format, char ***matching); +bfd_boolean +bfd_check_format_matches PARAMS ((bfd *abfd, bfd_format format, char ***matching)); -bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); +bfd_boolean +bfd_set_format PARAMS ((bfd *abfd, bfd_format format)); -const char *bfd_format_string (bfd_format format); +const char * +bfd_format_string PARAMS ((bfd_format format)); /* Extracted from linker.c. */ -bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); +bfd_boolean +bfd_link_split_section PARAMS ((bfd *abfd, asection *sec)); #define bfd_link_split_section(abfd, sec) \ BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) /* Extracted from simple.c. */ -bfd_byte *bfd_simple_get_relocated_section_contents - (bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); +bfd_byte * +bfd_simple_get_relocated_section_contents PARAMS ((bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table)); #ifdef __cplusplus } --- binutils-2.15/bfd/config.bfd 2004-05-17 21:35:56.000000000 +0200 +++ binutils-2.15-nios2/bfd/config.bfd 2005-05-17 12:20:13.000000000 +0200 @@ -59,6 +59,7 @@ m6812*|m68hc12*) targ_archs="bfd_m68hc12 m68*) targ_archs=bfd_m68k_arch ;; m88*) targ_archs=bfd_m88k_arch ;; mips*) targ_archs=bfd_mips_arch ;; +nios2*) targ_archs=bfd_nios2_arch ;; or32*) targ_archs=bfd_or32_arch ;; pdp11*) targ_archs=bfd_pdp11_arch ;; pj*) targ_archs="bfd_pj_arch bfd_i386_arch";; @@ -874,6 +875,10 @@ case "${targ}" in targ_underscore=yes ;; + nios2-*-*) + targ_defvec=bfd_elf32_littlenios2_vec + ;; + openrisc-*-elf) targ_defvec=bfd_elf32_openrisc_vec ;; --- binutils-2.15/bfd/configure 2004-05-17 21:35:57.000000000 +0200 +++ binutils-2.15-nios2/bfd/configure 2005-05-17 12:20:13.000000000 +0200 @@ -6322,6 +6322,7 @@ do bfd_elf32_mcore_little_vec) tb="$tb elf32-mcore.lo elf32.lo $elf" ;; bfd_elf32_mn10200_vec) tb="$tb elf-m10200.lo elf32.lo $elf" ;; bfd_elf32_mn10300_vec) tb="$tb elf-m10300.lo elf32.lo $elf" ;; + bfd_elf32_littlenios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; bfd_elf32_msp430_vec) tb="$tb elf32-msp430.lo elf32.lo $elf" ;; bfd_elf32_nbigmips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; --- binutils-2.15/bfd/configure.in 2004-05-17 21:35:57.000000000 +0200 +++ binutils-2.15-nios2/bfd/configure.in 2005-05-17 12:20:13.000000000 +0200 @@ -631,6 +631,7 @@ do bfd_elf32_mcore_little_vec) tb="$tb elf32-mcore.lo elf32.lo $elf" ;; bfd_elf32_mn10200_vec) tb="$tb elf-m10200.lo elf32.lo $elf" ;; bfd_elf32_mn10300_vec) tb="$tb elf-m10300.lo elf32.lo $elf" ;; + bfd_elf32_littlenios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; bfd_elf32_msp430_vec) tb="$tb elf32-msp430.lo elf32.lo $elf" ;; bfd_elf32_nbigmips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; --- binutils-2.15/bfd/cpu-nios2.c 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/bfd/cpu-nios2.c 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,70 @@ +/* bfd back-end for Altera Nios II support + + Copyright (C) 2003 + by Nigel Gray (ngray@altera.com). + +This file is part of BFD, the Binary File Descriptor library. + +This program 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 of the License, or +(at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static const bfd_arch_info_type *nios2_compatible + (const bfd_arch_info_type *, const bfd_arch_info_type *); + +/* The default routine tests bits_per_word, which is wrong on mips as + mips word size doesn't correlate with reloc size. */ + +static const bfd_arch_info_type * +nios2_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b) +{ + if (a->arch != b->arch) + return NULL; + + /* Machine compatibility is checked in + _bfd_mips_elf_merge_private_bfd_data. */ + + return a; +} + +#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \ + { \ + BITS_WORD, /* bits in a word */ \ + BITS_ADDR, /* bits in an address */ \ + 8, /* 8 bits in a byte */ \ + bfd_arch_nios2, \ + NUMBER, \ + "nios2", \ + PRINT, \ + 3, \ + DEFAULT, \ + nios2_compatible, \ + bfd_default_scan, \ + NEXT, \ + } + +#define NN(index) (&arch_info_struct[(index) + 1]) + +static const bfd_arch_info_type arch_info_struct[] = +{ + N (32, 32, bfd_mach_nios2, "nios2", FALSE, 0), +}; + +/* There is only one architecture - but we give the default a machine number of 0 + so the linker can distinguish it */ +const bfd_arch_info_type bfd_nios2_arch = +N (32, 32, 0, "nios2", TRUE, &arch_info_struct[0]); --- binutils-2.15/bfd/elf.c 2004-05-17 21:35:57.000000000 +0200 +++ binutils-2.15-nios2/bfd/elf.c 2005-05-17 12:20:13.000000000 +0200 @@ -3286,9 +3286,14 @@ map_sections_to_segments (bfd *abfd) phdr_size = elf_tdata (abfd)->program_header_size; if (phdr_size == 0) phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr; + + /* NG - for standalone embedded applications we don't want the program + headers or ELF header in the output memory map (cf CSP) */ if ((abfd->flags & D_PAGED) == 0 || sections[0]->lma < phdr_size - || sections[0]->lma % maxpagesize < phdr_size % maxpagesize) + || sections[0]->lma % maxpagesize < phdr_size % maxpagesize + || (elf_tdata (abfd)->elf_header[0].e_ident[EI_OSABI] + == ELFOSABI_STANDALONE)) phdr_in_segment = FALSE; } --- binutils-2.15/bfd/elf32-nios2.c 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/bfd/elf32-nios2.c 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,2188 @@ +/* New Jersey-specific support for 32-bit ELF + + Copyright (C) 2003 + by Nigel Gray (ngray@altera.com). + + +This file is part of BFD, the Binary File Descriptor library. + +This program 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 of the License, or +(at your option) any later version. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file handles Altera New Jersey ELF targets */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" +#include "elf-bfd.h" +#include "elf/nios2.h" +#include "opcode/nios2.h" + +/* use RELA relocations*/ +#ifndef USE_RELA +#define USE_RELA +#endif + +#ifdef USE_REL +#undef USE_REL +#endif + +/* Function prototypes */ + +static reloc_howto_type *nios2_elf32_bfd_reloc_type_lookup + (bfd *, bfd_reloc_code_real_type); + +static bfd_boolean nios2_elf32_relax_section + (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); + +static bfd_boolean nios2_elf32_relax_delete_bytes + (bfd *, asection *, bfd_vma, int); + +static reloc_howto_type *nios2_elf32_rtype_to_howto + (unsigned int r_type, bfd_boolean rela_p); + +static void nios2_elf32_info_to_howto + (bfd * abfd, arelent * cache_ptr, Elf_Internal_Rela * dst); + +static bfd_boolean nios2_elf32_relocate_section + (bfd * output_bfd, struct bfd_link_info * info, bfd * input_bfd, + asection * input_section, bfd_byte * contents, + Elf_Internal_Rela * relocs, Elf_Internal_Sym * local_syms, + asection ** local_sections); + +static reloc_howto_type *lookup_howto (unsigned int rtype); + +static bfd_reloc_status_type nios2_elf_final_gp + (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *, + struct bfd_link_info *); + +static bfd_boolean nios2_elf_assign_gp + (bfd *, bfd_vma *, struct bfd_link_info *); + +static bfd_reloc_status_type nios2_elf32_ignore_reloc + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_hi16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_lo16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_hiadj16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_pcrel16_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_call26_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_gprel_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_ujmp_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_cjmp_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_callr_relocate + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); + +static bfd_reloc_status_type nios2_elf32_do_hi16_relocate + (bfd *, reloc_howto_type *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); + +static bfd_reloc_status_type nios2_elf32_do_lo16_relocate + (bfd *, reloc_howto_type *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); + +static bfd_reloc_status_type nios2_elf32_do_hiadj16_relocate + (bfd *, reloc_howto_type *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); + +static bfd_reloc_status_type nios2_elf32_do_pcrel16_relocate + (bfd *, reloc_howto_type *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); + +static bfd_reloc_status_type nios2_elf32_do_call26_relocate + (bfd *, reloc_howto_type *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); + +static bfd_reloc_status_type nios2_elf32_do_gprel_relocate + (bfd *, reloc_howto_type *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); + +static bfd_reloc_status_type nios2_elf32_do_ujmp_relocate + (bfd *, reloc_howto_type *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); + +static bfd_reloc_status_type nios2_elf32_do_cjmp_relocate + (bfd *, reloc_howto_type *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); + +static bfd_reloc_status_type nios2_elf32_do_callr_relocate + (bfd *, reloc_howto_type *, asection *, + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); + + +static void nios2_elf32_post_process_headers + (bfd *, struct bfd_link_info *); + +static bfd_boolean nios2_elf32_section_from_shdr + (bfd *, Elf_Internal_Shdr *, const char *name); + +static bfd_boolean nios2_elf32_section_flags + (flagword *, Elf_Internal_Shdr *); + +static bfd_boolean nios2_elf32_fake_sections + (bfd *, Elf_Internal_Shdr *, asection *); + + + +static bfd_boolean nios2_elf32_check_relocs + (bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *); + +static asection *nios2_elf32_gc_mark_hook (asection * sec, + struct bfd_link_info * + info, + Elf_Internal_Rela * rel, + struct elf_link_hash_entry + * h, + Elf_Internal_Sym * sym); + + +/* target vector */ +extern const bfd_target bfd_elf32_littlenios2_vec; + +/* The relocation table used for SHT_REL sections. */ + +static reloc_howto_type elf_nios2_howto_table_rel[] = { + /* No relocation. */ + HOWTO (R_NIOS2_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 */ + bfd_elf_generic_reloc, /* special_function */ + "R_NIOS2_NONE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* 16-bit signed immediate relocation */ + HOWTO (R_NIOS2_S16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_signed, /* complain on overflow */ + bfd_elf_generic_reloc, /* special function */ + "R_NIOS2_S16", /* name */ + FALSE, /* partial_inplace */ + 0x003fffc0, /* src_mask */ + 0x003fffc0, /* dest_mask */ + FALSE), /* pcrel_offset */ + + /* 16-bit unsigned immediate relocation */ + HOWTO (R_NIOS2_U16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_unsigned, /* complain on overflow */ + bfd_elf_generic_reloc, /* special function */ + "R_NIOS2_U16", /* name */ + FALSE, /* partial_inplace */ + 0x003fffc0, /* src_mask */ + 0x003fffc0, /* dest_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NIOS2_PCREL16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_signed, /* complain on overflow */ + nios2_elf32_pcrel16_relocate, /* special function */ + "R_NIOS2_PCREL16", /* name */ + FALSE, /* partial_inplace */ + 0x003fffc0, /* src_mask */ + 0x003fffc0, /* dest_mask */ + TRUE), /* pcrel_offset */ + + HOWTO (R_NIOS2_CALL26, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + FALSE, /* pc_relative */ + 6, /* bitpos */ + complain_overflow_dont, /* complain on overflow */ + nios2_elf32_call26_relocate, /* special function */ + "R_NIOS2_CALL26", /* name */ + FALSE, /* partial_inplace */ + 0xffffffc0, /* src_mask */ + 0xffffffc0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_NIOS2_IMM5, + 0, + 2, + 5, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_IMM5", + FALSE, + 0x000007c0, + 0x000007c0, + FALSE), + + HOWTO (R_NIOS2_CACHE_OPX, + 0, + 2, + 5, + FALSE, + 22, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_CACHE_OPX", + FALSE, + 0x07c00000, + 0x07c00000, + FALSE), + + HOWTO (R_NIOS2_IMM6, + 0, + 2, + 6, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_IMM6", + FALSE, + 0x00000fc0, + 0x00000fc0, + FALSE), + + HOWTO (R_NIOS2_IMM8, + 0, + 2, + 8, + FALSE, + 6, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_IMM8", + FALSE, + 0x00003fc0, + 0x00003fc0, + FALSE), + + HOWTO (R_NIOS2_HI16, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_hi16_relocate, + "R_NIOS2_HI16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_LO16, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_lo16_relocate, + "R_NIOS2_LO16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_HIADJ16, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_hiadj16_relocate, + "R_NIOS2_HIADJ16", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_BFD_RELOC_32, + 0, + 2, /* long */ + 32, + FALSE, + 0, + complain_overflow_dont, + bfd_elf_generic_reloc, + "R_NIOS2_BFD_RELOC32", + FALSE, + 0xffffffff, + 0xffffffff, + FALSE), + + HOWTO (R_NIOS2_BFD_RELOC_16, + 0, + 1, /* short */ + 16, + FALSE, + 0, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_BFD_RELOC16", + FALSE, + 0x0000ffff, + 0x0000ffff, + FALSE), + + HOWTO (R_NIOS2_BFD_RELOC_8, + 0, + 0, /* byte */ + 8, + FALSE, + 0, + complain_overflow_bitfield, + bfd_elf_generic_reloc, + "R_NIOS2_BFD_RELOC8", + FALSE, + 0x000000ff, + 0x000000ff, + FALSE), + + HOWTO (R_NIOS2_GPREL, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_gprel_relocate, + "R_NIOS2_GPREL", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_GNU_VTINHERIT, + 0, + 2, /* short */ + 0, + FALSE, + 0, + complain_overflow_dont, + NULL, + "R_NIOS2_GNU_VTINHERIT", + FALSE, + 0, + 0, + FALSE), + + HOWTO (R_NIOS2_GNU_VTENTRY, + 0, + 2, /* byte */ + 0, + FALSE, + 0, + complain_overflow_dont, + _bfd_elf_rel_vtable_reloc_fn, + "R_NIOS2_GNU_VTENTRY", + FALSE, + 0, + 0, + FALSE), + + HOWTO (R_NIOS2_UJMP, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_ujmp_relocate, + "R_NIOS2_UJMP", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_CJMP, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_cjmp_relocate, + "R_NIOS2_CJMP", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_CALLR, + 0, + 2, + 32, + FALSE, + 6, + complain_overflow_dont, + nios2_elf32_callr_relocate, + "R_NIOS2_CALLR", + FALSE, + 0x003fffc0, + 0x003fffc0, + FALSE), + + HOWTO (R_NIOS2_ALIGN, + 0, + 2, + 0, + FALSE, + 0, + complain_overflow_dont, + nios2_elf32_ignore_reloc, + "R_NIOS2_ALIGN", + FALSE, + 0, + 0, + TRUE), + +/* add other relocations here */ +}; + +static unsigned char elf_code_to_howto_index[R_NIOS2_ILLEGAL + 1]; + +static reloc_howto_type * +lookup_howto (unsigned int rtype) +{ + static int initialized = 0; + int i; + int howto_tbl_size = (int) (sizeof (elf_nios2_howto_table_rel) + / sizeof (elf_nios2_howto_table_rel[0])); + + if (!initialized) + { + initialized = 1; + memset (elf_code_to_howto_index, 0xff, + sizeof (elf_code_to_howto_index)); + for (i = 0; i < howto_tbl_size; i++) + elf_code_to_howto_index[elf_nios2_howto_table_rel[i].type] = i; + } + + BFD_ASSERT (rtype <= R_NIOS2_ILLEGAL); + i = elf_code_to_howto_index[rtype]; + if (i >= howto_tbl_size) + return 0; + return elf_nios2_howto_table_rel + i; +} + +/* + map for converting BFD reloc types to New Jersey + reloc types + */ +struct elf_reloc_map +{ + bfd_reloc_code_real_type bfd_val; + enum elf_nios2_reloc_type elf_val; +}; + +static const struct elf_reloc_map nios2_reloc_map[] = { + {BFD_RELOC_NIOS2_S16, R_NIOS2_S16}, + {BFD_RELOC_NIOS2_U16, R_NIOS2_U16}, + {BFD_RELOC_16_PCREL, R_NIOS2_PCREL16}, + {BFD_RELOC_NIOS2_CALL26, R_NIOS2_CALL26}, + {BFD_RELOC_NIOS2_IMM5, R_NIOS2_IMM5}, + {BFD_RELOC_NIOS2_CACHE_OPX, R_NIOS2_CACHE_OPX}, + {BFD_RELOC_NIOS2_IMM6, R_NIOS2_IMM6}, + {BFD_RELOC_NIOS2_IMM8, R_NIOS2_IMM8}, + {BFD_RELOC_NIOS2_HI16, R_NIOS2_HI16}, + {BFD_RELOC_NIOS2_LO16, R_NIOS2_LO16}, + {BFD_RELOC_NIOS2_HIADJ16, R_NIOS2_HIADJ16}, + {BFD_RELOC_32, R_NIOS2_BFD_RELOC_32}, + {BFD_RELOC_16, R_NIOS2_BFD_RELOC_16}, + {BFD_RELOC_8, R_NIOS2_BFD_RELOC_8}, + {BFD_RELOC_NIOS2_GPREL, R_NIOS2_GPREL}, + {BFD_RELOC_VTABLE_INHERIT, R_NIOS2_GNU_VTINHERIT}, + {BFD_RELOC_VTABLE_ENTRY, R_NIOS2_GNU_VTENTRY}, + {BFD_RELOC_NIOS2_UJMP, R_NIOS2_UJMP}, + {BFD_RELOC_NIOS2_CJMP, R_NIOS2_CJMP}, + {BFD_RELOC_NIOS2_CALLR, R_NIOS2_CALLR}, + {BFD_RELOC_NIOS2_ALIGN, R_NIOS2_ALIGN}, +}; + +/* Given a BFD reloc type, return a howto structure. */ + +static reloc_howto_type * +nios2_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) +{ + int i; + for (i = 0; + i < (int) (sizeof (nios2_reloc_map) / sizeof (struct elf_reloc_map)); + ++i) + { + if (nios2_reloc_map[i].bfd_val == code) + return &elf_nios2_howto_table_rel[(int) nios2_reloc_map[i].elf_val]; + } + + return NULL; +} + +/* Helper function for nios2_elf32_info_to_howto */ + +static reloc_howto_type * +nios2_elf32_rtype_to_howto (unsigned int r_type, + bfd_boolean rela_p ATTRIBUTE_UNUSED) +{ + BFD_ASSERT (r_type < R_NIOS2_ILLEGAL); + return &elf_nios2_howto_table_rel[r_type]; +} + +/* Given a ELF32 relocation, fill in a arelent structure */ + +static void +nios2_elf32_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, arelent * cache_ptr, + Elf_Internal_Rela * dst) +{ + unsigned int r_type; + + r_type = ELF32_R_TYPE (dst->r_info); + cache_ptr->howto = nios2_elf32_rtype_to_howto (r_type, FALSE); + + // FIXME - do we need to do anything else here??? +} + +/* The assembler has output long jmp/call sequences for all calls + * and pc-relative branches that it cannot guarantee are within + * range, so the linker must attempt to "relax" these sequences to + * short branches and calls if it can. We avoid having to re-relax by + * replacing redundant instructions with nops instead of deleting them. + * + * + **/ +static bfd_boolean +nios2_elf32_relax_section (bfd * abfd, + asection * sec, + struct bfd_link_info *link_info, bfd_boolean * again) +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel, *irelend; + bfd_byte *contents = NULL; + Elf_Internal_Sym *isymbuf = NULL; + +#define OP_MATCH_NOP 0x0001883a + + /* Assume nothing changes. */ + *again = FALSE; + + /* We don't have to do anything for a relocatable link, if + this section does not have relocs, or if this is not a + code section. */ + if (link_info->relocatable + || (sec->flags & SEC_RELOC) == 0 + || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0) + return TRUE; + + /* If this is the first time we have been called for this section, + initialize the cooked size. */ + if (sec->_cooked_size == 0) + sec->_cooked_size = sec->_raw_size; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + /* Get a copy of the native relocations. */ + internal_relocs = (_bfd_elf_link_read_relocs + (abfd, sec, (void *) NULL, (Elf_Internal_Rela *) NULL, + link_info->keep_memory)); + if (internal_relocs == NULL) + goto error_return; + + /* Walk through them looking for relaxing opportunities. */ + irelend = internal_relocs + sec->reloc_count; + for (irel = internal_relocs; irel < irelend; irel++) + { + bfd_vma symval; + + /* If this isn't something that can be relaxed, then ignore + this reloc. */ + if (ELF32_R_TYPE (irel->r_info) != (int) R_NIOS2_UJMP + && ELF32_R_TYPE (irel->r_info) != (int) R_NIOS2_CJMP + && ELF32_R_TYPE (irel->r_info) != (int) R_NIOS2_CALLR) + { + continue; + } + + /* Get the section contents if we haven't done so already. */ + if (contents == NULL) + { + /* Get cached copy if it exists. */ + if (elf_section_data (sec)->this_hdr.contents != NULL) + contents = elf_section_data (sec)->this_hdr.contents; + else + { + /* Go get them off disk. */ + contents = (bfd_byte *) bfd_malloc (sec->_raw_size); + if (contents == NULL) + goto error_return; + + if (!bfd_get_section_contents (abfd, sec, contents, + (file_ptr) 0, sec->_raw_size)) + goto error_return; + } + } + + /* Read this BFD's local symbols if we haven't done so already. */ + if (isymbuf == NULL && symtab_hdr->sh_info != 0) + { + isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; + if (isymbuf == NULL) + isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, + symtab_hdr->sh_info, 0, + NULL, NULL, NULL); + if (isymbuf == NULL) + goto error_return; + } + + /* Get the value of the symbol referred to by the reloc. */ + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) + { + /* A local symbol. */ + Elf_Internal_Sym *isym; + asection *sym_sec; + + isym = isymbuf + ELF32_R_SYM (irel->r_info); + if (isym->st_shndx == SHN_UNDEF) + sym_sec = bfd_und_section_ptr; + else if (isym->st_shndx == SHN_ABS) + sym_sec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + sym_sec = bfd_com_section_ptr; + else + sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); + symval = (isym->st_value + + sym_sec->output_section->vma + sym_sec->output_offset); + } + else + { + unsigned long indx; + struct elf_link_hash_entry *h; + + /* An external symbol. */ + indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + { + /* This appears to be a reference to an undefined + symbol. Just ignore it--it will be caught by the + regular reloc processing. */ + continue; + } + + symval = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + } + + /* For simplicity of coding, we are going to modify the section + contents, the section relocs, and the BFD symbol table. We + must tell the rest of the code not to free up this + information. It would be possible to instead create a table + of changes which have to be made, as is done in coff-mips.c; + that would be more work, but would require less memory when + the linker is run. */ + + /* try to turn : + * movhi at, %hi(symbol) + * movui at, %lo(symbol) + * callr at + * into: + * call symbol + */ + if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_CALLR) + { + bfd_vma targ_addr = symval + irel->r_addend; + bfd_vma curr_addr = (sec->output_section->vma + sec->output_offset); + bfd_vma targ_page, curr_page; + targ_page = targ_addr & 0xf0000000; + curr_page = curr_addr & 0xf0000000; + + if (targ_page == curr_page) + { + /* change the opcode to a call */ + bfd_put_32 (abfd, OP_MATCH_CALL, contents + irel->r_offset); + /* Note that we've changed the relocs, section contents, etc. */ + elf_section_data (sec)->relocs = internal_relocs; + elf_section_data (sec)->this_hdr.contents = contents; + symtab_hdr->contents = (unsigned char *) isymbuf; + + /* Fix the relocation's type. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NIOS2_CALL26); + + /* replace next two instructions with nops */ + bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 4); + bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 8); + } + } + + /* try to turn : + * movhi at, %hi(symbol) + * movui at, %lo(symbol) + * jmp at + * into: + * br symbol + */ + if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_UJMP) + { + bfd_vma pcrel_offset; + Elf_Internal_Rela *irelalign = NULL; + Elf_Internal_Rela *irela = elf_section_data (sec)->relocs; + Elf_Internal_Rela *irelend = irel + sec->reloc_count; + + for (; irela < irelend; irela++) + { + if (ELF32_R_TYPE (irela->r_info) == (int) R_NIOS2_ALIGN + && irela->r_offset > irel->r_offset + 4 + && 8 < (1 << irela->r_addend)) + { + irelalign = irela; + break; + } + } + + /* calculate the pcrelative offset from current location */ + pcrel_offset = symval; + pcrel_offset -= (sec->output_section->vma + sec->output_offset); + pcrel_offset += irel->r_addend; + + /* we need to compute the pcrel_offset from the next instruction */ + pcrel_offset -= (irel->r_offset + 4); + + /* does this value fit in 16 bits */ + if ((irelalign == NULL && (long) pcrel_offset <= 0x8004 + && (long) pcrel_offset >= -0x8000) || (irelalign != NULL + && (long) pcrel_offset + <= 0x7ffc + && (long) pcrel_offset + >= -0x8000)) + { + /* change the opcode to an unconditional branch */ + bfd_put_32 (abfd, OP_MATCH_BR, contents + irel->r_offset); + /* Note that we've changed the relocs, section contents, etc. */ + elf_section_data (sec)->relocs = internal_relocs; + elf_section_data (sec)->this_hdr.contents = contents; + symtab_hdr->contents = (unsigned char *) isymbuf; + + /* Fix the relocation's type. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NIOS2_PCREL16); + + /* replace next two instructions with nops */ + bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 4); + bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 8); + } + } + + /* try to turn : + * b{cond} a, b skip + * movhi at, %hi(symbol) + * movui at, %lo(symbol) + * jmp at + * skip: + * ... + * into: + * br{opp_cond} a, b, symbol + */ + if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_CJMP) + { + bfd_vma pcrel_offset; + Elf_Internal_Rela *irelalign = NULL; + Elf_Internal_Rela *irela = elf_section_data (sec)->relocs; + Elf_Internal_Rela *irelend = irel + sec->reloc_count; + + for (; irela < irelend; irela++) + { + if (ELF32_R_TYPE (irela->r_info) == (int) R_NIOS2_ALIGN + && irela->r_offset > irel->r_offset + 4 + && 8 < (1 << irela->r_addend)) + { + irelalign = irela; + break; + } + } + + /* calculate the pcrelative offset from current location */ + pcrel_offset = symval; + pcrel_offset -= (sec->output_section->vma + sec->output_offset); + pcrel_offset += irel->r_addend; + + /* we need to compute the pcrel_offset from this instruction + * ie the movhi */ + pcrel_offset -= (irel->r_offset); + + /* does this value fit in 16 bits */ + if ((irelalign == NULL && (long) pcrel_offset <= 0x8008 + && (long) pcrel_offset >= -0x8000) || (irelalign != NULL + && (long) pcrel_offset + <= 0x7ffc + && (long) pcrel_offset + >= -0x8000)) + { + unsigned long opcode, op_a, op_b; + /* get the conditional branch opcode */ + opcode = bfd_get_32 (abfd, contents + irel->r_offset - 4); + /* reverse the condition */ + switch (opcode & OP_MASK_OP) + { + case OP_MATCH_BEQ: + opcode = (opcode & ~OP_MASK_OP) | OP_MATCH_BNE; + break; + case OP_MATCH_BNE: + opcode = (opcode & ~OP_MASK_OP) | OP_MATCH_BEQ; + break; + case OP_MATCH_BGE: + case OP_MATCH_BGEU: + case OP_MATCH_BLT: + case OP_MATCH_BLTU: + /* swap the operands */ + op_a = (opcode & OP_MASK_RRT) << 5; + op_b = (opcode & OP_MASK_RRS) >> 5; + opcode = + (opcode & ~(OP_MASK_RRS | OP_MASK_RRT)) | op_a | op_b; + break; + default: + fprintf (stderr, + "relaxation error - expecting conditional branch, aborting\n"); + abort (); + break; + } + + /* we must set the branch target to zero so that the skip over the jmp doesn't get + * added to the jmp */ + opcode = opcode & (~OP_MASK_IMM16); + + /* change the opcode to the reversed conditional branch */ + bfd_put_32 (abfd, opcode, contents + irel->r_offset - 4); + /* Note that we've changed the relocs, section contents, etc. */ + elf_section_data (sec)->relocs = internal_relocs; + elf_section_data (sec)->this_hdr.contents = contents; + symtab_hdr->contents = (unsigned char *) isymbuf; + + /* Fix the relocation's type. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_NIOS2_PCREL16); + + /* this relocation's offset has also been reduced by 4 bytes */ + irel->r_offset -= 4; + + /* replace next two instructions with nops */ + bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 4); + bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 8); + bfd_put_32 (abfd, OP_MATCH_NOP, contents + irel->r_offset + 12); + } + } + + /* otherwise, leave alone */ + } + + if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) + { + if (!link_info->keep_memory) + free (isymbuf); + else + { + /* Cache the symbols for elf_link_input_bfd. */ + symtab_hdr->contents = (unsigned char *) isymbuf; + } + } + + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + { + if (!link_info->keep_memory) + free (contents); + else + { + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; + } + } + + if (internal_relocs != NULL + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); + + + return TRUE; + +error_return: + if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) + free (isymbuf); + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + free (contents); + if (internal_relocs != NULL + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); + + return FALSE; +} + +/* Delete some bytes from a section while relaxing. + * Copied from mn10200 port */ + +static bfd_boolean +nios2_elf32_relax_delete_bytes (bfd * abfd, + asection * sec, bfd_vma addr, int count) +{ + Elf_Internal_Shdr *symtab_hdr; + unsigned int sec_shndx; + bfd_byte *contents; + Elf_Internal_Rela *irel, *irelend; + Elf_Internal_Rela *irelalign; + bfd_vma toaddr; + Elf_Internal_Sym *isym; + Elf_Internal_Sym *isymend; + struct elf_link_hash_entry **sym_hashes; + struct elf_link_hash_entry **end_hashes; + unsigned int symcount; + asection *asec; + + sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + + contents = elf_section_data (sec)->this_hdr.contents; + + /* The deletion must stop at the next ALIGN reloc for an aligment + power larger than the number of bytes we are deleting. */ + + irelalign = NULL; + /* +1 because we need to readjust symbols at end of section */ + toaddr = sec->_cooked_size + 1; + + irel = elf_section_data (sec)->relocs; + irelend = irel + sec->reloc_count; + + for (; irel < irelend; irel++) + { + if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_ALIGN + && irel->r_offset > addr && count < (1 << irel->r_addend)) + { + irelalign = irel; + /* +1 because we need to readjust symbols at end of section */ + toaddr = irel->r_offset + 1; + break; + } + } + + + /* Actually delete the bytes. */ + memmove (contents + addr, contents + addr + count, + (size_t) ((toaddr - 1) - addr - count)); + + if (irelalign == NULL) + sec->_cooked_size -= count; + else + { + int i; + +#define NOP_OPCODE (0x0001883a) + + BFD_ASSERT ((count & 3) == 0); + for (i = 0; i < count; i += 4) + bfd_put_32 (abfd, (bfd_vma) NOP_OPCODE, + contents + (toaddr - 1) - count + i); + } + + /* get the symbol table */ + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + isym = (Elf_Internal_Sym *) symtab_hdr->contents; + + /* Adjust all the reloc offsets in this section. */ + for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) + { + /* Get the new reloc address. */ + if ((irel->r_offset > addr && irel->r_offset < toaddr)) + irel->r_offset -= count; + } + + /* Adjust relocations against targets in this section whose positions + * have moved as a result of the relaxation */ + + for (asec = abfd->sections; asec; asec = asec->next) + { + irelend = elf_section_data (asec)->relocs + asec->reloc_count; + for (irel = elf_section_data (asec)->relocs; irel < irelend; irel++) + { + Elf_Internal_Sym *sym; + /* if the symbol which this reloc is against doesn't change + * we need to change the reloc addend */ + + sym = isym + ELF32_R_SYM (irel->r_info); + if (sym->st_shndx == sec_shndx + && !(sym->st_value > addr && sym->st_value < toaddr) + && sym->st_value + irel->r_addend > addr + && sym->st_value + irel->r_addend < toaddr) + { + irel->r_addend -= count; + } + + } + } + + /* Adjust the local symbols defined in this section. */ + for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) + { + if (isym->st_shndx == sec_shndx + && isym->st_value > addr && isym->st_value < toaddr) + isym->st_value -= count; + + + } + + /* Now adjust the global symbols defined in this section. */ + symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) + - symtab_hdr->sh_info); + sym_hashes = elf_sym_hashes (abfd); + end_hashes = sym_hashes + symcount; + for (; sym_hashes < end_hashes; sym_hashes++) + { + struct elf_link_hash_entry *sym_hash = *sym_hashes; + if ((sym_hash->root.type == bfd_link_hash_defined + || sym_hash->root.type == bfd_link_hash_defweak) + && sym_hash->root.u.def.section == sec + && sym_hash->root.u.def.value > addr + && sym_hash->root.u.def.value < toaddr) + { + sym_hash->root.u.def.value -= count; + } + } + + return TRUE; +} + +struct bfd_link_info *nios2_link_info = NULL; + +void +_bfd_set_link_info (info) + struct bfd_link_info *info; +{ + nios2_link_info = info; +} + +bfd_boolean linker_force_make_executable = FALSE; + +void +_bfd_set_force_make_executable (force) + bfd_boolean force; +{ + linker_force_make_executable = force; +} + +/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a + dangerous relocation. */ + +static bfd_boolean +nios2_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp, struct bfd_link_info *info) +{ + + bfd_boolean gp_found; + struct bfd_hash_entry *h; + struct bfd_link_hash_entry *lh; + + /* If we've already figured out what GP will be, just return it. */ + *pgp = _bfd_get_gp_value (output_bfd); + if (*pgp) + return TRUE; + + h = bfd_hash_lookup (&info->hash->table, "_gp", FALSE, FALSE); + lh = (struct bfd_link_hash_entry *) h; +lookup: + if (lh) + { + switch (lh->type) + { + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + case bfd_link_hash_common: + gp_found = FALSE; + break; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + gp_found = TRUE; + *pgp = lh->u.def.value; + break; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + lh = lh->u.i.link; + /* @@FIXME ignoring warning for now */ + goto lookup; + case bfd_link_hash_new: + default: + abort (); + } + } + else + gp_found = FALSE; + + if (!gp_found) + { + /* Only get the error once. */ + *pgp = 4; + _bfd_set_gp_value (output_bfd, *pgp); + return FALSE; + } + + _bfd_set_gp_value (output_bfd, *pgp); + + return TRUE; +} + +/* We have to figure out the gp value, so that we can adjust the + symbol value correctly. We look up the symbol _gp in the output + BFD. If we can't find it, we're stuck. We cache it in the ELF + target data. We don't need to adjust the symbol value for an + external symbol if we are producing relocatable output. */ + +static bfd_reloc_status_type +nios2_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, + char **error_message, bfd_vma *pgp, struct bfd_link_info *info) +{ + if (bfd_is_und_section (symbol->section) && !relocatable) + { + *pgp = 0; + return bfd_reloc_undefined; + } + + *pgp = _bfd_get_gp_value (output_bfd); + if (*pgp == 0 && (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0)) + { + /* if this is called without link_info, then + we cannot be doing a final link */ + if (info == NULL) + relocatable = TRUE; + + if (relocatable) + { + /* Make up a value. */ + *pgp = symbol->section->output_section->vma + 0x4000; + _bfd_set_gp_value (output_bfd, *pgp); + } + else if (!nios2_elf_assign_gp (output_bfd, pgp, info)) + { + *error_message = + (char *) + _("global pointer relative relocation when _gp not defined"); + return bfd_reloc_dangerous; + } + } + + return bfd_reloc_ok; +} + + +/* Relocations that require special handling */ + +/* This is for relocations used only when relaxing to ensure + * changes in size of section don't screw up .align */ +static bfd_reloc_status_type +nios2_elf32_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, + asymbol *symbol ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED, + asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) +{ + if (output_bfd != NULL) + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +nios2_elf32_hi16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, void *data, + asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_ok; + + return nios2_elf32_do_hi16_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_lo16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) +{ +/* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_ok; + + return nios2_elf32_do_lo16_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_hiadj16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ +/* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_ok; + + return nios2_elf32_do_hiadj16_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + + symbol->section->output_section-> + vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_pcrel16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ +/* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_ok; + + return nios2_elf32_do_pcrel16_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + + symbol->section->output_section-> + vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_call26_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) +{ +/* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_ok; + + return nios2_elf32_do_call26_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + + symbol->section->output_section-> + vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_gprel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, char **msg) +{ + bfd_vma relocation; + bfd_vma gp; + bfd_reloc_status_type r; + + +/* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_ok; + + relocation = symbol->value + + symbol->section->output_section->vma + symbol->section->output_offset; + + if ((r = + nios2_elf_final_gp (abfd, symbol, FALSE, msg, &gp, + nios2_link_info)) == bfd_reloc_ok) + { + relocation = relocation + reloc_entry->addend - gp; + reloc_entry->addend = 0; + if ((signed) relocation < -32768 || (signed) relocation > 32767) + { + *msg = _("global pointer relative address out of range"); + r = bfd_reloc_outofrange; + } + else + { + r = nios2_elf32_do_gprel_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + relocation, reloc_entry->addend); + } + } + + return r; +} + +static bfd_reloc_status_type +nios2_elf32_ujmp_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_ok; + + return nios2_elf32_do_ujmp_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_cjmp_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_ok; + + return nios2_elf32_do_cjmp_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + symbol->section->output_section->vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +static bfd_reloc_status_type +nios2_elf32_callr_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) +{ + /* This part is from bfd_elf_generic_reloc. */ + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd != NULL) + /* FIXME: See bfd_perform_relocation. Is this right? */ + return bfd_reloc_ok; + + + return nios2_elf32_do_callr_relocate (abfd, reloc_entry->howto, + input_section, + data, reloc_entry->address, + (symbol->value + + + symbol->section->output_section-> + vma + + symbol->section->output_offset), + reloc_entry->addend); +} + +/* Do the relocations which require special handling */ + +static bfd_reloc_status_type +nios2_elf32_do_hi16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) +{ + symbol_value = symbol_value + addend; + addend = 0; + symbol_value = (symbol_value >> 16) & 0xffff; + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + + +static bfd_reloc_status_type +nios2_elf32_do_lo16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) +{ + symbol_value = symbol_value + addend; + addend = 0; + symbol_value = symbol_value & 0xffff; + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_hiadj16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, bfd_vma offset, + bfd_vma symbol_value, bfd_vma addend) +{ + symbol_value = symbol_value + addend; + addend = 0; + symbol_value = + ((symbol_value >> 16) & 0xffff) + ((symbol_value >> 15) & 0x01); + return _bfd_final_link_relocate (howto, abfd, input_section, data, offset, + symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_pcrel16_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) +{ + // NIOS2 pc relative relocations are relative to the next 32-bit instruction so we need + // to subtract 4 before doing a final_link_relocate + symbol_value = symbol_value + addend - 4; + addend = 0; + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_call26_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) +{ + /* check that the relocation is in the same page as the current address */ + if (((symbol_value + addend) & 0xf0000000) + != ((input_section->output_section->vma + offset) & 0xf0000000)) + return bfd_reloc_overflow; + + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + + +static bfd_reloc_status_type +nios2_elf32_do_gprel_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) +{ + // because we need the output_bfd, the special handling is done + // in nios2_elf32_relocate_section or in nios2_elf32_gprel_relocate + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_value, addend); +} + +static bfd_reloc_status_type +nios2_elf32_do_ujmp_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) +{ + bfd_vma symbol_lo16, symbol_hi16; + bfd_reloc_status_type r; + symbol_value = symbol_value + addend; + addend = 0; + symbol_hi16 = (symbol_value >> 16) & 0xffff; + symbol_lo16 = symbol_value & 0xffff; + + r = _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_hi16, addend); + + if (r == bfd_reloc_ok) + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset + 4, symbol_lo16, addend); + + return r; +} + +static bfd_reloc_status_type +nios2_elf32_do_cjmp_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) +{ + bfd_vma symbol_lo16, symbol_hi16; + bfd_reloc_status_type r; + symbol_value = symbol_value + addend; + addend = 0; + symbol_hi16 = (symbol_value >> 16) & 0xffff; + symbol_lo16 = symbol_value & 0xffff; + + r = _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_hi16, addend); + + if (r == bfd_reloc_ok) + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset + 4, symbol_lo16, addend); + + return r; +} + +static bfd_reloc_status_type +nios2_elf32_do_callr_relocate (bfd *abfd, reloc_howto_type *howto, + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) +{ + bfd_vma symbol_lo16, symbol_hi16; + bfd_reloc_status_type r; + symbol_value = symbol_value + addend; + addend = 0; + symbol_hi16 = (symbol_value >> 16) & 0xffff; + symbol_lo16 = symbol_value & 0xffff; + + r = _bfd_final_link_relocate (howto, abfd, input_section, + data, offset, symbol_hi16, addend); + + if (r == bfd_reloc_ok) + return _bfd_final_link_relocate (howto, abfd, input_section, + data, offset + 4, symbol_lo16, addend); + + return r; +} + +/* + The function nios2_elf32_relocate_section is used by the linker + to perform relocations +*/ +static bfd_boolean +nios2_elf32_relocate_section (bfd * output_bfd, + struct bfd_link_info *info, + bfd * input_bfd, + asection * input_section, + bfd_byte * contents, + Elf_Internal_Rela * relocs, + Elf_Internal_Sym * local_syms, + asection ** local_sections) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + relend = relocs + input_section->reloc_count; + +// size_t psymalloc = 0; +// _bfd_generic_link_output_symbols(output_bfd, input_bfd, info, &psymalloc); + for (rel = relocs; rel < relend; rel++) + { + reloc_howto_type *howto; + unsigned long r_symndx; + Elf_Internal_Sym *sym; + asection *sec; + struct elf_link_hash_entry *h; + bfd_vma relocation; + bfd_vma gp; + bfd_vma reloc_address; + bfd_reloc_status_type r = bfd_reloc_ok; + const char *name = NULL; + int r_type; + const char *format; + char msgbuf[256]; + const char* msg = (const char*) NULL; + + + + r_type = ELF32_R_TYPE (rel->r_info); + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocatable) + { + /* This is a relocatable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sec = local_sections[r_symndx]; + rel->r_addend += sec->output_offset + sym->st_value; + } + } + continue; + } + + /* This is a final link. */ + howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info)); + h = NULL; + sym = NULL; + sec = NULL; + + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + + relocation = (sec->output_section->vma + + sec->output_offset + sym->st_value); + + // this ensures that relocations against duplicated symbols + // in merged sections that have been removed are fixed up against + // the remaining symbol and not the one that has been removed + if ((sec->flags & SEC_MERGE) + && ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + rel->r_addend = + _bfd_elf_rel_local_sym (output_bfd, sym, &sec, rel->r_addend); + rel->r_addend -= relocation; + rel->r_addend += sec->output_section->vma + sec->output_offset; + } + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); + + name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + name = h->root.root.string; + + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + + relocation = (h->root.u.def.value + + sec->output_section->vma + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + { + relocation = 0; + } + else + { + if (!((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset, TRUE))) + return FALSE; + relocation = 0; + } + } + + if (sec) + reloc_address = sec->output_section->vma + sec->output_offset + rel->r_offset; + else + reloc_address = 0; + + if (howto != NULL) + { + switch (howto->type) + { + case R_NIOS2_HI16: + r = + nios2_elf32_do_hi16_relocate (input_bfd, howto, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + case R_NIOS2_LO16: + r = + nios2_elf32_do_lo16_relocate (input_bfd, howto, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + case R_NIOS2_HIADJ16: + r = + nios2_elf32_do_hiadj16_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + case R_NIOS2_PCREL16: + r = + nios2_elf32_do_pcrel16_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + case R_NIOS2_GPREL: + // turns an absolute address into a gp-relative address + if (!nios2_elf_assign_gp (output_bfd, &gp, info)) + { + format = _("global pointer relative relocation at address 0x%08x when _gp not defined\n"); + sprintf(msgbuf, format, reloc_address); + msg = msgbuf; + r = bfd_reloc_dangerous; + } + else + { + relocation = relocation + rel->r_addend - gp; + rel->r_addend = 0; + if ((signed) relocation < -32768 + || (signed) relocation > 32767) + { + format = _("global pointer relative offset %d at address 0x%08x out of range -32678 to 32767\n"); + sprintf(msgbuf, format, (signed)relocation, reloc_address); + msg = msgbuf; + r = bfd_reloc_outofrange; + } + else + { + r = + _bfd_final_link_relocate (howto, input_bfd, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + } + } + + break; + case R_NIOS2_UJMP: + r = + nios2_elf32_do_ujmp_relocate (input_bfd, howto, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + case R_NIOS2_CJMP: + r = + nios2_elf32_do_cjmp_relocate (input_bfd, howto, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + case R_NIOS2_CALLR: + r = + nios2_elf32_do_callr_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + case R_NIOS2_CALL26: + r = + nios2_elf32_do_call26_relocate (input_bfd, howto, + input_section, contents, + rel->r_offset, relocation, + rel->r_addend); + break; + case R_NIOS2_ALIGN: + r = bfd_reloc_ok; + /* comment - for symmetry this would be + r = nios2_elf32_do_ignore_reloc (input_bfd, howto, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + but do_ignore_reloc would do no more than return bfd_reloc_ok */ + break; + default: + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + break; + } + } + else + { + r = bfd_reloc_notsupported; + } + + if (r != bfd_reloc_ok) + { + if (h != NULL) + name = h->root.root.string; + else + { + name = (bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name)); + if (name == NULL || *name == '\0') + name = bfd_section_name (input_bfd, sec); + } + + switch (r) + { + case bfd_reloc_overflow: + r = info->callbacks->reloc_overflow + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset); + break; + + case bfd_reloc_undefined: + r = info->callbacks->undefined_symbol + (info, name, input_bfd, input_section, rel->r_offset, TRUE); + break; + + case bfd_reloc_outofrange: + if (msg == NULL) + msg = _("relocation out of range"); + break; + + case bfd_reloc_notsupported: + if (msg == NULL) + msg = _("unsupported relocation"); + break; + + case bfd_reloc_dangerous: + if (msg == NULL) + msg = _("dangerous relocation"); + break; + + default: + if (msg == NULL) + msg = _("unknown error"); + break; + } + + if (msg) + { + r = info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + return linker_force_make_executable; + } + } + } + return TRUE; +} + + + +/* Handle an NIOS2 specific section when reading an object file. This + is called when elfcode.h finds a section with an unknown type. + FIXME: We need to handle the SHF_NIOS2_GPREL flag */ + +static bfd_boolean +nios2_elf32_section_from_shdr (bfd *abfd, + Elf_Internal_Shdr *hdr, const char *name) +{ + asection *newsect; + + /* NG - I'm keeping this code commented out at the moment + in case we add a .mdebug section */ + + /* + switch (hdr->sh_type) + { + case SHT_NIOS2_DEBUG: + if (strcmp (name, ".mdebug") != 0) + return FALSE; + break; + default: + return FALSE; + } + */ + + if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return FALSE; + + newsect = hdr->bfd_section; + + /* ditto */ + /* + if (hdr->sh_type == SHT_NIOS2_DEBUG) + { + if (! bfd_set_section_flags (abfd, newsect, + (bfd_get_section_flags (abfd, newsect) + | SEC_DEBUGGING))) + return FALSE; + } + */ + return TRUE; +} + +/* Convert NIOS2 specific section flags to bfd internal section flags. */ + +static bfd_boolean +nios2_elf32_section_flags (flagword *flags, Elf_Internal_Shdr *hdr) +{ + if (hdr->sh_flags & SHF_NIOS2_GPREL) + *flags |= SEC_SMALL_DATA; + + return TRUE; +} + +/* Set the correct type for an NIOS2 ELF section. We do this by the + section name, which is a hack, but ought to work. */ + +static bfd_boolean +nios2_elf32_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, + Elf_Internal_Shdr *hdr, asection *sec) +{ + register const char *name; + + name = bfd_get_section_name (abfd, sec); + + if (strcmp (name, ".mdebug") == 0) + { + /* we don't yet have an .mdebug section, but I'm leaving this here + in case we ever do + hdr->sh_type = SHT_NIOS2_DEBUG; + + if ((abfd->flags & DYNAMIC) != 0 ) + hdr->sh_entsize = 0; + else + hdr->sh_entsize = 1; + */ + } + else if ((sec->flags & SEC_SMALL_DATA) + || strcmp (name, ".sdata") == 0 + || strcmp (name, ".sbss") == 0 + || strcmp (name, ".lit4") == 0 || strcmp (name, ".lit8") == 0) + hdr->sh_flags |= SHF_NIOS2_GPREL; + + return TRUE; +} + +/* Look through the relocs for a section during the first phase. + Since we don't do .gots or .plts, we just need to consider the + virtual table relocs for gc. */ + +static bfd_boolean +nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info, + asection *sec, const Elf_Internal_Rela *relocs) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + + if (info->relocatable) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + sym_hashes_end = + sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym); + if (!elf_bad_symtab (abfd)) + sym_hashes_end -= symtab_hdr->sh_info; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + struct elf_link_hash_entry *h; + unsigned long r_symndx; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + switch (ELF32_R_TYPE (rel->r_info)) + { + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + case R_NIOS2_GNU_VTINHERIT: + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + + /* This relocation describes which C++ vtable entries are actually + used. Record for later use during GC. */ + case R_NIOS2_GNU_VTENTRY: + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + return FALSE; + break; + } + } + + return TRUE; +} + + +/* Return the section that should be marked against GC for a given + relocation. */ + +asection * +nios2_elf32_gc_mark_hook (asection *sec, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + Elf_Internal_Rela *rel, struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) +{ + if (h != NULL) + { + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_NIOS2_GNU_VTINHERIT: + case R_NIOS2_GNU_VTENTRY: + break; + + default: + switch (h->root.type) + { + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + return h->root.u.def.section; + + case bfd_link_hash_common: + return h->root.u.c.p->section; + + default: + break; + } + } + } + else + return bfd_section_from_elf_index (sec->owner, sym->st_shndx); + + return NULL; +} + +/* + NG ??? I'm marking the sections as standalone ie. I'm linking for + standalone embedded applications, not for UNIX System V or any other + OS/ABI - this may need to change when we deal with embedded PIC or + dynamic linking +*/ + +static void +nios2_elf32_post_process_headers (bfd *abfd, + struct bfd_link_info *link_info ATTRIBUTE_UNUSED) +{ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + + i_ehdrp = elf_elfheader (abfd); + i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_STANDALONE; +} + +#define ELF_ARCH bfd_arch_nios2 +#define ELF_MACHINE_CODE EM_ALTERA_NIOS2 + +/* for now we just make this 1, as we have no MMU in New Jersey */ + +#define ELF_MAXPAGESIZE 1 + +/* relocation table lookup macros */ + +#define bfd_elf32_bfd_reloc_type_lookup nios2_elf32_bfd_reloc_type_lookup + +/* JUMP_TABLE_LINK macros */ + +#define bfd_elf32_bfd_relax_section nios2_elf32_relax_section + +/* elf_info_to_howto (using RELA relocations) */ + +#define elf_info_to_howto nios2_elf32_info_to_howto + +/* elf backend functions */ + +#define elf_backend_can_gc_sections 1 + +#define elf_backend_relocate_section nios2_elf32_relocate_section +#define elf_backend_section_from_shdr nios2_elf32_section_from_shdr +#define elf_backend_section_flags nios2_elf32_section_flags +#define elf_backend_fake_sections nios2_elf32_fake_sections +#define elf_backend_post_process_headers nios2_elf32_post_process_headers +#define elf_backend_check_relocs nios2_elf32_check_relocs + +#define elf_backend_gc_mark_hook nios2_elf32_gc_mark_hook + + + +/* Support for SGI-ish mips targets. */ +#define TARGET_LITTLE_SYM bfd_elf32_littlenios2_vec +#define TARGET_LITTLE_NAME "elf32-littlenios2" +//#define TARGET_BIG_SYM bfd_elf32_bignios2_vec +//#define TARGET_BIG_NAME "elf32-bignios2" + +#include "elf32-target.h" --- binutils-2.15/bfd/libbfd.h 2004-02-12 00:23:20.000000000 +0100 +++ binutils-2.15-nios2/bfd/libbfd.h 2005-05-17 12:20:13.000000000 +0200 @@ -652,9 +652,11 @@ extern bfd_boolean _bfd_sh_align_load_sp #endif /* Extracted from init.c. */ /* Extracted from libbfd.c. */ -bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int); +bfd_boolean +bfd_write_bigendian_4byte_int PARAMS ((bfd *, unsigned int)); -unsigned int bfd_log2 (bfd_vma x); +unsigned int +bfd_log2 PARAMS ((bfd_vma x)); /* Extracted from bfdio.c. */ /* Extracted from bfdwin.c. */ @@ -673,13 +675,17 @@ extern bfd *bfd_last_cache; ((x)==bfd_last_cache? \ (FILE*) (bfd_last_cache->iostream): \ bfd_cache_lookup_worker(x)) -bfd_boolean bfd_cache_init (bfd *abfd); +bfd_boolean +bfd_cache_init PARAMS ((bfd *abfd)); -bfd_boolean bfd_cache_close (bfd *abfd); +bfd_boolean +bfd_cache_close PARAMS ((bfd *abfd)); -FILE* bfd_open_file (bfd *abfd); +FILE* +bfd_open_file PARAMS ((bfd *abfd)); -FILE *bfd_cache_lookup_worker (bfd *abfd); +FILE * +bfd_cache_lookup_worker PARAMS ((bfd *abfd)); /* Extracted from reloc.c. */ #ifdef _BFD_MAKE_TABLE_bfd_reloc_code_real @@ -1504,6 +1510,21 @@ static const char *const bfd_reloc_code_ "BFD_RELOC_MSP430_16", "BFD_RELOC_MSP430_16_PCREL_BYTE", "BFD_RELOC_MSP430_16_BYTE", + "BFD_RELOC_NIOS2_S16", + "BFD_RELOC_NIOS2_U16", + "BFD_RELOC_NIOS2_CALL26", + "BFD_RELOC_NIOS2_IMM5", + "BFD_RELOC_NIOS2_CACHE_OPX", + "BFD_RELOC_NIOS2_IMM6", + "BFD_RELOC_NIOS2_IMM8", + "BFD_RELOC_NIOS2_HI16", + "BFD_RELOC_NIOS2_LO16", + "BFD_RELOC_NIOS2_HIADJ16", + "BFD_RELOC_NIOS2_GPREL", + "BFD_RELOC_NIOS2_UJMP", + "BFD_RELOC_NIOS2_CJMP", + "BFD_RELOC_NIOS2_CALLR", + "BFD_RELOC_NIOS2_ALIGN", "BFD_RELOC_IQ2000_OFFSET_16", "BFD_RELOC_IQ2000_OFFSET_21", "BFD_RELOC_IQ2000_UHI16", @@ -1521,40 +1542,41 @@ static const char *const bfd_reloc_code_ }; #endif -reloc_howto_type *bfd_default_reloc_type_lookup - (bfd *abfd, bfd_reloc_code_real_type code); +reloc_howto_type * +bfd_default_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); -bfd_boolean bfd_generic_relax_section - (bfd *abfd, +bfd_boolean +bfd_generic_relax_section PARAMS ((bfd *abfd, asection *section, struct bfd_link_info *, - bfd_boolean *); + bfd_boolean *)); -bfd_boolean bfd_generic_gc_sections - (bfd *, struct bfd_link_info *); +bfd_boolean +bfd_generic_gc_sections PARAMS ((bfd *, struct bfd_link_info *)); -bfd_boolean bfd_generic_merge_sections - (bfd *, struct bfd_link_info *); +bfd_boolean +bfd_generic_merge_sections PARAMS ((bfd *, struct bfd_link_info *)); -bfd_byte *bfd_generic_get_relocated_section_contents - (bfd *abfd, +bfd_byte * +bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd, struct bfd_link_info *link_info, struct bfd_link_order *link_order, bfd_byte *data, bfd_boolean relocatable, - asymbol **symbols); + asymbol **symbols)); /* Extracted from archures.c. */ extern const bfd_arch_info_type bfd_default_arch_struct; -bfd_boolean bfd_default_set_arch_mach - (bfd *abfd, enum bfd_architecture arch, unsigned long mach); +bfd_boolean +bfd_default_set_arch_mach PARAMS ((bfd *abfd, enum bfd_architecture arch, unsigned long mach)); -const bfd_arch_info_type *bfd_default_compatible - (const bfd_arch_info_type *a, const bfd_arch_info_type *b); +const bfd_arch_info_type * +bfd_default_compatible PARAMS ((const bfd_arch_info_type *a, const bfd_arch_info_type *b)); -bfd_boolean bfd_default_scan - (const struct bfd_arch_info *info, const char *string); +bfd_boolean +bfd_default_scan PARAMS ((const struct bfd_arch_info *info, const char *string)); /* Extracted from elf.c. */ -struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name); +struct elf_internal_shdr * +bfd_elf_find_section PARAMS ((bfd *abfd, char *name)); --- binutils-2.15/bfd/reloc.c 2004-01-21 12:17:53.000000000 +0100 +++ binutils-2.15-nios2/bfd/reloc.c 2005-05-17 12:20:13.000000000 +0200 @@ -3943,6 +3943,39 @@ ENUMDOC msp430 specific relocation codes ENUM + BFD_RELOC_NIOS2_S16 +ENUMX + BFD_RELOC_NIOS2_U16 +ENUMX + BFD_RELOC_NIOS2_CALL26 +ENUMX + BFD_RELOC_NIOS2_IMM5 +ENUMX + BFD_RELOC_NIOS2_CACHE_OPX +ENUMX + BFD_RELOC_NIOS2_IMM6 +ENUMX + BFD_RELOC_NIOS2_IMM8 +ENUMX + BFD_RELOC_NIOS2_HI16 +ENUMX + BFD_RELOC_NIOS2_LO16 +ENUMX + BFD_RELOC_NIOS2_HIADJ16 +ENUMX + BFD_RELOC_NIOS2_GPREL +ENUMX + BFD_RELOC_NIOS2_UJMP +ENUMX + BFD_RELOC_NIOS2_CJMP +ENUMX + BFD_RELOC_NIOS2_CALLR +ENUMX + BFD_RELOC_NIOS2_ALIGN +ENUMDOC + Relocations used by the Altera New Jersey core + +ENUM BFD_RELOC_IQ2000_OFFSET_16 ENUMX BFD_RELOC_IQ2000_OFFSET_21 --- binutils-2.15/bfd/srec.c 2003-11-30 19:40:41.000000000 +0100 +++ binutils-2.15-nios2/bfd/srec.c 2005-05-17 12:20:13.000000000 +0200 @@ -1009,9 +1009,14 @@ srec_write_header (abfd) { unsigned int len = strlen (abfd->filename); - /* I'll put an arbitrary 40 char limit on header size. */ - if (len > 40) - len = 40; + /* validate Chunk for header */ + if (Chunk == 0) + Chunk = 1; + else if (Chunk > MAXCHUNK - 2) /* S0 has 2 address bytes */ + Chunk = MAXCHUNK - 2; + + if (len > Chunk) + len = Chunk; return srec_write_record (abfd, 0, (bfd_vma) 0, abfd->filename, abfd->filename + len); --- binutils-2.15/bfd/targets.c 2004-05-17 21:36:04.000000000 +0200 +++ binutils-2.15-nios2/bfd/targets.c 2005-05-17 12:20:13.000000000 +0200 @@ -559,6 +559,7 @@ extern const bfd_target bfd_elf32_nbigmi extern const bfd_target bfd_elf32_nlittlemips_vec; extern const bfd_target bfd_elf32_ntradbigmips_vec; extern const bfd_target bfd_elf32_ntradlittlemips_vec; +extern const bfd_target bfd_elf32_littlenios2_vec; extern const bfd_target bfd_elf32_openrisc_vec; extern const bfd_target bfd_elf32_or32_big_vec; extern const bfd_target bfd_elf32_pj_vec; @@ -746,6 +747,7 @@ extern const bfd_target sco5_core_vec; extern const bfd_target trad_core_vec; extern const bfd_target bfd_elf32_am33lin_vec; +extern const bfd_target bfd_elf32_littlenios2_vec; static const bfd_target * const _bfd_target_vector[] = { #ifdef SELECT_VECS @@ -854,6 +856,7 @@ static const bfd_target * const _bfd_tar &bfd_elf32_ntradbigmips_vec, &bfd_elf32_ntradlittlemips_vec, #endif + &bfd_elf32_littlenios2_vec, &bfd_elf32_openrisc_vec, &bfd_elf32_or32_big_vec, &bfd_elf32_pj_vec, --- binutils-2.15/binutils/nios2_binutils_xfail.lst 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/binutils/nios2_binutils_xfail.lst 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1 @@ +No xfails --- binutils-2.15/binutils/readelf.c 2004-05-17 21:35:52.000000000 +0200 +++ binutils-2.15-nios2/binutils/readelf.c 2005-05-17 12:20:13.000000000 +0200 @@ -110,6 +110,8 @@ #include "aout/ar.h" +#include "elf/nios2.h" + #include "bucomm.h" #include "getopt.h" #include "libiberty.h" @@ -668,6 +670,7 @@ guess_is_rela (unsigned long e_machine) case EM_XTENSA: case EM_XTENSA_OLD: case EM_M32R: + case EM_ALTERA_NIOS2: return TRUE; case EM_MMA: @@ -1166,6 +1169,10 @@ dump_relocations (FILE *file, case EM_XTENSA: rtype = elf_xtensa_reloc_type (type); break; + + case EM_ALTERA_NIOS2: + rtype = elf_nios2_reloc_type (type); + break; } if (rtype == NULL) @@ -1649,6 +1656,7 @@ get_machine_name (unsigned e_machine) case EM_IQ2000: return "Vitesse IQ2000"; case EM_XTENSA_OLD: case EM_XTENSA: return "Tensilica Xtensa Processor"; + case EM_ALTERA_NIOS2: return "Altera Nios II"; default: sprintf (buff, _(": %x"), e_machine); return buff; --- binutils-2.15/binutils/testsuite/binutils-all/bintest.s 1999-05-03 09:29:11.000000000 +0200 +++ binutils-2.15-nios2/binutils/testsuite/binutils-all/bintest.s 2005-05-17 12:20:13.000000000 +0200 @@ -1,5 +1,8 @@ .globl text_symbol .text + # this is needed to get the readelf -s, -S and -r tests to work + # with nios2 as it has relaxation on by default + .set norelax text_symbol: static_text_symbol: .long 1 --- binutils-2.15/binutils-2.15_copied 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/binutils-2.15_copied 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1 @@ +timestamp --- binutils-2.15/binutils-2.15_untarred 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/binutils-2.15_untarred 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1 @@ +timestamp --- binutils-2.15/configure 2004-05-17 21:36:20.000000000 +0200 +++ binutils-2.15-nios2/configure 2005-05-17 12:20:13.000000000 +0200 @@ -1434,6 +1434,10 @@ case "${target}" in mips*-*-*) noconfigdirs="$noconfigdirs gprof ${libgcj}" ;; + nios2-*-*) + skipdirs=`echo " ${skipdirs} " | sed -e 's/ gprof / /'` + noconfigdirs="$noconfigdirs" + ;; romp-*-*) noconfigdirs="$noconfigdirs bfd binutils ld gas opcodes target-libgloss ${libgcj}" ;; --- binutils-2.15/configure.in 2004-05-17 21:40:54.000000000 +0200 +++ binutils-2.15-nios2/configure.in 2005-05-17 12:20:13.000000000 +0200 @@ -18,6 +18,7 @@ ############################################################################## ### WARNING: this file contains embedded tabs. Do not run untabify on this file. + AC_INIT(move-if-change) AC_PREREQ(2.13) AC_CANONICAL_SYSTEM @@ -667,6 +668,10 @@ case "${target}" in mips*-*-*) noconfigdirs="$noconfigdirs gprof ${libgcj}" ;; + nios2-*-*) + skipdirs=`echo " ${skipdirs} " | sed -e 's/ gprof / /'` + noconfigdirs="$noconfigdirs" + ;; romp-*-*) noconfigdirs="$noconfigdirs bfd binutils ld gas opcodes target-libgloss ${libgcj}" ;; --- binutils-2.15/gas/Makefile.in 2004-05-17 21:36:07.000000000 +0200 +++ binutils-2.15-nios2/gas/Makefile.in 2005-05-17 12:20:13.000000000 +0200 @@ -299,6 +299,7 @@ CPU_TYPES = \ mn10200 \ mn10300 \ msp430 \ + nios2 \ ns32k \ openrisc \ or32 \ @@ -493,6 +494,7 @@ TARGET_CPU_CFILES = \ config/tc-mn10200.c \ config/tc-mn10300.c \ config/tc-msp430.c \ + config/tc-nios2.c \ config/tc-ns32k.c \ config/tc-openrisc.c \ config/tc-or32.c \ @@ -545,6 +547,7 @@ TARGET_CPU_HFILES = \ config/tc-mn10200.h \ config/tc-mn10300.h \ config/tc-msp430.h \ + config/tc-nios2.h \ config/tc-ns32k.h \ config/tc-openrisc.h \ config/tc-or32.h \ @@ -1171,6 +1174,13 @@ DEPTC_msp430_elf = $(INCDIR)/symcat.h $( subsegs.h $(INCDIR)/obstack.h $(INCDIR)/opcode/msp430.h \ $(INCDIR)/safe-ctype.h +DEPTC_nios2_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-nios2.h \ + subsegs.h $(INCDIR)/obstack.h $(INCDIR)/safe-ctype.h \ + $(INCDIR)/opcode/nios2.h itbl-ops.h dwarf2dbg.h $(INCDIR)/elf/nios2.h \ + $(INCDIR)/elf/reloc-macros.h + DEPTC_ns32k_aout = $(INCDIR)/symcat.h $(srcdir)/config/obj-aout.h \ $(srcdir)/config/tc-ns32k.h $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h \ $(INCDIR)/opcode/ns32k.h $(INCDIR)/obstack.h @@ -1824,6 +1834,12 @@ DEPOBJ_msp430_elf = $(INCDIR)/symcat.h $ $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ struc-symbol.h dwarf2dbg.h $(INCDIR)/aout/aout64.h +DEPOBJ_nios2_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-nios2.h \ + $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ + $(INCDIR)/elf/nios2.h $(INCDIR)/elf/reloc-macros.h + DEPOBJ_ns32k_aout = $(INCDIR)/symcat.h $(srcdir)/config/obj-aout.h \ $(srcdir)/config/tc-ns32k.h $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h \ $(INCDIR)/aout/aout64.h $(INCDIR)/obstack.h @@ -2349,6 +2365,10 @@ DEP_msp430_elf = $(srcdir)/config/obj-el $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-msp430.h +DEP_nios2_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-nios2.h + DEP_ns32k_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-ns32k.h \ $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h --- binutils-2.15/gas/config/obj-elf.c 2004-05-17 21:36:08.000000000 +0200 +++ binutils-2.15-nios2/gas/config/obj-elf.c 2005-05-17 12:20:13.000000000 +0200 @@ -53,6 +53,10 @@ #include "elf/i370.h" #endif +#ifdef TC_NIOS2 +#include "elf/nios2.h" +#endif + static void obj_elf_line (int); static void obj_elf_size (int); static void obj_elf_type (int); --- binutils-2.15/gas/config/tc-nios2.c 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/gas/config/tc-nios2.c 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,2996 @@ +/* tc-nios2.c -- assemble code for a New Jersey processor. + + Copyright (C) 2003 + by Nigel Gray (ngray@altera.com). + + + This file is part of GAS. + + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +#include +#include +#include +#include +#include "as.h" +#include "opcode/nios2.h" +#include "elf/nios2.h" +#include "tc-nios2.h" +#include "bfd.h" +#include "dwarf2dbg.h" +#include "subsegs.h" +#include "safe-ctype.h" + +#ifndef OBJ_ELF + /* we are not supporting any other target + so we throw a compile time error */ +OBJ_ELF not defined +#endif + typedef enum +{ + relax_section = 0, + relax_none, + relax_all +} +relax_optionT; + + +/* struct contains all assembler options set with .set */ +struct +{ + /* + .set noat -> noat = 1 allows assembly code to use at without warning + and macro expansions will generate a warning. + .set at -> noat = 0, assembly code using at will warn + macro expansions will not generate warnings + */ + bfd_boolean noat; + + /* + .set nobreak -> nobreak = 1 allows assembly code to use ba,bt without warning + .set break -> nobreak = 0, assembly code using ba,bt will warn + */ + bfd_boolean nobreak; + + /* + .cmd line option -relax-all allows all branches and calls to be replaced + with longer versions + -no-relax inhibits branch/call conversion + default value is relax_section, which relaxes branches within a section + */ + relax_optionT relax; + +} +nios2_as_options = +{ +FALSE, FALSE, relax_section}; + + +typedef struct nios2_insn_reloc +{ + /* any expression in the instruction is parsed into + this field which is passed to fix_new_exp() to + generate a fixup */ + expressionS reloc_expression; + + /* the type of the relocation to be applied */ + bfd_reloc_code_real_type reloc_type; + + /* pc relative */ + unsigned int reloc_pcrel; + + /* the next relocation to be applied to the instruction */ + struct nios2_insn_reloc *reloc_next; +} +nios2_insn_relocS; + + +/* ------------------------------------------------------------------ + This struct is used by the functions in tc-nios2.c to assemble an + instruction + ------------------------------------------------------------------*/ + +typedef struct nios2_insn_info +{ + /* assembled instruction */ + unsigned long insn_code; + /* ptr to the relevant bit of the opcode table */ + const struct nios2_opcode *insn_nios2_opcode; + /* after parsing ptrs to the tokens in the instruction fill this array + it is terminated with a null pointer ( hence the first +1 + The second +1 is because in some parts of the code the opcode + is not counted as a token, but still placed in this array*/ + const char *insn_tokens[NIOS2_MAX_INSN_TOKENS + 1 + 1]; + + /* this holds information used to generate fixups + and eventually relocations if it is not null */ + nios2_insn_relocS *insn_reloc; +} +nios2_insn_infoS; + + +/* + This struct associates an argument assemble function with + an argument syntax string. Used by the assembler to find out + how to parse and assemble a set of instruction operands and return the instruction + field values +*/ + +typedef struct nios2_arg_info +{ + const char *args; + void (*assemble_args_func) (nios2_insn_infoS * insn_info); +} +nios2_arg_infoS; + +/* + This struct is used to convert New Jersey pseudo-ops into the + corresponding real op + */ +typedef struct nios2_ps_insn_info +{ + const char *pseudo_insn; + const char *insn; + const char *arg_modifier; + void (*arg_modifer_func) (const char *arg, char **parsedArgs, int numArg, + int startIndex); + int num; + int index; +} +nios2_ps_insn_infoS; + + + +/* function prototypes */ +static void NIOS2_CHECK_ASSEMBLY (unsigned int opcode, + const char *exp_opcode); +static void s_nios2_sdata (int); +void nios2_assemble_args_dst (nios2_insn_infoS * insn_info); +void nios2_assemble_args_tsi (nios2_insn_infoS * insn_info); +void nios2_assemble_args_tsu (nios2_insn_infoS * insn_info); +void nios2_assemble_args_o (nios2_insn_infoS * insn_info); +void nios2_assemble_args_m (nios2_insn_infoS * insn_info); +void nios2_assemble_args_s (nios2_insn_infoS * insn_info); +void nios2_assemble_args_tis (nios2_insn_infoS * insn_info); +void nios2_assemble_args_dc (nios2_insn_infoS * insn_info); +void nios2_assemble_args_cs (nios2_insn_infoS * insn_info); +void nios2_assemble_args_ldst (nios2_insn_infoS * insn_info); +void nios2_assemble_args_none (nios2_insn_infoS * insn_info); +void nios2_assemble_args_dsj (nios2_insn_infoS * insn_info); +void nios2_assemble_args_is (nios2_insn_infoS * insn_info); +void nios2_assemble_args_sto (nios2_insn_infoS * insn_info); +void nios2_assemble_args_d (nios2_insn_infoS * insn_info); +void nios2_assemble_args_b (nios2_insn_infoS * insn_info); + +nios2_insn_relocS *nios2_insn_reloc_new (bfd_reloc_code_real_type reloc_type, + unsigned int pcrel); +void nios2_insn_reloc_destroy (nios2_insn_relocS * reloc); +unsigned long nios2_assemble_expression (const char *exprstr, + nios2_insn_infoS * insn, + nios2_insn_relocS * prev_reloc, + bfd_reloc_code_real_type reloc_type, + unsigned int pcrel); +char *nios2_consume_separator (char *argStr, const char *separator); +char *nios2_consume_arg (char *argStr, const char *argType); +void nios2_parse_args (char *argStr, const char *parseStr, char **parsedArgs); + +void nios2_modify_arg (const char *modifier, char **parsedArgs, int unused, + int index); +void nios2_append_arg (const char *append, char **parsedArgs, int numAppend, + int startIndex); +void nios2_insert_arg (const char *insert, char **parsedArgs, int numInsert, + int startIndex); +void nios2_swap_args (const char *unused, char **parsedArgs, int index_1, + int index_2); +void nios2_negate_arg (const char *modifier ATTRIBUTE_UNUSED, + char **parsedArgs, int unused ATTRIBUTE_UNUSED, + int index); +void nios2_translate_pseudo_insn (nios2_insn_infoS * insn); +valueT md_chars_to_number (char *buf, int n); +void md_number_to_imm (char *buf, valueT val, int n); +void md_number_to_disp (char *buf, valueT val, int n); +void md_number_to_field (char *buf, valueT val, int n); +static void nios2_align (int log_size, const char *pfill, symbolS * sym); +static void s_nios2_ucons (int nbytes); +static void s_nios2_set (int equiv); +static void s_nios2_align (int ignore); +static void s_nios2_text (int); +static void s_nios2_data (int); +static void s_nios2_section (int); +static bfd_boolean nios2_coproc_reg (const char *reg_name); +static void output_insn (void); +static void output_ubranch (void); +static void output_cbranch (void); +static void output_call (void); +static void output_movia (void); + + +bfd_boolean nios2_check_overflow (valueT fixup, reloc_howto_type * howto); + +/* The known current alignment of the current section. */ +static int nios2_current_align; +static segT nios2_current_align_seg; + +/* The last seen label in the current section. This is used to auto-align + labels preceeding instructions. */ +static symbolS *nios2_last_label; + + +static int nios2_auto_align_on = 1; + +/* 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[] = "#"; + +/* 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 C style comments are always supported. */ +const char line_comment_chars[] = "#"; + +/* This array holds machine specific line separator characters. */ +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. + */ + +/* handle of the OPCODE hash table */ +static struct hash_control *nios2_opcode_hash = NULL; + +/* handle of the Register hash table */ +static struct hash_control *nios2_reg_hash = NULL; + +/* handle of the parse args hash table */ +static struct hash_control *nios2_arg_hash = NULL; + +/* pseudo-op hash table */ +static struct hash_control *nios2_ps_hash = NULL; + +/* mode of the assembler */ +typedef enum +{ + NIOS2_MODE_ASSEMBLE, // ordinary operation + NIOS2_MODE_TEST // hidden mode used for self testing +} +NIOS2_MODE; + +static NIOS2_MODE nios2_mode = NIOS2_MODE_ASSEMBLE; + +/* this function is used to in self-checking mode + to check the assembled instruction + opcode should be the assembled opcode, and exp_opcode + the parsed string representing the expected opcode */ +void +NIOS2_CHECK_ASSEMBLY (unsigned int opcode, const char *exp_opcode) +{ + if (nios2_mode == NIOS2_MODE_TEST) + { + if ((exp_opcode) == NULL) + { + as_bad (_("expecting opcode string in self test mode")); + } + else if ((opcode) != strtoul ((exp_opcode), NULL, 16)) + { + as_bad (_("assembly 0x%08x, expected %s"), (opcode), (exp_opcode)); + } + } +} + +/* Machine-dependent command-line options */ + +const char *md_shortopts = "r"; + +struct option md_longopts[] = { +#define OPTION_RELAX_ALL (OPTION_MD_BASE + 0) + {"relax-all", no_argument, NULL, OPTION_RELAX_ALL}, +#define OPTION_NORELAX (OPTION_MD_BASE + 1) + {"no-relax", no_argument, NULL, OPTION_NORELAX}, +#define OPTION_RELAX_SECTION (OPTION_MD_BASE + 2) + {"relax-section", no_argument, NULL, OPTION_RELAX_SECTION} +}; + +size_t md_longopts_size = sizeof (md_longopts); + +/* Machine dependent pseudo-ops + These are actually assembler directives + format of each entry is + + { "directive", handler_func, param } +*/ +const pseudo_typeS md_pseudo_table[] = { + {"align", s_nios2_align, 0}, + {"text", s_nios2_text, 0}, + {"data", s_nios2_data, 0}, + {"section", s_nios2_section, 0}, + {"section.s", s_nios2_section, 0}, + {"sect", s_nios2_section, 0}, + {"sect.s", s_nios2_section, 0}, + /* .dword and .half are included for + compatibility with MIPS */ + {"dword", cons, 8}, + {"half", cons, 2}, + /* NIOS2 native word size is 4 bytes, so we override + the GAS default of 2 */ + {"word", cons, 4}, + /* explicitly unaligned directives */ + {"2byte", s_nios2_ucons, 2}, + {"4byte", s_nios2_ucons, 4}, + {"8byte", s_nios2_ucons, 8}, + {"16byte", s_nios2_ucons, 16}, +#ifdef OBJ_ELF + {"sdata", s_nios2_sdata, 0}, +#endif + {"set", s_nios2_set, 0}, + {NULL, NULL, 0} +}; + +#define BYTE_F 32764 +#define BYTE_B -32768 +#define ABS (long)0xffffffff /* special value to indicate non-pc relative jmp */ + +#define UBRANCH 1 +#define UJMP 2 +#define CBRANCH 3 +#define CJMP 4 + + +#define RELAX_MAX_SIZE(type) nios2_relax_table[nios2_relax_table[type].rlx_more].rlx_length +#define RELAX_SIZE(type) nios2_relax_table[type].rlx_length +#define RELAX_SUBSTATE(type) type + +/* machine dependent relaxations */ +struct relax_type nios2_relax_table[] = { + /* first entry unused (ends relaxation sequence) */ + {1, 1, 0, 0}, + /* unconditional branch */ + {BYTE_F, BYTE_B, 4, 2}, /* br label (label is in range) */ + /* unconditional jmp */ + {ABS, ABS, 12, 0}, /* movhi at, %hi(label) ; ori at, %lo(label) ; jmp at */ + /* conditional branch */ + {BYTE_F, BYTE_B, 4, 4}, /* br{cond} label (label is in range) */ + /* conditional jmp */ + {ABS, ABS, 16, 0}, /* br{opp_cond} skip ; movhi at, %hi(label) ; ori at, %lo(label) ; jmp at ; skip: } */ +}; + + +/* this is just the generic relax_frag function but + amended to include absolute jmps in the relax table + */ + +long +nios2_relax_frag (segT segment, fragS * fragP, long stretch) +{ + const relax_typeS *this_type; + const relax_typeS *start_type; + relax_substateT next_state; + relax_substateT this_state; + long growth; + offsetT aim; + addressT target; + addressT address; + symbolS *symbolP; + const relax_typeS *table; + + target = fragP->fr_offset; + address = fragP->fr_address; + table = nios2_relax_table; + this_state = fragP->fr_subtype; + start_type = this_type = table + this_state; + symbolP = fragP->fr_symbol; + + if (symbolP) + { + fragS *sym_frag; + + sym_frag = symbol_get_frag (symbolP); + +#ifndef DIFF_EXPR_OK +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (S_GET_SEGMENT (symbolP) == SEG_DATA) + || (S_GET_SEGMENT (symbolP) == SEG_BSS) + || (S_GET_SEGMENT (symbolP) == SEG_TEXT)); +#endif + know (sym_frag != NULL); +#endif + know (!(S_GET_SEGMENT (symbolP) == absolute_section) + || sym_frag == &zero_address_frag); + target += S_GET_VALUE (symbolP); + + /* If frag has yet to be reached on this pass, + assume it will move by STRETCH just as we did. + If this is not so, it will be because some frag + between grows, and that will force another pass. */ + + if (stretch != 0 + && sym_frag->relax_marker != fragP->relax_marker + && S_GET_SEGMENT (symbolP) == segment) + { + target += stretch; + } + } + + + /* NG we subtract 4 because all pc relative branches are + from the next instruction */ + aim = target - address - fragP->fr_fix - 4; + + if (aim < 0) + { + /* Look backwards. */ + for (next_state = this_type->rlx_more; next_state;) + { + if (aim >= this_type->rlx_backward + || this_type->rlx_backward == ABS) + next_state = 0; + else + { + /* Grow to next state. */ + this_state = next_state; + this_type = table + this_state; + next_state = this_type->rlx_more; + } + } + } + else + { + /* Look forwards. */ + + for (next_state = this_type->rlx_more; next_state;) + { + if (aim <= this_type->rlx_forward || this_type->rlx_forward == ABS) + next_state = 0; + else + { + /* Grow to next state. */ + this_state = next_state; + this_type = table + this_state; + next_state = this_type->rlx_more; + } + } + } + + + growth = this_type->rlx_length - start_type->rlx_length; + + if (growth != 0) + fragP->fr_subtype = this_state; + + return growth; +} + +/*-------------------------------------------------------------------------------- + The next table associates pointers to functions which parse the arguments to an + instruction and fill in the relevant fields of the instruction + --------------------------------------------------------------------------------*/ + +const nios2_arg_infoS nios2_arg_info_structs[] = { + /* args assemble_args_func */ + {"d,s,t", nios2_assemble_args_dst}, + {"d,s,t,E", nios2_assemble_args_dst}, + {"t,s,i", nios2_assemble_args_tsi}, + {"t,s,i,E", nios2_assemble_args_tsi}, + {"t,s,u", nios2_assemble_args_tsu}, + {"t,s,u,E", nios2_assemble_args_tsu}, + {"s,t,o", nios2_assemble_args_sto}, + {"s,t,o,E", nios2_assemble_args_sto}, + {"o", nios2_assemble_args_o}, + {"o,E", nios2_assemble_args_o}, + {"s", nios2_assemble_args_s}, + {"s,E", nios2_assemble_args_s}, + {"", nios2_assemble_args_none}, + {"E", nios2_assemble_args_none}, + {"i(s)", nios2_assemble_args_is}, + {"i(s)E", nios2_assemble_args_is}, + {"m", nios2_assemble_args_m}, + {"m,E", nios2_assemble_args_m}, + {"t,i(s)", nios2_assemble_args_tis}, + {"t,i(s)E", nios2_assemble_args_tis}, + {"d,c", nios2_assemble_args_dc}, + {"d,c,E", nios2_assemble_args_dc}, + {"c,s", nios2_assemble_args_cs}, + {"c,s,E", nios2_assemble_args_cs}, + {"l,d,s,t", nios2_assemble_args_ldst}, + {"l,d,s,t,E", nios2_assemble_args_ldst}, + {"d,s,j", nios2_assemble_args_dsj}, + {"d,s,j,E", nios2_assemble_args_dsj}, + {"d", nios2_assemble_args_d}, + {"d,E", nios2_assemble_args_d}, + {"b", nios2_assemble_args_b}, + {"b,E", nios2_assemble_args_b} +}; + +#define NIOS2_NUM_ARGS \ + ((sizeof(nios2_arg_info_structs)/sizeof(nios2_arg_info_structs[0]))) +const int nios2_num_arg_info_structs = NIOS2_NUM_ARGS; + + +const nios2_ps_insn_infoS nios2_ps_insn_info_structs[] = { + /* pseudo-op real-op arg arg_modifier_func num index */ + {"mov", "add", "zero", nios2_append_arg, 1, 3}, + {"movi", "addi", "zero", nios2_insert_arg, 1, 2}, + {"movhi", "orhi", "zero", nios2_insert_arg, 1, 2}, + {"movui", "ori", "zero", nios2_insert_arg, 1, 2}, + {"movia", "orhi", "zero", nios2_insert_arg, 1, 2}, + {"nop", "add", "zero", nios2_append_arg, 3, 1}, + {"bgt", "blt", "", nios2_swap_args, 1, 2}, + {"bgtu", "bltu", "", nios2_swap_args, 1, 2}, + {"ble", "bge", "", nios2_swap_args, 1, 2}, + {"bleu", "bgeu", "", nios2_swap_args, 1, 2}, + {"cmpgt", "cmplt", "", nios2_swap_args, 2, 3}, + {"cmpgtu", "cmpltu", "", nios2_swap_args, 2, 3}, + {"cmple", "cmpge", "", nios2_swap_args, 2, 3}, + {"cmpleu", "cmpgeu", "", nios2_swap_args, 2, 3}, + {"cmpgti", "cmpgei", "+1", nios2_modify_arg, 0, 3}, + {"cmpgtui", "cmpgeui", "+1", nios2_modify_arg, 0, 3}, + {"cmplei", "cmplti", "+1", nios2_modify_arg, 0, 3}, + {"cmpleui", "cmpltui", "+1", nios2_modify_arg, 0, 3}, + {"subi", "addi", "", nios2_negate_arg, 0, 3} + /* add further pseudo-ops here */ +}; + +#define NIOS2_NUM_PSEUDO_INSNS \ + ((sizeof(nios2_ps_insn_info_structs)/sizeof(nios2_ps_insn_info_structs[0]))) +const int nios2_num_ps_insn_info_structs = NIOS2_NUM_PSEUDO_INSNS; + +/* special relocation directive strings */ + +struct nios2_special_relocS +{ + const char *string; + bfd_reloc_code_real_type reloc_type; +}; + +struct nios2_special_relocS nios2_special_reloc[] = { + {"%hiadj", BFD_RELOC_NIOS2_HIADJ16}, + {"%hi", BFD_RELOC_NIOS2_HI16}, + {"%lo", BFD_RELOC_NIOS2_LO16}, + {"%gprel", BFD_RELOC_NIOS2_GPREL} +}; + +#define NIOS2_NUM_SPECIAL_RELOCS \ + (sizeof(nios2_special_reloc)/sizeof(nios2_special_reloc[0])) +const int nios2_num_special_relocs = NIOS2_NUM_SPECIAL_RELOCS; + +/* + The function nios2_modify_arg appends the string modifier to the string contained + in the argument at index in the array parsedArgs[] +*/ +void +nios2_modify_arg (const char *modifier, + char **parsedArgs, int unused ATTRIBUTE_UNUSED, int index) +{ + assert (index < NIOS2_MAX_INSN_TOKENS); + +/* + we can't just strcat here because strcat will free the memory pointed to by the first + argument and allocate new memory - but at this stage, parsedArgs[index] may point into + the middle of a block of allocated memory, so trying to free it will cause a seg fault. + + */ + char *tmp = parsedArgs[index]; + parsedArgs[index] = + (char *) malloc (strlen (parsedArgs[index]) + strlen (modifier) + 1); + strcpy (parsedArgs[index], tmp); + strcat (parsedArgs[index], modifier); +} + + +void +nios2_negate_arg (const char *modifier ATTRIBUTE_UNUSED, + char **parsedArgs, int unused ATTRIBUTE_UNUSED, int index) +{ + char *tmp = parsedArgs[index]; + parsedArgs[index] = + (char *) malloc (strlen ("~(") + strlen (parsedArgs[index]) + + strlen (")+1") + 1); + + strcpy (parsedArgs[index], "~("); + strcat (parsedArgs[index], tmp); + strcat (parsedArgs[index], ")+1"); +} + +/* + The function nios2_swap_args swaps the pointers at indices index_1 and + index_2 in the array parsedArgs[] - this is used for operand swapping + for comparison operations + */ +void +nios2_swap_args (const char *unused ATTRIBUTE_UNUSED, + char **parsedArgs, int index_1, int index_2) +{ + char *tmp; + assert (index_1 < NIOS2_MAX_INSN_TOKENS && index_2 < NIOS2_MAX_INSN_TOKENS); + tmp = parsedArgs[index_1]; + parsedArgs[index_1] = parsedArgs[index_2]; + parsedArgs[index_2] = tmp; +} + +/* + This function appends the string append to the array of strings in + parsedArgs numAppend times starting at index startIndex in the array +*/ +void +nios2_append_arg (const char *append, char **parsedArgs, int numAppend, + int startIndex) +{ + int i, count; + char *tmp; + + assert ((startIndex + numAppend) < NIOS2_MAX_INSN_TOKENS); + i = startIndex; + count = numAppend; + + if (nios2_mode == NIOS2_MODE_TEST) + tmp = parsedArgs[startIndex]; + else + tmp = NULL; + + while (count > 0) + { + parsedArgs[i] = (char *) append; + ++i; + --count; + } + + assert (i == (startIndex + numAppend)); + parsedArgs[i] = tmp; + parsedArgs[i + 1] = NULL; +} + +/* This function inserts the string insert numInsert times in the array parsedArgs, + starting at the index startIndex + */ +void +nios2_insert_arg (const char *insert, char **parsedArgs, int numInsert, + int startIndex) +{ + int i, count, from, to; + + assert ((startIndex + numInsert) < NIOS2_MAX_INSN_TOKENS); + + to = startIndex + numInsert; + from = startIndex; + + /* move the existing arguments up to create space */ + i = NIOS2_MAX_INSN_TOKENS; + while ((i - numInsert) >= startIndex) + { + parsedArgs[i] = parsedArgs[i - numInsert]; + --i; + } + + i = startIndex; + count = numInsert; + while (count > 0) + { + parsedArgs[i] = (char *) insert; + ++i; + --count; + } +} + +/* + This function swaps the pseudo-op for a real op + FIXME - only works for 1-to-1 correspondence + */ +void +nios2_translate_pseudo_insn (nios2_insn_infoS * insn) +{ + + nios2_ps_insn_infoS *ps_insn; + + /* find which real insn the pseudo-op transates to and + switch the insn_info ptr to point to it */ + ps_insn = + (nios2_ps_insn_infoS *) hash_find (nios2_ps_hash, + insn->insn_nios2_opcode->name); + + if (ps_insn != NULL) + { + insn->insn_nios2_opcode = + (struct nios2_opcode *) hash_find (nios2_opcode_hash, ps_insn->insn); + insn->insn_tokens[0] = insn->insn_nios2_opcode->name; + // modify the args so they work with the real insn + ps_insn->arg_modifer_func (ps_insn->arg_modifier, + (char **) insn->insn_tokens, ps_insn->num, + ps_insn->index); + } + else + { + // we cannot recover from this + as_fatal (_("unrecognized pseudo-instruction %s"), + ps_insn->pseudo_insn); + } +} + +/******************************************************************** + The following functions are called by machine-independent parts of + the assembler + ********************************************************************/ + +/* + Function : void md_parse_option + (char** option_ptr, int* argc_ptr, char*** argv_ptr) + + Description : + + */ +int +md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) +{ + switch (c) + { + case 'r': + /* hidden option for self-test mode */ + nios2_mode = NIOS2_MODE_TEST; + break; + case OPTION_RELAX_ALL: + nios2_as_options.relax = relax_all; + break; + case OPTION_NORELAX: + nios2_as_options.relax = relax_none; + break; + case OPTION_RELAX_SECTION: + nios2_as_options.relax = relax_section; + break; + default: + return 0; + break; + } + + return 1; +} + +/* + Function : md_show_usage(FILE* stream) + + Description : machine-dependent usage message +*/ +void +md_show_usage (FILE * stream) +{ + fprintf (stream, "\ + NIOS2 options:\n\ + -relax-all replace all branch and call instructions with jmp and callr sequences\n\ + -relax-section replace identified out of range branches with jmp sequences (default)\n\ + -no-relax do not replace any branches or calls\n"); +} + +/* + Function : void md_begin() + + Description : + 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 () +{ + int i; + const char *inserted; + + /* create and fill a hashtable for the New Jersey opcodes, registers and arguments */ + nios2_opcode_hash = hash_new (); + nios2_reg_hash = hash_new (); + nios2_arg_hash = hash_new (); + nios2_ps_hash = hash_new (); + + for (i = 0; i < NUMOPCODES; ++i) + { + inserted = + hash_insert (nios2_opcode_hash, nios2_opcodes[i].name, + (PTR) & nios2_opcodes[i]); + if (inserted != NULL) + { + fprintf (stderr, _("internal error: can't hash `%s': %s\n"), + nios2_opcodes[i].name, inserted); + /* Probably a memory allocation problem? Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + } + + for (i = 0; i < nios2_num_regs; ++i) + { + inserted = + hash_insert (nios2_reg_hash, nios2_regs[i].name, + (PTR) & nios2_regs[i]); + if (inserted != NULL) + { + fprintf (stderr, _("internal error: can't hash `%s': %s\n"), + nios2_regs[i].name, inserted); + /* Probably a memory allocation problem? Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + + } + + for (i = 0; i < nios2_num_arg_info_structs; ++i) + { + inserted = + hash_insert (nios2_arg_hash, nios2_arg_info_structs[i].args, + (PTR) & nios2_arg_info_structs[i]); + if (inserted != NULL) + { + fprintf (stderr, _("internal error: can't hash `%s': %s\n"), + nios2_arg_info_structs[i].args, inserted); + /* Probably a memory allocation problem? Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + } + + for (i = 0; i < nios2_num_ps_insn_info_structs; ++i) + { + inserted = + hash_insert (nios2_ps_hash, nios2_ps_insn_info_structs[i].pseudo_insn, + (PTR) & nios2_ps_insn_info_structs[i]); + if (inserted != NULL) + { + fprintf (stderr, _("internal error: can't hash `%s': %s\n"), + nios2_ps_insn_info_structs[i].pseudo_insn, inserted); + /* Probably a memory allocation problem? Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + } + + /* assembler option defaults */ + nios2_as_options.noat = FALSE; + nios2_as_options.nobreak = FALSE; + + /* debug information is incompatible with relaxation */ + if (debug_type != DEBUG_UNSPECIFIED) + { + nios2_as_options.relax = relax_none; + } + + /* initialize the alignment data */ + nios2_current_align_seg = now_seg; + nios2_last_label = NULL; + nios2_current_align = 0; +} + + + + +/* made this global to avoid changing one function prototype */ +nios2_insn_infoS insn; + +/* + Function: void md_assemble(char* op_str) + + Description: assembles a single line of Nios II assembly + language + */ +void +md_assemble (char *op_str) +{ + char *argstr; + char *op_strdup; + nios2_arg_infoS *arg_info; + unsigned long saved_pinfo = 0; + + /* make sure we are aligned on a 4-byte boundary */ + if (nios2_current_align < 2) + nios2_align (2, NULL, nios2_last_label); + else if (nios2_current_align > 2) + nios2_current_align = 2; + nios2_last_label = NULL; + + + /* we don't want to clobber to op_str + because we want to be able to use it in messages */ + op_strdup = strdup (op_str); + + insn.insn_tokens[0] = strtok (op_strdup, " "); + argstr = strtok (NULL, ""); + + /* assemble the opcode */ + insn.insn_nios2_opcode = + (struct nios2_opcode *) hash_find (nios2_opcode_hash, + insn.insn_tokens[0]); + insn.insn_reloc = NULL; + + if (insn.insn_nios2_opcode != NULL) + { + /* set the opcode for the instruction */ + insn.insn_code = insn.insn_nios2_opcode->match; + + /* parse the arguments pointed to by argstr */ + if (nios2_mode == NIOS2_MODE_ASSEMBLE) + { + nios2_parse_args (argstr, insn.insn_nios2_opcode->args, + (char **) &insn.insn_tokens[1]); + } + else + { + nios2_parse_args (argstr, insn.insn_nios2_opcode->args_test, + (char **) &insn.insn_tokens[1]); + } + + /* we need to preserve the MOVIA macro as this is clobbered by translate_pseudo_insn */ + if (insn.insn_nios2_opcode->pinfo == NIOS2_INSN_MACRO_MOVIA) + { + saved_pinfo = NIOS2_INSN_MACRO_MOVIA; + } + /* if the instruction is an pseudo-instruction, we want to replace it with its + real equivalent, and then continue */ + if ((insn.insn_nios2_opcode->pinfo & NIOS2_INSN_MACRO) == + NIOS2_INSN_MACRO) + { + nios2_translate_pseudo_insn (&insn); + } + + /* find the assemble function, and call it */ + arg_info = + (nios2_arg_infoS *) hash_find (nios2_arg_hash, + insn.insn_nios2_opcode->args); + if (arg_info != NULL) + { + arg_info->assemble_args_func (&insn); + + if (nios2_as_options.relax != relax_none + && insn.insn_nios2_opcode->pinfo & NIOS2_INSN_UBRANCH) + output_ubranch (); + else if (nios2_as_options.relax != relax_none + && insn.insn_nios2_opcode->pinfo & NIOS2_INSN_CBRANCH) + output_cbranch (); + else if (nios2_as_options.relax == relax_all + && insn.insn_nios2_opcode->pinfo & NIOS2_INSN_CALL) + output_call (); + else if (saved_pinfo == NIOS2_INSN_MACRO_MOVIA) + output_movia (); + else + output_insn (); + } + else + { + /* the assembler is broken */ + fprintf (stderr, + _("internal error: %s is not a valid argument syntax\n"), + insn.insn_nios2_opcode->args); + /* Probably a memory allocation problem? Give up now. */ + as_fatal (_("Broken assembler. No assembly attempted.")); + } + } + else + { + /* unrecognised instruction - error */ + as_bad (_("unrecognised instruction %s"), insn.insn_tokens[0]); + } +} + +/* output a normal instruction */ +static void +output_insn () +{ + char *f; + nios2_insn_relocS *reloc; + + f = frag_more (4); + /* this allocates enough space for the instruction + and puts it in the current frag */ + md_number_to_chars (f, insn.insn_code, 4); + /* emit debug info */ + dwarf2_emit_insn (4); + /* create any fixups */ + reloc = insn.insn_reloc; + while (reloc != NULL) + { + /* this creates any fixups to be acted on later */ + fix_new_exp (frag_now, f - frag_now->fr_literal, 4, + &reloc->reloc_expression, reloc->reloc_pcrel, + reloc->reloc_type); + reloc = reloc->reloc_next; + } +} + +/* output an unconditional branch */ +static void +output_ubranch () +{ + char *f; + nios2_insn_relocS *reloc; + symbolS *symp; + offsetT offset; + + reloc = insn.insn_reloc; + + /* if the reloc is NULL, there was an error assembling the branch */ + if (reloc != NULL) + { + + symp = reloc->reloc_expression.X_add_symbol; + offset = reloc->reloc_expression.X_add_number; + + /* we must tag debug info here since we can't do it after + calling frag_var */ + dwarf2_emit_insn (4); + + /* we create a machine dependent frag which can grow + to accommodate the largest possible instruction sequence + this may generate */ + f = frag_var (rs_machine_dependent, + RELAX_MAX_SIZE (UBRANCH), + RELAX_SIZE (UBRANCH), + RELAX_SUBSTATE (UBRANCH), symp, offset, NULL); + + md_number_to_chars (f, insn.insn_code, 4); + + /* we leave fixup generation to md_convert_frag */ + } +} + +/* output a conditional branch */ +static void +output_cbranch () +{ + char *f; + nios2_insn_relocS *reloc; + symbolS *symp; + offsetT offset; + + reloc = insn.insn_reloc; + + /* if the reloc is NULL, there was an error assembling the branch */ + if (reloc != NULL) + { + + symp = reloc->reloc_expression.X_add_symbol; + offset = reloc->reloc_expression.X_add_number; + + /* we must tag debug info here since we can't do it after + calling frag_var */ + dwarf2_emit_insn (4); + + /* we create a machine dependent frag which can grow + to accommodate the largest possible instruction sequence + this may generate */ + f = frag_var (rs_machine_dependent, + RELAX_MAX_SIZE (CBRANCH), + RELAX_SIZE (CBRANCH), + RELAX_SUBSTATE (CBRANCH), symp, offset, NULL); + + md_number_to_chars (f, insn.insn_code, 4); + + + /* we leave fixup generation to md_convert_frag */ + } +} + +/* Output a call sequence. Since calls are not pc-relative for NIOS2, + but are page-relative, we cannot tell at any stage in assembly + whether a call will be out of range since a section may be linked + at any address. So if we are relaxing, we convert all call instructions + to long call sequences, and rely on the linker to relax them back to + short calls */ +static void +output_call () +{ + char *f; + nios2_insn_relocS *reloc; + f = frag_more (12); + /* this allocates enough space for the instruction + and puts it in the current frag */ + reloc = insn.insn_reloc; + + /* if the reloc is NULL, there was an error assembling the branch */ + if (reloc != NULL) + { + md_number_to_chars (f, OP_MATCH_ORHI | 0x00400000, 4); + dwarf2_emit_insn (4); + md_number_to_chars (f + 4, OP_MATCH_ORI | 0x08400000, 4); + dwarf2_emit_insn (4); + md_number_to_chars (f + 8, OP_MATCH_CALLR | 0x08000000, 4); + dwarf2_emit_insn (4); + fix_new (frag_now, f - frag_now->fr_literal, 4, + reloc->reloc_expression.X_add_symbol, + reloc->reloc_expression.X_add_number, 0, + BFD_RELOC_NIOS2_CALLR); + + + } +} + +/* output a movhi/addi pair for the movia pseudo-op */ +static void +output_movia () +{ + char *f; + nios2_insn_relocS *reloc; + f = frag_more (8); + unsigned long reg_index = GET_INSN_FIELD (IRT, insn.insn_code); + + /* this allocates enough space for the instruction + and puts it in the current frag */ + reloc = insn.insn_reloc; + + /* if the reloc is NULL, there was an error assembling the movia */ + if (reloc != NULL) + { + md_number_to_chars (f, insn.insn_code, 4); + dwarf2_emit_insn (4); + md_number_to_chars (f + 4, + OP_MATCH_ADDI | (reg_index << OP_SH_IRT) | + (reg_index << OP_SH_IRS), 4); + dwarf2_emit_insn (4); + fix_new (frag_now, f - frag_now->fr_literal, 4, + reloc->reloc_expression.X_add_symbol, + reloc->reloc_expression.X_add_number, 0, + BFD_RELOC_NIOS2_HIADJ16); + fix_new (frag_now, f + 4 - frag_now->fr_literal, 4, + reloc->reloc_expression.X_add_symbol, + reloc->reloc_expression.X_add_number, 0, BFD_RELOC_NIOS2_LO16); + + } +} + +/* + Function md_chars_to_number takes the sequence of + bytes in bug and returns the corresponding value + in an int. n must be 1, 2 or 4. + */ +valueT +md_chars_to_number (char *buf, int n) +{ + // this assumes little endian format + int i; + valueT val; + + assert (n == 1 || n == 2 || n == 4); + + val = 0; + for (i = 0; i < n; ++i) + { + val = val | ((buf[i] & 0xff) << 8 * i); + } + return val; +} + + +/* + Function : void md_number_to_chars(char *buf, valueT val, int n) + + Description : this function turns a C long int, short int or char + into the series of bytes that represent the number + on the target machine + */ +void +md_number_to_chars (char *buf, valueT val, int n) +{ + /* this assumes little endian format */ + int i; + assert (n == 1 || n == 2 || n == 4); + for (i = 0; i < n; ++i) + { + buf[i] = val & 0xFF; + val >>= 8; + } +} + +/* + Function : void md_number_to_imm(char *buf, valueT val, int n) + + Description : this function is identical to md_number_to_chars + */ +void +md_number_to_imm (char *buf, valueT val, int n) +{ + md_number_to_chars (buf, val, n); +} + +/* + Function : void md_number_to_disp(char *buf, valueT val, int n) + + Description : this function is identical to md_number_to_chars + */ +void +md_number_to_disp (char *buf, valueT val, int n) +{ + md_number_to_chars (buf, val, n); +} + +/* + Function : void md_number_to_field(char *buf, valueT val, int n) + + Description : this function is identical to md_number_to_chars + */ +void +md_number_to_field (char *buf, valueT val, int n) +{ + md_number_to_chars (buf, val, n); +} + +/* + + Function : char * md_atof(int type, char *litP,int *sizeP) + + Description : + 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 (int type, char *litP, int *sizeP) +{ + int prec; + LITTLENUM_TYPE words[4]; + char *t; + int i; + + switch (type) + { + case 'f': + prec = 2; + break; + case 'd': + prec = 4; + 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 * 2; + + /* little endian target */ + for (i = prec - 1; i >= 0; i--) + { + md_number_to_chars (litP, (valueT) words[i], 2); + litP += 2; + } + + return NULL; +} + + + +int md_short_jump_size; +int md_long_jump_size; + +void +md_create_short_jump (char *result_ptr ATTRIBUTE_UNUSED, + addressT from_addr ATTRIBUTE_UNUSED, + addressT to_addr ATTRIBUTE_UNUSED, + fragS * frag ATTRIBUTE_UNUSED, + symbolS * to_symbol ATTRIBUTE_UNUSED) +{ + abort (); +} + +void +md_create_long_jump (char *ptr ATTRIBUTE_UNUSED, + addressT from_addr ATTRIBUTE_UNUSED, + addressT to_addr ATTRIBUTE_UNUSED, + fragS * frag ATTRIBUTE_UNUSED, + symbolS * to_symbol ATTRIBUTE_UNUSED) +{ + abort (); +} + +int +md_estimate_size_before_relax (fragS * fragp, segT segment ATTRIBUTE_UNUSED) +{ + /* we only support ELF targets */ + + switch (nios2_as_options.relax) + { + case relax_none: + case relax_section: + break; + case relax_all: + /* The NIOS2 linker performs relaxation so the assembler + always assumes the worst case, so that the linker can + replace with a better case if possible - this way, linker + relaxation can never cause a short branch to be out of range + */ + while (nios2_relax_table[fragp->fr_subtype].rlx_more != 0) + fragp->fr_subtype = nios2_relax_table[fragp->fr_subtype].rlx_more; + break; + default: + abort (); + break; + } + + /* return the estimated size of the frag */ + return nios2_relax_table[fragp->fr_subtype].rlx_length; +} + + +void +md_convert_frag (bfd * headers ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED, + fragS * fragp) +{ + unsigned char *buffer = fragp->fr_literal + fragp->fr_fix; + relax_substateT subtype = fragp->fr_subtype; + unsigned int growth = RELAX_SIZE (subtype); + unsigned int br_opcode, br_op_a, br_op_b; + + switch (subtype) + { + case UBRANCH: + /* we just need to generate the fixup for the symbol and offset */ + fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset, 1, + BFD_RELOC_16_PCREL); + break; + case UJMP: + /* replace ubranch at fr_fix with : + movhi at, %hi(symbol+offset) + ori at, %lo(symbol+offset) + jmp at + */ + md_number_to_chars (buffer, OP_MATCH_ORHI | 0x00400000, 4); + md_number_to_chars (buffer + 4, OP_MATCH_ORI | 0x08400000, 4); + md_number_to_chars (buffer + 8, OP_MATCH_JMP | 0x08000000, 4); + fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset, 0, + BFD_RELOC_NIOS2_UJMP); + break; + case CBRANCH: + /* we just need to generate the fixup for the symbol and offset */ + fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset, 1, + BFD_RELOC_16_PCREL); + break; + case CJMP: + /* replace cbranch at fr_fix with : + b(opposite condition) r, s, skip + movhi at, %hi(symbol+offset) + ori at, %lo(symbol+offset) + jmp at + skip: + ... + */ + br_opcode = md_chars_to_number (buffer, 4); + + switch (br_opcode & OP_MASK_OP) + { + case OP_MATCH_BEQ: + br_opcode = + (br_opcode & ~OP_MASK_OP) | OP_MATCH_BNE | (12 << OP_SH_IMM16); + break; + case OP_MATCH_BNE: + br_opcode = + (br_opcode & ~OP_MASK_OP) | OP_MATCH_BEQ | (12 << OP_SH_IMM16); + break; + case OP_MATCH_BGE: + case OP_MATCH_BGEU: + case OP_MATCH_BLT: + case OP_MATCH_BLTU: + /* swap the operands */ + br_op_a = (br_opcode & OP_MASK_RRT) << 5; + br_op_b = (br_opcode & OP_MASK_RRS) >> 5; + br_opcode = + (br_opcode & ~(OP_MASK_RRS | OP_MASK_RRT)) | br_op_a | br_op_b | + (12 << OP_SH_IMM16); + break; + default: + as_bad_where (fragp->fr_file, fragp->fr_line, + _("expecting conditional branch for relaxation\n")); + abort (); + } + + md_number_to_chars (buffer, br_opcode, 4); + md_number_to_chars (buffer + 4, OP_MATCH_ORHI | 0x00400000, 4); + md_number_to_chars (buffer + 8, OP_MATCH_ORI | 0x08400000, 4); + md_number_to_chars (buffer + 12, OP_MATCH_JMP | 0x08000000, 4); + fix_new (fragp, fragp->fr_fix + 4, 4, fragp->fr_symbol, + fragp->fr_offset, 0, BFD_RELOC_NIOS2_CJMP); + break; + default: + as_bad_where (fragp->fr_file, fragp->fr_line, + _("can't relax instruction\n")); + abort (); + break; + } + + fragp->fr_fix += growth; +} + + +/* round up section size */ +valueT +md_section_align (asection * seg ATTRIBUTE_UNUSED, valueT size) +{ + /* I think byte alignment is fine here */ + return size; +} + + +int +nios2_force_relocation (fixS * fixp) +{ + if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY + || fixp->fx_r_type == BFD_RELOC_NIOS2_ALIGN) + return 1; + + return 0; +} + +/* nios2_fix_adjustable is called to see whether a reloc against a defined symbol + should be converted into a reloc against a section. */ + +int +nios2_fix_adjustable (fixS * fixp) +{ +#ifdef OBJ_ELF + /* Prevent all adjustments to global symbols. */ + if (OUTPUT_FLAVOR == bfd_target_elf_flavour + && (S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))) + return 0; +#endif + if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 0; + + return 1; +} + +/* + nios2_frob_symbol is called in adjust_reloc_syms through the macro + tc_frob_symbol - it is used to remove *ABS* references from the + symbol table + */ +int +nios2_frob_symbol (symbolS * symp) +{ + if ((OUTPUT_FLAVOR == bfd_target_elf_flavour + && (symp) == section_symbol (absolute_section)) + || !S_IS_DEFINED (symp)) + return 1; + else + return 0; +} + +/* + The function tc_gen_reloc creates a relocation structure for the + fixup fixp, and returns a pointer to it. This structure is passed + to bfd_install_relocation so that it can be written to the object + file for linking +*/ +arelent * +tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp) +{ + arelent *reloc; + reloc = (arelent *) xmalloc (sizeof (arelent)); + reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->addend = fixp->fx_addnumber; + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); + if (reloc->howto == NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("can't represent relocation type %s"), + bfd_get_reloc_code_name (fixp->fx_r_type)); + + /* Set howto to a garbage value so that we can keep going. */ + reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); + assert (reloc->howto != NULL); + } + return reloc; +} + +long +md_pcrel_from (fixS * fixP ATTRIBUTE_UNUSED) +{ + return 0; +} + + +/* Apply a fixup to the object file. */ +void +md_apply_fix3 (fixS * fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED) +{ + const struct nios2_opcode *opcode; + enum overflow_type overflow_msg_type; + bfd_boolean overflowed = FALSE; + valueT fixup = 0; + + /* assert that the fixup is one we can handle */ + assert (fixP != NULL && valP != NULL && + (fixP->fx_r_type == BFD_RELOC_8 || + fixP->fx_r_type == BFD_RELOC_16 || + fixP->fx_r_type == BFD_RELOC_32 || + fixP->fx_r_type == BFD_RELOC_NIOS2_S16 || + fixP->fx_r_type == BFD_RELOC_NIOS2_U16 || + fixP->fx_r_type == BFD_RELOC_16_PCREL || + fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26 || + fixP->fx_r_type == BFD_RELOC_NIOS2_IMM5 || + fixP->fx_r_type == BFD_RELOC_NIOS2_CACHE_OPX || + fixP->fx_r_type == BFD_RELOC_NIOS2_IMM6 || + fixP->fx_r_type == BFD_RELOC_NIOS2_IMM8 || + fixP->fx_r_type == BFD_RELOC_NIOS2_HI16 || + fixP->fx_r_type == BFD_RELOC_NIOS2_LO16 || + fixP->fx_r_type == BFD_RELOC_NIOS2_HIADJ16 || + fixP->fx_r_type == BFD_RELOC_NIOS2_GPREL || + fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || + fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY || + fixP->fx_r_type == BFD_RELOC_NIOS2_UJMP || + fixP->fx_r_type == BFD_RELOC_NIOS2_CJMP || + fixP->fx_r_type == BFD_RELOC_NIOS2_CALLR || + fixP->fx_r_type == BFD_RELOC_NIOS2_ALIGN + // add other relocs here as we generate them + )); + + + /* The value passed in valP can be the value of a fully + resolved expression, or it can be the value of a partially + resolved expression. In the former case, both fixP->fx_addsy + and fixP->fx_subsy are NULL, and fixP->fx_offset == *valP, and + we can fix up the instruction that fixP relates to. + In the latter case, one or both of fixP->fx_addsy and + fixP->fx_subsy are not NULL, and fixP->fx_offset may or may not + equal *valP. We don't need to check for fixP->fx_subsy being null + because the generic part of the assembler generates an error if + it is not an absolute symbol */ + + if (fixP->fx_addsy != NULL) + { + fixP->fx_addnumber = fixP->fx_offset; + fixP->fx_done = 0; + } + else + { + valueT value; + + char *buf; + reloc_howto_type *howto; + howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); + + if (howto == NULL) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("relocation is not supported")); + } + else + { + fixup += *valP; + + /* If this is a pc-relative relocation, we need to + subtract the current offset within the object file + FIXME : for some reason fixP->fx_pcrel isn't 1 when it should be + so I'm using the howto structure instead to determine this */ + if (howto->pc_relative == 1) + fixup = fixup - (fixP->fx_frag->fr_address + fixP->fx_where + 4); + + + + /* Get the instruction to be fixed up */ + buf = fixP->fx_frag->fr_literal + fixP->fx_where; + value = md_chars_to_number (buf, 4); + + /* What opcode is the instruction? This will determine + whether we check for overflow in immediate values + and what error message we get */ + opcode = nios2_find_opcode_hash (value); + overflow_msg_type = opcode->overflow_msg; + + overflowed = nios2_check_overflow (fixup, howto); + + + if (overflowed) + { + unsigned int range_min; + unsigned int range_max; + unsigned int address; + switch (overflow_msg_type) + { + case call_target_overflow: + range_min = + ((fixP->fx_frag->fr_address + + fixP->fx_where) & 0xf0000000); + range_max = range_min + 0x0fffffff; + address = fixup | range_min; + + as_bad_where (fixP->fx_file, fixP->fx_line, + _(overflow_msgs[call_target_overflow]), + address, range_min, range_max); + break; + case branch_target_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _(overflow_msgs[branch_target_overflow]), + fixup, BYTE_B, BYTE_F); + break; + case address_offset_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _(overflow_msgs[address_offset_overflow]), + opcode->name, fixup, -32768, 32767); + break; + case signed_immed16_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _(overflow_msgs[signed_immed16_overflow]), + fixup, -32768, 32767); + break; + case unsigned_immed16_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _(overflow_msgs[unsigned_immed16_overflow]), + fixup, 0, 65535); + break; + case unsigned_immed5_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _(overflow_msgs[unsigned_immed5_overflow]), + fixup, 0, 31); + break; + case custom_opcode_overflow: + as_bad_where (fixP->fx_file, fixP->fx_line, + _(overflow_msgs[custom_opcode_overflow]), + fixup, 0, 255); + break; + default: + as_bad_where (fixP->fx_file, fixP->fx_line, + _ + ("unspecified overflow in immediate argument")); + break; + } + } + + + /* apply the rightshift */ + (signed) fixup >>= howto->rightshift; + + /* truncate the fixup to right size */ + switch (fixP->fx_r_type) + { + case BFD_RELOC_NIOS2_HI16: + fixup = (fixup >> 16) & 0xFFFF; + break; + case BFD_RELOC_NIOS2_LO16: + fixup = fixup & 0xFFFF; + break; + case BFD_RELOC_NIOS2_HIADJ16: + fixup = ((fixup >> 16) & 0xFFFF) + ((fixup >> 15) & 0x01); + break; + default: + fixup = + (fixup << (32 - howto->bitsize)) >> (32 - howto->bitsize); + break; + } + + /* fixup the instruction */ + value = (value & ~howto->dst_mask) | (fixup << howto->bitpos); + md_number_to_chars (buf, value, 4); + } + + fixP->fx_done = 1; + } + + if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT) + { + fixP->fx_done = 0; + if (fixP->fx_addsy + && !S_IS_DEFINED (fixP->fx_addsy) && !S_IS_WEAK (fixP->fx_addsy)) + S_SET_WEAK (fixP->fx_addsy); + } + else if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + { + fixP->fx_done = 0; + } +} + +bfd_boolean +nios2_check_overflow (valueT fixup, reloc_howto_type * howto) +{ + /* apply the rightshift before checking for overflow */ + (signed) fixup >>= howto->rightshift; + + /* check for overflow - return TRUE if overflow, FALSE if not */ + switch (howto->complain_on_overflow) + { + case complain_overflow_dont: + break; + case complain_overflow_bitfield: + if ((fixup >> howto->bitsize) != 0) + return TRUE; + break; + case complain_overflow_signed: + if ((fixup & 0x80000000) > 0) + { + /* check for negative overflow */ + if ((signed) fixup < ((signed) 0x80000000 >> howto->bitsize)) + return TRUE; + } + else + { + /* check for positive overflow */ + if (fixup >= ((unsigned) 1 << (howto->bitsize - 1))) + return TRUE; + } + break; + case complain_overflow_unsigned: + if ((fixup >> howto->bitsize) != 0) + return TRUE; + break; + default: + as_bad (_("error checking for overflow - broken assembler")); + break; + } + + return FALSE; +} + +/* + Function : void md_end() + Description : Called just before the assembler exits + */ +void +md_end () +{ + /* FIXME - not yet implemented */ +} + + +/* + Creates a new nios2_insn_relocS and returns a pointer to it +*/ +nios2_insn_relocS * +nios2_insn_reloc_new (bfd_reloc_code_real_type reloc_type, unsigned int pcrel) +{ + nios2_insn_relocS *retval; + retval = (nios2_insn_relocS *) malloc (sizeof (nios2_insn_relocS)); + if (retval == NULL) + { + as_bad (_("can't create relocation")); + abort (); + } + + /* fill out the fields with default values */ + retval->reloc_next = NULL; + retval->reloc_type = reloc_type; + retval->reloc_pcrel = pcrel; + return retval; +} + +/* + Frees up memory previously allocated by nios2_insn_reloc_new() + */ +void +nios2_insn_reloc_destroy (nios2_insn_relocS * reloc) +{ + assert (reloc != NULL); + free (reloc); +} + +/* + Function : nios2_assemble_expression(char* exprstr) + + Description : The various nios2_assemble_* functions call this + function to generate an expression from a + string representing an expression + It then tries to evaluate the expression, and + if it can, returns its value. + If not, it creates a new nios2_insn_relocS + and stores the expression and reloc_type + for future use + */ +unsigned long +nios2_assemble_expression (const char *exprstr, + nios2_insn_infoS * insn, + nios2_insn_relocS * prev_reloc, + bfd_reloc_code_real_type reloc_type, + unsigned int pcrel) +{ + nios2_insn_relocS *reloc; + char *saved_line_ptr; + unsigned short value; + int i; + + assert (exprstr != NULL); + assert (insn != NULL); + + /* check for %gprel, %hi, %lo or %hiadj + change the relocation type + and advance the ptr to the start of + the expression proper */ + for (i = 0; i < nios2_num_special_relocs; i++) + { + if (strstr (exprstr, nios2_special_reloc[i].string) != NULL) + { + reloc_type = nios2_special_reloc[i].reloc_type; + exprstr += strlen (nios2_special_reloc[i].string) + 1; + break; + } + } + + /* we potentially have a relocation */ + reloc = nios2_insn_reloc_new (reloc_type, pcrel); + if (prev_reloc != NULL) + prev_reloc->reloc_next = reloc; + else + insn->insn_reloc = reloc; + + /* parse the expression string */ + saved_line_ptr = input_line_pointer; + input_line_pointer = (char *) exprstr; + expression (&reloc->reloc_expression); + input_line_pointer = saved_line_ptr; + + /* this is redundant as the fixup will put this into + the instruction, but it is included here so that + self-test mode (-r) works */ + value = 0; + if (nios2_mode == NIOS2_MODE_TEST) + { + if (reloc->reloc_expression.X_op == O_constant) + value = reloc->reloc_expression.X_add_number; + } + + return (unsigned long) value; +} + +/* + The function consume_separate takes a pointer into a string + of instruction tokens (args) and a pointer into a string representing + the expected sequence of tokens and separators. It finds the first + instance of the character pointed to by separator in argStr, and + returns a pointer to the next element of argStr, which is the + following token in the sequence. + */ +char * +nios2_consume_separator (char *argStr, const char *separator) +{ + char *argPtr; + + /* if we have a opcode reg, expr(reg) type instruction, and + * we are separating the expr from the (reg), we find the last + * (, just in case the expression has brackets */ + + if (*separator == '(') + argPtr = strrchr (argStr, *separator); + else + argPtr = strchr (argStr, *separator); + + if (argPtr != NULL) + *argPtr++ = 0; + else + as_bad (_("expecting %c near %s"), *separator, argStr); + return argPtr; +} + +/* + The function consume_arg takes a pointer into a string + of instruction tokens (args) and a pointer into a string + representing the expected sequence of tokens and separators. + It checks whether the first argument in argStr is of the + expected type, throwing an error if it is not, and returns + the pointer argStr. + */ +char * +nios2_consume_arg (char *argStr, const char *argType) +{ + char *temp; + int regno = -1; + + switch (*argType) + { + case 'c': + if (strncmp (argStr, "ctl", strlen ("ctl")) != 0 + && strncmp (argStr, "status", strlen ("status")) != 0 + && strncmp (argStr, "estatus", strlen ("estatus")) != 0 + && strncmp (argStr, "bstatus", strlen ("bstatus")) != 0 + && strncmp (argStr, "ienable", strlen ("ienable")) != 0 + && strncmp (argStr, "ipending", strlen ("ipending")) != 0) + { + as_bad (_("expecting control register")); + } + break; + case 'd': + case 's': + case 't': + + /* we check to make sure we don't have a control register */ + if (strncmp (argStr, "ctl", strlen ("ctl")) == 0 + || strncmp (argStr, "status", strlen ("status")) == 0 + || strncmp (argStr, "estatus", strlen ("estatus")) == 0 + || strncmp (argStr, "bstatus", strlen ("bstatus")) == 0 + || strncmp (argStr, "ienable", strlen ("ienable")) == 0 + || strncmp (argStr, "ipending", strlen ("ipending")) == 0) + { + as_bad (_("illegal use of control register")); + } + + /* and whether coprocessor registers are valid here */ + if (nios2_coproc_reg (argStr) + && insn.insn_nios2_opcode->match != OP_MATCH_CUSTOM) + { + as_bad (_("illegal use of coprocessor register\n")); + } + + + /* extract a register number if the register is of the + form r[0-9]+, if it is a normal register, set + regno to its number (0-31), else set regno to -1 */ + if (argStr[0] == 'r' && ISDIGIT (argStr[1])) + { + char *p = argStr; + + ++p; + regno = 0; + do + { + regno *= 10; + regno += *p - '0'; + ++p; + } + while (ISDIGIT (*p)); + } + else + { + regno = -1; + } + + /* and whether we are using at */ + if (!nios2_as_options.noat + && (regno == 1 + || strncmp (argStr, "at", strlen ("at")) == 0)) + { + as_warn (_("Register at (r1) can sometimes be corrupted by assembler optimizations.\n" + "Use .set noat to turn off those optimizations (and this warning).")); + } + + /* and whether we are using oci registers */ + if (!nios2_as_options.nobreak + && (regno == 25 + || strncmp (argStr, "bt", strlen ("bt")) == 0)) + { + as_warn (_("The debugger will corrupt bt (r25). If you don't need to debug this\n" + "code then use .set nobreak to turn off this warning.")); + } + + if (!nios2_as_options.nobreak + && (regno == 30 + || strncmp (argStr, "ba", strlen ("ba")) == 0)) + { + as_warn (_("The debugger will corrupt ba (r30). If you don't need to debug this\n" + "code then use .set nobreak to turn off this warning.")); + } + break; + case 'i': + case 'u': + if (*argStr == '%') + { + if (strstr (argStr, "%hi(") || strstr (argStr, "%lo(") + || strstr (argStr, "%hiadj(") || strstr (argStr, "%gprel(")) + { + // we zap the brackets because we don't want them confused with separators + temp = strchr (argStr, '('); + if (temp != NULL) + *temp = ' '; + temp = strchr (argStr, ')'); + if (temp != NULL) + *temp = ' '; + } + else + { + as_bad (_("badly formed expression near %s"), argStr); + } + } + break; + case 'm': + case 'j': + case 'k': + case 'l': + case 'b': + /* we can't have %hi, %lo or %hiadj here */ + if (*argStr == '%') + as_bad (_("badly formed expression near %s"), argStr); + break; + default: + break; + } + return argStr; +} + +/* + The principal argument parsing function which takes a string + representing the instruction arguments, and extracts the argument + tokens + */ +void +nios2_parse_args (char *argStr, const char *parseStr, char **parsedArgs) +{ + char *p; + char *end = NULL; + int i; + p = argStr; + i = 0; + bfd_boolean terminate = FALSE; + + /* This rest of this function is it too fragile and it mostly works, + therefore special case this one */ + if (*parseStr == 0 && argStr != 0) + { + as_bad (_("too many arguments")); + parsedArgs[0] = NULL; + return; + } + + + while (p != NULL && !terminate && i < NIOS2_MAX_INSN_TOKENS) + { + parsedArgs[i] = nios2_consume_arg (p, parseStr); + ++parseStr; + if (*parseStr != '\0') + { + p = nios2_consume_separator (p, parseStr); + ++parseStr; + } + else + { + /* check that the argument string has no trailing arguments */ + /* if we've got a %lo etc relocation, we've zapped the brackets with spaces */ + if (strstr (p, "%lo") == p || strstr (p, "%hi") == p + || strstr (p, "%hiadj") == p || strstr (p, "%gprel") == p) + end = strpbrk (p, ","); + else + end = strpbrk (p, " ,"); + + if (end != NULL) + as_bad (_("too many arguments")); + } + + if (*parseStr == '\0' || (p != NULL && *p == '\0')) + { + terminate = TRUE; + } + ++i; + } + + parsedArgs[i] = NULL; + + if (*parseStr != '\0' && insn.insn_nios2_opcode->match != OP_MATCH_BREAK) + as_bad (_("missing argument")); + +} + + +/* checks whether the register name is a coprocessor + register - returns TRUE if it is, FALSE otherwise */ + +static bfd_boolean +nios2_coproc_reg (const char *reg_name) +{ + assert (reg_name != NULL); + +/* check that we do have a valid register name and that it is a + * coprocessor register + * it must begin with c, not be a control register, and be a valid + * register name */ + + if (strncmp (reg_name, "c", 1) == 0 && + strncmp (reg_name, "ctl", strlen ("ctl")) != 0 && + hash_find (nios2_reg_hash, reg_name) != NULL) + return TRUE; + else + return FALSE; +} + + +/********************************************************************* + Argument assemble functions + + Description : All take an instruction argument string, and a pointer + to an instruction opcode. Upon return the insn_opcode + has the relevant fields filled in to represent the arg + string. The return value is NULL if successful, or + an error message if an error was detected + *********************************************************************/ + +/* assembles register arguments "dst, src1, src2" */ +void +nios2_assemble_args_dst (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *dst, *src1, *src2; + + if (insn_info->insn_tokens[1] != NULL && + insn_info->insn_tokens[2] != NULL && insn_info->insn_tokens[3] != NULL) + { + dst = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + src1 = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[2]); + src2 = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[3]); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src1->index); + + if (src2 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[3]); + else + SET_INSN_FIELD (RRT, insn_info->insn_code, src2->index); + + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[4]); + } +} + + +/* assembles arguments successfully parsed by nios2_parse_args_tsi */ +void +nios2_assemble_args_tsi (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *dst, *src1; + unsigned int src2; + + if (insn_info->insn_tokens[1] != NULL && + insn_info->insn_tokens[2] != NULL && insn_info->insn_tokens[3] != NULL) + { + dst = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + src1 = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[2]); + src2 = + nios2_assemble_expression (insn_info->insn_tokens[3], insn_info, + insn_info->insn_reloc, BFD_RELOC_NIOS2_S16, + 0); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (IRT, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (IRS, insn_info->insn_code, src1->index); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, src2); + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[4]); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + + +/* assembles args successfully parsed by nios2_parse_args_tsu */ +void +nios2_assemble_args_tsu (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *dst, *src1; + unsigned int src2; + + if (insn_info->insn_tokens[1] != NULL && + insn_info->insn_tokens[2] != NULL && insn_info->insn_tokens[3] != NULL) + { + dst = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + src1 = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[2]); + src2 = + nios2_assemble_expression (insn_info->insn_tokens[3], insn_info, + insn_info->insn_reloc, BFD_RELOC_NIOS2_U16, + 0); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (IRT, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (IRS, insn_info->insn_code, src1->index); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, src2); + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[4]); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + + +/* assembles args successfully parsed by nios2_parse_args_sti */ +void +nios2_assemble_args_sto (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *dst, *src1; + unsigned int src2; + + if (insn_info->insn_tokens[1] != NULL && + insn_info->insn_tokens[2] != NULL && insn_info->insn_tokens[3] != NULL) + { + dst = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + src1 = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[2]); + src2 = + nios2_assemble_expression (insn_info->insn_tokens[3], insn_info, + insn_info->insn_reloc, BFD_RELOC_16_PCREL, + 1); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (IRS, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (IRT, insn_info->insn_code, src1->index); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, src2); + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[4]); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + + +void +nios2_assemble_args_o (nios2_insn_infoS * insn_info) +{ + unsigned long immed; + + if (insn_info->insn_tokens[1] != NULL) + { + immed = + nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, + insn_info->insn_reloc, BFD_RELOC_16_PCREL, + 1); + SET_INSN_FIELD (IMM16, insn_info->insn_code, immed); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[2]); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + + +void +nios2_assemble_args_is (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *addr_src; + unsigned long immed; + + if (insn_info->insn_tokens[1] != NULL && insn_info->insn_tokens[2] != NULL) + { + addr_src = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[2]); + + immed = + nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, + insn_info->insn_reloc, BFD_RELOC_NIOS2_S16, + 0); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, immed); + + if (addr_src == NULL) + as_bad (_("unknown base register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, addr_src->index); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[3]); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + + +void +nios2_assemble_args_m (nios2_insn_infoS * insn_info) +{ + unsigned long immed; + if (insn_info->insn_tokens[1] != NULL) + { + immed = + nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, + insn_info->insn_reloc, + BFD_RELOC_NIOS2_CALL26, 0); + + SET_INSN_FIELD (IMM26, insn_info->insn_code, immed); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[2]); + + SET_INSN_FIELD (IMM26, insn_info->insn_code, 0); + } +} + + +void +nios2_assemble_args_s (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *src; + + if (insn_info->insn_tokens[1] != NULL) + { + src = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + + if (src == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src->index); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[2]); + } +} + + +void +nios2_assemble_args_tis (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *addr_src, *dst; + unsigned long immed; + + if (insn_info->insn_tokens[1] != NULL && + insn_info->insn_tokens[2] != NULL && insn_info->insn_tokens[3] != NULL) + { + + dst = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + addr_src = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[3]); + immed = + nios2_assemble_expression (insn_info->insn_tokens[2], insn_info, + insn_info->insn_reloc, BFD_RELOC_NIOS2_S16, + 0); + + + if (addr_src == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[3]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, addr_src->index); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRT, insn_info->insn_code, dst->index); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, immed); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[4]); + + SET_INSN_FIELD (IMM16, insn_info->insn_code, 0); + } +} + + +/* assemble rdctl dst, ctl */ +void +nios2_assemble_args_dc (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *dst, *ctl; + + if (insn_info->insn_tokens[1] != NULL && insn_info->insn_tokens[2] != NULL) + { + ctl = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[2]); + dst = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + + if (ctl == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RCTL, insn_info->insn_code, ctl->index); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[3]); + } +} + + +/* assemble wrctl ctl, src */ +void +nios2_assemble_args_cs (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *src, *ctl; + + if (insn_info->insn_tokens[1] != NULL && insn_info->insn_tokens[2] != NULL) + { + ctl = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + src = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[2]); + + if (ctl == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else if (ctl->index == 4) + as_bad (_("ipending control register (ctl4) is read-only\n")); + else + SET_INSN_FIELD (RCTL, insn_info->insn_code, ctl->index); + + if (src == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src->index); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[3]); + } +} + + + +void +nios2_assemble_args_ldst (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *dst, *src1, *src2; + unsigned long custom_n; + + if (insn_info->insn_tokens[1] != NULL && + insn_info->insn_tokens[2] != NULL && + insn_info->insn_tokens[3] != NULL && insn_info->insn_tokens[4] != NULL) + { +#if 0 /* ??? Unused/half commented out code */ + char *end_p; + /* custom_n = nios2_strtoul(insn_info->insn_tokens[1], &end_p); */ +#endif + custom_n = + nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, + insn_info->insn_reloc, + BFD_RELOC_NIOS2_IMM8, 0); + + dst = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[2]); + src1 = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[3]); + src2 = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[4]); + + SET_INSN_FIELD (CUSTOM_N, insn_info->insn_code, custom_n); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[3]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src1->index); + + if (src2 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[4]); + else + SET_INSN_FIELD (RRT, insn_info->insn_code, src2->index); + + /* set or clear the bits to indicate whether coprocessor registers are used */ + if (nios2_coproc_reg (insn_info->insn_tokens[2])) + SET_INSN_FIELD (CUSTOM_C, insn_info->insn_code, 0); + else + SET_INSN_FIELD (CUSTOM_C, insn_info->insn_code, 1); + + if (nios2_coproc_reg (insn_info->insn_tokens[3])) + SET_INSN_FIELD (CUSTOM_A, insn_info->insn_code, 0); + else + SET_INSN_FIELD (CUSTOM_A, insn_info->insn_code, 1); + + if (nios2_coproc_reg (insn_info->insn_tokens[4])) + SET_INSN_FIELD (CUSTOM_B, insn_info->insn_code, 0); + else + SET_INSN_FIELD (CUSTOM_B, insn_info->insn_code, 1); + + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[5]); + } +} + + +void +nios2_assemble_args_none (nios2_insn_infoS * insn_info ATTRIBUTE_UNUSED) +{ + // nothing to do +} + + +void +nios2_assemble_args_dsj (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *dst, *src1; + unsigned int src2; + + if (insn_info->insn_tokens[1] != NULL && + insn_info->insn_tokens[2] != NULL && insn_info->insn_tokens[3] != NULL) + { + dst = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + src1 = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[2]); + + // a 5-bit constant expression + src2 = + nios2_assemble_expression (insn_info->insn_tokens[3], insn_info, + insn_info->insn_reloc, + BFD_RELOC_NIOS2_IMM5, 0); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + if (src1 == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[2]); + else + SET_INSN_FIELD (RRS, insn_info->insn_code, src1->index); + + SET_INSN_FIELD (IMM5, insn_info->insn_code, src2); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[4]); + + SET_INSN_FIELD (IMM5, insn_info->insn_code, 0); + } +} + + +/* assembles register arguments "dst" */ +void +nios2_assemble_args_d (nios2_insn_infoS * insn_info) +{ + struct nios2_reg *dst; + + if (insn_info->insn_tokens[1] != NULL) + { + dst = + (struct nios2_reg *) hash_find (nios2_reg_hash, + insn_info->insn_tokens[1]); + + if (dst == NULL) + as_bad (_("unknown register %s"), insn_info->insn_tokens[1]); + else + SET_INSN_FIELD (RRD, insn_info->insn_code, dst->index); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[2]); + } +} + +/* assemble break op */ +void +nios2_assemble_args_b (nios2_insn_infoS * insn_info) +{ + unsigned int imm5 = 0; + + if (insn_info->insn_tokens[1] != NULL) + { + // a 5-bit constant expression + imm5 = + nios2_assemble_expression (insn_info->insn_tokens[1], insn_info, + insn_info->insn_reloc, + BFD_RELOC_NIOS2_IMM5, 0); + + SET_INSN_FIELD (TRAP_IMM5, insn_info->insn_code, imm5); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[2]); + } + + SET_INSN_FIELD (TRAP_IMM5, insn_info->insn_code, imm5); + + NIOS2_CHECK_ASSEMBLY (insn_info->insn_code, insn_info->insn_tokens[2]); +} + +/* Machine-dependent assembler directive handling follows */ + +/* + .set sets assembler options eg noat/at and is also used + to set symbol values (.equ, .equiv ) +*/ +void +s_nios2_set (int equiv) +{ + char *directive = input_line_pointer; + char delim = get_symbol_end (); + char *endline; + endline = input_line_pointer; + *endline = delim; + + /* we only want to handle ".set XXX" if the + user has tried ".set XXX, YYY" they are not + trying a directive. This prevents + us from polluting the name space */ + + SKIP_WHITESPACE (); + + if (is_end_of_line[(unsigned char) *input_line_pointer]) + { + bfd_boolean done = FALSE; + *endline = 0; + + if (!strcmp (directive, "noat")) + { + done = TRUE; + nios2_as_options.noat = TRUE; + } + + if (!strcmp (directive, "at")) + { + done = TRUE; + nios2_as_options.noat = FALSE; + } + + if (!strcmp (directive, "nobreak")) + { + done = TRUE; + nios2_as_options.nobreak = TRUE; + } + + if (!strcmp (directive, "break")) + { + done = TRUE; + nios2_as_options.nobreak = FALSE; + } + + if (!strcmp (directive, "norelax")) + { + done = TRUE; + nios2_as_options.relax = relax_none; + } + else if (!strcmp (directive, "relaxsection")) + { + done = TRUE; + nios2_as_options.relax = relax_section; + } + else if (!strcmp (directive, "relaxall")) + { + done = TRUE; + nios2_as_options.relax = relax_all; + } + + + if (done) + { + *endline = delim; + demand_empty_rest_of_line (); + return; + } + } + + + /* If we fall through to here, either we have ".set XXX, YYY" + or we have ".set XXX" where XXX is unknown or we have + a syntax error */ + input_line_pointer = directive; + *endline = delim; + s_set (equiv); +} + +/* nop fill pattern for text section */ +static char const nop[4] = { 0x3a, 0x88, 0x01, 0x00 }; + +/* nios2_frob_label() is called when after a label is recognized. */ + +void +nios2_frob_label (symbolS * lab) +{ + /* Update the label's address with the current output pointer. */ + symbol_set_frag (lab, frag_now); + S_SET_VALUE (lab, (valueT) frag_now_fix ()); + + /* Record this label for future adjustment after we find out what + kind of data it references, and the required alignment therewith. */ + nios2_last_label = lab; +} + + + +/* Hook into cons for auto-alignment. */ + +void +nios2_cons_align (int size) +{ + int log_size; + const char *pfill = NULL; + + log_size = 0; + while ((size >>= 1) != 0) + ++log_size; + + if (subseg_text_p (now_seg)) + { + pfill = (const char *) &nop; + } + else + pfill = NULL; + + if (nios2_auto_align_on) + nios2_align (log_size, pfill, NULL); + + nios2_last_label = NULL; +} + +static void +s_nios2_sdata (int ignore ATTRIBUTE_UNUSED) +{ + int temp; + + temp = get_absolute_expression (); + subseg_new (".sdata", 0); + demand_empty_rest_of_line (); +} + +/* Map 's' to SHF_NIOS2_GPREL. */ +/* this is from the Alpha code tc-alpha.c */ +int +nios2_elf_section_letter (int letter, char **ptr_msg) +{ + if (letter == 's') + return SHF_NIOS2_GPREL; + + *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S,G,T in string"); + return 0; +} + +/* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA. */ +/* this is from the Alpha code tc-alpha.c */ +flagword +nios2_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED) +{ + if (attr & SHF_NIOS2_GPREL) + flags |= SEC_SMALL_DATA; + return flags; +} + +/* explicitly unaligned cons */ + +static void +s_nios2_ucons (int nbytes) +{ + int hold; + hold = nios2_auto_align_on; + nios2_auto_align_on = 0; + cons (nbytes); + nios2_auto_align_on = hold; +} + +/* Handles all machine-dependent alignment needs */ +static void +nios2_align (int log_size, const char *pfill, symbolS * label) +{ + int align; + long max_alignment = 15; + + /* The front end is prone to changing segments out from under us + temporarily when -g is in effect. */ + int switched_seg_p = (nios2_current_align_seg != now_seg); + + align = log_size; + if (align > max_alignment) + { + align = max_alignment; + as_bad (_("Alignment too large: %d. assumed"), align); + } + else if (align < 0) + { + as_warn (_("Alignment negative: 0 assumed")); + align = 0; + } + + if (align != 0) + { + if (subseg_text_p (now_seg) && align >= 2) + { + /* First, make sure we're on a four-byte boundary, in case + someone has been putting .byte values the text section. */ + if (nios2_current_align < 2 || switched_seg_p) + frag_align (2, 0, 0); + + /* now fill in the alignment pattern */ + if (pfill != NULL) + frag_align_pattern (align, pfill, sizeof nop, 0); + else + frag_align (align, 0, 0); + } + else + { + frag_align (align, 0, 0); + } + + if (!switched_seg_p) + nios2_current_align = align; + + /* If the last label was in a different section we can't align it */ + if (label != NULL && !switched_seg_p) + { + symbolS *sym; + int label_seen = FALSE; + struct frag *old_frag; + valueT old_value; + valueT new_value; + + assert (S_GET_SEGMENT (label) == now_seg); + + old_frag = symbol_get_frag (label); + old_value = S_GET_VALUE (label); + new_value = (valueT) frag_now_fix (); + + /* It is possible to have more than one label at a particular + address, especially if debugging is enabled, so we must + take care to adjust all the labels at this address in this + fragment. To save time we search from the end of the symbol + list, backwards, since the symbols we are interested in are + almost certainly the ones that were most recently added. + Also to save time we stop searching once we have seen at least + one matching label, and we encounter a label that is no longer + in the target fragment. Note, this search is guaranteed to + find at least one match when sym == label, so no special case + code is necessary. */ + for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym)) + { + if (symbol_get_frag (sym) == old_frag + && S_GET_VALUE (sym) == old_value) + { + label_seen = TRUE; + symbol_set_frag (sym, frag_now); + S_SET_VALUE (sym, new_value); + } + else if (label_seen && symbol_get_frag (sym) != old_frag) + break; + } + } + record_alignment (now_seg, align); + } +} + +/* This is called from HANDLE_ALIGN in tc-nios2.h. */ + +void +nios2_handle_align (fragS * fragp) +{ + /* If we are expecting to relax in the linker, then we must output a relocation + * to tell the linker we are aligning code */ + if (nios2_as_options.relax == relax_all + && (fragp->fr_type == rs_align + || fragp->fr_type == rs_align_code) + && fragp->fr_address + fragp->fr_fix > 0 + && fragp->fr_offset > 1 && now_seg != bss_section) + fix_new (fragp, fragp->fr_fix, 4, &abs_symbol, fragp->fr_offset, 0, + BFD_RELOC_NIOS2_ALIGN); + +} + +/* Handle the .align pseudo-op. This aligns to a power of two. It + also adjusts any current instruction label. We treat this the same + way the MIPS port does: .align 0 turns off auto alignment. */ + +static void +s_nios2_align (int ignore ATTRIBUTE_UNUSED) +{ + int align; + char fill; + const char *pfill = NULL; + long max_alignment = 15; + + + align = get_absolute_expression (); + if (align > max_alignment) + { + align = max_alignment; + as_bad (_("Alignment too large: %d. assumed"), align); + } + else if (align < 0) + { + as_warn (_("Alignment negative: 0 assumed")); + align = 0; + } + + if (*input_line_pointer == ',') + { + input_line_pointer++; + fill = get_absolute_expression (); + pfill = (const char *) &fill; + } + else if (subseg_text_p (now_seg)) + { + pfill = (const char *) &nop; + } + else + { + pfill = NULL; + nios2_last_label = NULL; + } + + if (align != 0) + { + nios2_auto_align_on = 1; + nios2_align (align, pfill, nios2_last_label); + nios2_last_label = NULL; + } + else + { + nios2_auto_align_on = 0; + } + + demand_empty_rest_of_line (); +} + + +/* Handle the .text pseudo-op. This is like the usual one, but it + clears the saved last label and resets known alignment. */ + +static void +s_nios2_text (int i) +{ + s_text (i); + nios2_last_label = NULL; + nios2_current_align = 0; + nios2_current_align_seg = now_seg; +} + +/* Handle the .data pseudo-op. This is like the usual one, but it + clears the saved last label and resets known alignment. */ + +static void +s_nios2_data (int i) +{ + s_data (i); + nios2_last_label = NULL; + nios2_current_align = 0; + nios2_current_align_seg = now_seg; +} + +/* Handle the .section pseudo-op. This is like the usual one, but it + clears the saved last label and resets known alignment. */ + +static void +s_nios2_section (int ignore) +{ + obj_elf_section (ignore); + nios2_last_label = NULL; + nios2_current_align = 0; + nios2_current_align_seg = now_seg; +} --- binutils-2.15/gas/config/tc-nios2.h 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/gas/config/tc-nios2.h 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,98 @@ +/* tc-nios2.h -- header file for tc-nios2.c. + + Copyright (C) 2003 + by Nigel Gray (ngray@altera.com). + + This file is part of GAS. + + 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, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef TC_NIOS2 +#define TC_NIOS2 + + +#define TARGET_BYTES_BIG_ENDIAN 0 + +#ifdef OBJ_ELF +#define TARGET_FORMAT "elf32-littlenios2" +#define TARGET_ARCH bfd_arch_nios2 +#endif + +/* An NIOS2 instruction consists of tokens and separator characters +// the tokens are things like the instruction name (add, or jmp etc), +// the register indices ($5, $7 etc), and constant expressions. The +// separator characters are commas, brackets and space. +// The instruction name is always separated from other tokens by a space +// The maximum number of tokens in an instruction is 5 (the instruction name, +// 3 arguments, and a 4th string representing the expected instructin opcode +// after assembly. The latter is only used when the assemble is running in +// self test mode, otherwise its presence will generate an error. */ +#define NIOS2_MAX_INSN_TOKENS 6 + +/* There are no machine-specific operands so we #define this to nothing */ +#define md_operand(x) + +/* NG this may need to change when we look at implementing symbols */ +#define md_undefined_symbol(name) (0) + +/* function prototypes exported to rest of GAS */ +extern void md_assemble (char *op_str); +extern void md_end (void); +extern void md_begin (void); + +#define TC_FORCE_RELOCATION(fixp) nios2_force_relocation (fixp) +extern int nios2_force_relocation (struct fix *); + +#define tc_fix_adjustable(fixp) nios2_fix_adjustable (fixp) +extern int nios2_fix_adjustable (struct fix *); + +#define tc_frob_label(lab) nios2_frob_label(lab) +extern void nios2_frob_label (symbolS *); + +#define tc_frob_symbol(symp, punt) punt = nios2_frob_symbol(symp) ? 1 : punt +extern int nios2_frob_symbol (symbolS * symp); + +#define md_cons_align(nbytes) nios2_cons_align (nbytes) +extern void nios2_cons_align (int); + +extern void md_convert_frag (bfd * headers, segT sec, fragS * fragP); + +/* When relaxing, we need to generate relocations for alignment + directives. */ +#define HANDLE_ALIGN(frag) nios2_handle_align (frag) +extern void nios2_handle_align (fragS *); + + +#define md_relax_frag nios2_relax_frag +extern long nios2_relax_frag + (segT segment, fragS * fragP, long stretch); + +#ifdef OBJ_ELF +#define ELF_TC_SPECIAL_SECTIONS \ + { ".sdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, \ + { ".sbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, \ + { ".lit4", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, \ + { ".lit8", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, + +/* Processor specific section directives */ +#define md_elf_section_letter nios2_elf_section_letter +extern int nios2_elf_section_letter (int, char **); +#define md_elf_section_flags nios2_elf_section_flags +extern flagword nios2_elf_section_flags (flagword, int, int); +#endif + + +#endif // TC_NIOS2 --- binutils-2.15/gas/configure 2004-05-17 21:36:07.000000000 +0200 +++ binutils-2.15-nios2/gas/configure 2005-05-17 12:20:13.000000000 +0200 @@ -4173,6 +4173,7 @@ for this_target in $target $canon_target m8*) cpu_type=m88k ;; mips*el) cpu_type=mips endian=little ;; mips*) cpu_type=mips endian=big ;; + nios2*|nios2*) cpu_type=nios2 ;; or32*) cpu_type=or32 endian=big ;; pjl*) cpu_type=pj endian=little ;; pj*) cpu_type=pj endian=big ;; @@ -4439,6 +4440,7 @@ echo "$as_me: error: Unknown vendor for mn10200-*-*) fmt=elf ;; mn10300-*-*) fmt=elf ;; msp430-*-*) fmt=elf ;; + nios2-*-*) fmt=elf ;; openrisc-*-*) fmt=elf ;; or32-*-rtems*) fmt=elf ;; or32-*-coff) fmt=coff ;; @@ -4589,7 +4591,7 @@ _ACEOF fi case ${cpu_type}-${fmt} in - alpha*-* | arm-* | i386-* | ia64*-* | mips-* | ns32k-* \ + alpha*-* | arm-* | i386-* | ia64*-* | mips-* | nios2-* | ns32k-* \ | pdp11-* | ppc-* | sparc-* | strongarm-* | xscale-* \ | *-elf | *-ecoff | *-som) bfd_gas=yes ;; --- binutils-2.15/gas/configure.in 2004-05-17 21:36:07.000000000 +0200 +++ binutils-2.15-nios2/gas/configure.in 2005-05-17 12:20:13.000000000 +0200 @@ -143,6 +143,7 @@ changequote([,])dnl m8*) cpu_type=m88k ;; mips*el) cpu_type=mips endian=little ;; mips*) cpu_type=mips endian=big ;; + nios2*|nios2*) cpu_type=nios2 ;; or32*) cpu_type=or32 endian=big ;; pjl*) cpu_type=pj endian=little ;; pj*) cpu_type=pj endian=big ;; @@ -400,6 +401,7 @@ changequote([,])dnl mn10200-*-*) fmt=elf ;; mn10300-*-*) fmt=elf ;; msp430-*-*) fmt=elf ;; + nios2-*-*) fmt=elf ;; openrisc-*-*) fmt=elf ;; or32-*-rtems*) fmt=elf ;; or32-*-coff) fmt=coff ;; @@ -539,7 +541,7 @@ changequote([,])dnl fi case ${cpu_type}-${fmt} in - alpha*-* | arm-* | i386-* | ia64*-* | mips-* | ns32k-* \ + alpha*-* | arm-* | i386-* | ia64*-* | mips-* | nios2-* | ns32k-* \ | pdp11-* | ppc-* | sparc-* | strongarm-* | xscale-* \ | *-elf | *-ecoff | *-som) bfd_gas=yes ;; --- binutils-2.15/gas/doc/Makefile.am 2004-01-05 23:16:05.000000000 +0100 +++ binutils-2.15-nios2/gas/doc/Makefile.am 2005-05-17 12:20:13.000000000 +0200 @@ -24,6 +24,7 @@ asconfig.texi: $(CONFIG).texi || cp $(srcdir)/$(CONFIG).texi ./asconfig.texi CPU_DOCS = \ + c-nios2.texi \ c-a29k.texi \ c-alpha.texi \ c-arc.texi \ --- binutils-2.15/gas/doc/Makefile.in 2004-05-17 21:36:11.000000000 +0200 +++ binutils-2.15-nios2/gas/doc/Makefile.in 2005-05-17 12:20:13.000000000 +0200 @@ -213,6 +213,7 @@ POD2MAN = pod2man --center="GNU Developm man_MANS = as.1 info_TEXINFOS = as.texinfo CPU_DOCS = \ + c-nios2.texi \ c-a29k.texi \ c-alpha.texi \ c-arc.texi \ --- binutils-2.15/gas/doc/all.texi 2003-04-01 17:50:30.000000000 +0200 +++ binutils-2.15-nios2/gas/doc/all.texi 2005-05-17 12:20:13.000000000 +0200 @@ -26,6 +26,7 @@ @c CPUs of interest @c ================ +@set NIOSII @set A29K @set ALPHA @set ARC --- binutils-2.15/gas/doc/as.texinfo 2004-01-09 03:34:04.000000000 +0100 +++ binutils-2.15-nios2/gas/doc/as.texinfo 2005-05-17 12:20:13.000000000 +0200 @@ -238,6 +238,15 @@ gcc(1), ld(1), and the Info entries for @c @c Target dependent options are listed below. Keep the list sorted. @c Add an empty line for separation. + + +@ifset NIOSII +@emph{Target Altera Nios II options:} + [@b{-relax-all}] + [@b{-relax-section}] + [@b{-no-relax}] +@end ifset + @ifset A29K @c am29k has no machine-dependent assembler options @end ifset @@ -577,6 +586,21 @@ Standard input, or source files to assem @end table +@ifset NIOSII +The following options are available when @value{AS} is configured for +an Altera Nios II processor. + +@table @gcctabopt +@item -relax-all +Replace all branch and call instructions with @code{jmp} and @code{callr} sequences +@item -relax-section +Replace identified out of range branches with @code{jmp} sequences (default) +@item -no-relax +Do not replace any branches or calls +@end table +@end ifset + + @ifset ARC The following options are available when @value{AS} is configured for an ARC processor. @@ -2035,6 +2059,9 @@ This means you may not nest these commen @cindex line comment character Anything from the @dfn{line comment} character to the next newline is considered a comment and is ignored. The line comment character is +@ifset NIOSII +@samp{#} for the Altera Nios II family; +@end ifset @ifset A29K @samp{;} for the AMD 29K family; @end ifset @@ -3876,7 +3903,7 @@ is already a multiple of 8, no change is first expression is the alignment request in words. For other systems, including the i386 using a.out format, and the arm and -strongarm, it is the +strongarm, and the Altera Nios II, it is the number of low-order zero bits the location counter must have after advancement. For example @samp{.align 3} advances the location counter until it a multiple of 8. If the location counter is already a @@ -5864,6 +5891,9 @@ include details on any machine's instruc subject, see the hardware manufacturer's manual. @menu +@ifset NIOSII +* NiosII-Dependent:: Altera Nios II Dependent Features +@end ifset @ifset A29K * AMD29K-Dependent:: AMD 29K Dependent Features @end ifset @@ -5974,6 +6004,11 @@ subject, see the hardware manufacturer's @c node and sectioning commands; hence the repetition of @chapter BLAH @c in both conditional blocks. + +@ifset NIOSII +@include c-nios2.texi +@end ifset + @ifset A29K @include c-a29k.texi @end ifset --- binutils-2.15/gas/doc/c-nios2.texi 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/gas/doc/c-nios2.texi 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,214 @@ +@c Copyright 2004 +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@ifset GENERIC +@page +@node NiosII-Dependent +@chapter Altera Nios II Dependent Features +@end ifset +@ifclear GENERIC +@node Machine Dependencies +@chapter ltera Nios II Dependent Features +@end ifclear + +@cindex Altera Nios II support +@cindex Nios support +@cindex Nios II support +@menu +* Nios II Options:: Options +* Nios II Syntax:: Syntax +* Nios II Relocations:: Relocations +* Nios II Directives:: Nios II Machine Directives +* Nios II Opcodes:: Opcodes +@end menu + +@node Nios II Options +@section Options +@cindex Nios II options +@cindex options for Nios II + +@table @code + +@cindex @code{relax-all} command line option, Nios II +@item -relax-all +Replace all branch and call instructions with @code{jmp} and @code{callr} sequences + +@cindex @code{relax-section} command line option, Nios II +@item -relax-section +Replace identified out of range branches with @code{jmp} sequences (default) + +@cindex @code{no-relax} command line option, Nios II +@item -no-relax +Do not replace any branches or calls + +@end table + + +@node Nios II Syntax +@section Syntax +@menu +* Nios II Chars:: Special Characters +@end menu + + +@node Nios II Chars +@subsection Special Characters + +@cindex line comment character, Nios II +@cindex Nios II line comment character +@samp{#} is the line comment character. + +@cindex line separator character, Nios II +@cindex Nios II line separator character +@samp{;} is the line separator character. + + +@node Nios II Relocations +@section Nios II Machine Relocations + +@cindex machine relocations, Nios II +@cindex Nios II machine relocations + +@table @code +@cindex @code{hiadj} directive, Nios II +@item %hiadj(@var{expression}) +Extract the upper 16-bits of @var{expression} and add +one if the 15th bit is set. + +The value of %hiadj is: +((@var{expression} >> 16) & 0xffff) + ((@var{expression} >> 15) & 0x01). + +The intention of the @code{%hiadj} relocation is to be used with +an @code{addi}, @code{ld} or @code{st} instructions +along with a @code{%lo}. + +@smallexample +movhi r2, %hiadj(symbol) +addi r2, r2, %lo(symbol) +@end smallexample + +@cindex @code{hi} directive, Nios II +@item %hi(@var{expression}) +Extract the upper 16-bits of @var{expression}. + + +@cindex @code{lo} directive, Nios II +@item %lo(@var{expression}) +Extract the lower 16-bits of @var{expression}. + + +@cindex @code{gprel} directive, Nios II +@item %gprel(@var{expression}) +Subtract the value of the symbol @code{_gp} from +@var{expression}. + +The intention of the @code{%gprel} relocation is +to have a fast small area of memory which only +takes a 16-bit immediate to access. + +@smallexample + .section .sdata +fastint: + .int 123 + .section .text + ldw r4, %gprel(fastint)(gp) +@end smallexample + + +@end table + + +@node Nios II Directives +@section Nios II Machine Directives + +@cindex machine directives, Nios II +@cindex Nios II machine directives + +@table @code + +@cindex @code{align} directive, Nios II +@item .align @var{expression} [, @var{expression}] +This is the generic @var{.align} directive, however +this aligns to a power of two. + +@cindex @code{half} directive, Nios II +@item .half @var{expression} +Create an aligned constant 2-bytes in size + +@cindex @code{word} directive, Nios II +@item .word @var{expression} +Create an aligned constant 4-bytes in size + +@cindex @code{dword} directive, Nios II +@item .dword @var{expression} +Create an aligned constant 8-bytes in size + +@cindex @code{2byte} directive, Nios II +@item .2byte @var{expression} +Create an un-aligned constant 2-bytes in size + +@cindex @code{4byte} directive, Nios II +@item .4byte @var{expression} +Create an un-aligned constant 4-bytes in size + +@cindex @code{8byte} directive, Nios II +@item .8byte @var{expression} +Create an un-aligned constant 8-bytes in size + +@cindex @code{16byte} directive, Nios II +@item .16byte @var{expression} +Create an un-aligned constant 16-bytes in size + +@cindex @code{set noat} directive, Nios II +@item .set noat +Allows assembly code to use @code{at} register without +warning and macro or relaxation expansions will +generate a warning. + +@cindex @code{set at} directive, Nios II +@item .set at +Assembly code using @code{at} register will generate +warnings, and macro expansion and relaxation will be +enabled. + +@cindex @code{set nobreak} directive, Nios II +@item .set nobreak +Allows assembly code to use @code{ba}, @code{bt}, +registers without warning. + +@cindex @code{set break} directive, Nios II +@item .set break +Turns warnings back on for using @code{ba}, @code{bt} +registers. + +@cindex @code{set norelax} directive, Nios II +@item .set norelax +Do not replace any branches or calls. + +@cindex @code{set relaxsection} directive, Nios II +@item .set relaxsection +Replace identified out of range branches with +@code{jmp} sequences (default). + +@cindex @code{set relaxall} directive, Nios II +@item .set relaxsection +Replace all branch and call instructions with +@code{jmp} and @code{callr} sequences. + +@cindex @code{set} directive, Nios II +@item .set @dots{} +All other @code{.set} are the normal use. + +@end table + +@node Nios II Opcodes +@section Opcodes + +@cindex Nios II opcodes +@cindex opcodes for Nios II +@code{@value{AS}} implements all the standard Nios II opcodes. No +additional pseudo-instructions are needed on this family. + +For information on the Nios II machine instruction set, see the @cite{Nios II +User's Manual} + --- binutils-2.15/gas/testsuite/gas/macros/irp.s 1999-06-10 15:48:35.000000000 +0200 +++ binutils-2.15-nios2/gas/testsuite/gas/macros/irp.s 2005-05-17 12:20:13.000000000 +0200 @@ -1,3 +1,4 @@ + .set norelax .irp param,1,2,3 .long foo\param .endr --- binutils-2.15/gas/testsuite/gas/macros/rept.s 1999-06-10 15:48:39.000000000 +0200 +++ binutils-2.15-nios2/gas/testsuite/gas/macros/rept.s 2005-05-17 12:20:13.000000000 +0200 @@ -1,3 +1,4 @@ + .set norelax .rept 3 .long foo1 .endr --- binutils-2.15/gas/testsuite/gas/macros/test2.s 2004-02-06 17:00:21.000000000 +0100 +++ binutils-2.15-nios2/gas/testsuite/gas/macros/test2.s 2005-05-17 12:20:13.000000000 +0200 @@ -1,3 +1,4 @@ + .set norelax .macro m arg1 arg2 arg3 .long \arg1 .ifc ,\arg2\arg3 --- binutils-2.15/gas/testsuite/gas/macros/test3.s 1999-06-10 15:48:44.000000000 +0200 +++ binutils-2.15-nios2/gas/testsuite/gas/macros/test3.s 2005-05-17 12:20:13.000000000 +0200 @@ -1,3 +1,4 @@ + .set norelax .macro m arg1 arg2 \arg1 .exitm --- binutils-2.15/gas/testsuite/gas/nios2/add.d 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/gas/testsuite/gas/nios2/add.d 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,16 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 add + +# Test the add instruction + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> add r4,r4,r4 +0+0004 <[^>]*> addi r4,r4,32767 +0+0008 <[^>]*> addi r4,r4,-32768 +0+000c <[^>]*> addi r4,r4,0 +0+0010 <[^>]*> addi r4,r4,-1 +0+0014 <[^>]*> addi r4,r4,-1 +0+0018 <[^>]*> addi r4,r4,13398 +0+001c <[^>]*> nop --- binutils-2.15/gas/testsuite/gas/nios2/add.s 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/gas/testsuite/gas/nios2/add.s 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,13 @@ +# Source file used to test the add and addi instructions. + +foo: + add r4,r4,r4 + addi r4,r4,0x7fff + addi r4,r4,-0x8000 + addi r4,r4,0x0 + addi r4,r4,-0x01 + subi r4,r4,0x01 + addi r4,r4,0x3456 + +# should disassemble to add r0,0,r0 + nop --- binutils-2.15/gas/testsuite/gas/nios2/align_fill.d 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/gas/testsuite/gas/nios2/align_fill.d 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,23 @@ +#objdump: -dr --prefix-addresses +#name: NIOS2 align_fill + +# Test the and macro. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +0+0000 <[^>]*> addi sp,sp,-8 +0+0004 <[^>]*> stw fp,4\(sp\) +0+0008 <[^>]*> mov fp,sp +0+000c <[^>]*> mov r3,zero +0+0010 <[^>]*> nop +0+0014 <[^>]*> nop +0+0018 <[^>]*> nop +0+001c <[^>]*> nop +0+0020 <[^>]*> addi r3,r3,1 +0+0024 <[^>]*> cmplti r2,r3,100 +0+0028 <[^>]*> bne r2,zero,0+0020 <[^>*]*> +0+002c <[^>]*> ldw fp,4\(sp\) +0+0030 <[^>]*> addi sp,sp,8 +0+0034 <[^>]*> ret + ... --- binutils-2.15/gas/testsuite/gas/nios2/align_fill.s 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/gas/testsuite/gas/nios2/align_fill.s 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,20 @@ + .file "a.c" + .section .text + .align 3 + .global x + .type x, @function +x: + addi sp, sp, -8 + stw fp, 4(sp) + mov fp, sp + mov r3, zero + .align 5 +.L6: + addi r3, r3, 1 + cmplti r2, r3, 100 + bne r2, zero, .L6 + ldw fp, 4(sp) + addi sp, sp, 8 + ret + .size x, .-x + .ident "GCC: (GNU) 3.3.3 (Altera Nios II 1.0 b302)" --- binutils-2.15/gas/testsuite/gas/nios2/align_text.d 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.15-nios2/gas/testsuite/gas/nios2/align_text.d 2005-05-17 12:20:13.000000000 +0200 @@ -0,0 +1,22 @@ +#objdump: -dr +#name: NIOS2 align_test + +# Test alignment in text sections. + +.*: +file format elf32-littlenios2 + +Disassembly of section .text: +00000000 : + 0: 00000000 call 0 + 4: 0001883a nop + 8: 0001883a nop + c: 0001883a nop + 10: 0001883a nop + 14: 0001883a nop + 18: 0001883a nop + 1c: 0001883a nop + +00000020