cpu-ns32k.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 845 行 · 第 1/2 页
C
845 行
/* BFD support for the ns32k architecture. Copyright 1990, 1991, 1994, 1995, 1998, 2000 Free Software Foundation, Inc. Almost totally rewritten by Ian Dall from initial work by Andrew Cagney.This file is part of BFD, the Binary File Descriptor library.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "bfd.h"#include "sysdep.h"#include "libbfd.h"#include "ns32k.h"#define N(machine, printable, d, next) \{ 32, 32, 8, bfd_arch_ns32k, machine, "ns32k",printable,3,d,bfd_default_compatible,bfd_default_scan, next, }static const bfd_arch_info_type arch_info_struct[] ={ N(32532,"ns32k:32532",true, 0), /* the word ns32k will match this too */};const bfd_arch_info_type bfd_ns32k_arch = N(32032,"ns32k:32032",false, &arch_info_struct[0]);static longns32k_sign_extend(value, bits) int value; int bits;{ value = value & ((1 << bits) - 1); return (value & (1 << (bits-1)) ? value | (~((1 << bits) - 1)) : value);}long_bfd_ns32k_get_displacement(buffer, offset, size) bfd_byte *buffer; long offset; long size;{ long value; buffer += offset; switch (size) { case 1: value = ns32k_sign_extend (*buffer, 7); break; case 2: value = ns32k_sign_extend(*buffer++, 6); value = (value << 8) | (0xff & *buffer); break; case 4: value = ns32k_sign_extend(*buffer++, 6); value = (value << 8) | (0xff & *buffer++); value = (value << 8) | (0xff & *buffer++); value = (value << 8) | (0xff & *buffer); break; default: abort (); return 0; } return value;}int_bfd_ns32k_put_displacement(value, buffer, offset, size) long value; bfd_byte *buffer; long offset; long size;{ buffer += offset; switch (size) { case 1: if (value < -64 || value > 63) return -1; value&=0x7f; *buffer++=value; break; case 2: if (value < -8192 || value > 8191) return -1; value&=0x3fff; value|=0x8000; *buffer++=(value>>8); *buffer++=value; break; case 4: if (value < -0x1f000000 || value >= 0x20000000) return -1; value|=0xc0000000; *buffer++=(value>>24); *buffer++=(value>>16); *buffer++=(value>>8); *buffer++=value; break; default: return -1; } return 0;}long_bfd_ns32k_get_immediate (buffer, offset, size) bfd_byte *buffer; long offset; long size;{ long value = 0; buffer += offset; switch (size) { case 4: value = (value << 8) | (*buffer++ & 0xff); case 3: value = (value << 8) | (*buffer++ & 0xff); case 2: value = (value << 8) | (*buffer++ & 0xff); case 1: value = (value << 8) | (*buffer++ & 0xff); } return value;}int_bfd_ns32k_put_immediate (value, buffer, offset, size) long value; bfd_byte *buffer; long offset; long size;{ buffer += offset + size - 1; switch (size) { case 4: *buffer-- = (value & 0xff); value >>= 8; case 3: *buffer-- = (value & 0xff); value >>= 8; case 2: *buffer-- = (value & 0xff); value >>= 8; case 1: *buffer-- = (value & 0xff); value >>= 8; } return 0;}/* This is just like the standard perform_relocation except we * use get_data and put_data which know about the ns32k * storage methods. * This is probably a lot more complicated than it needs to be! */static bfd_reloc_status_typedo_ns32k_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message, get_data, put_data) bfd *abfd; arelent *reloc_entry; struct symbol_cache_entry *symbol; PTR data; asection *input_section; bfd *output_bfd; char **error_message ATTRIBUTE_UNUSED; long (*get_data) (); int (*put_data) ();{ int overflow = 0; bfd_vma relocation; bfd_reloc_status_type flag = bfd_reloc_ok; bfd_size_type addr = reloc_entry->address; bfd_vma output_base = 0; reloc_howto_type *howto = reloc_entry->howto; asection *reloc_target_output_section; if ((symbol->section == &bfd_abs_section) && output_bfd != (bfd *) NULL) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; } /* If we are not producing relocateable output, return an error if the symbol is not defined. An undefined weak symbol is considered to have a value of zero (SVR4 ABI, p. 4-27). */ if (symbol->section == &bfd_und_section && (symbol->flags & BSF_WEAK) == 0 && output_bfd == (bfd *) NULL) flag = bfd_reloc_undefined; /* Is the address of the relocation really within the section? */ if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; /* Work out which section the relocation is targetted at and the initial relocation command value. */ /* Get symbol value. (Common symbols are special.) */ if (bfd_is_com_section (symbol->section)) relocation = 0; else relocation = symbol->value; reloc_target_output_section = symbol->section->output_section; /* Convert input-section-relative symbol value to absolute. */ if (output_bfd && howto->partial_inplace == false) output_base = 0; else output_base = reloc_target_output_section->vma; relocation += output_base + symbol->section->output_offset; /* Add in supplied addend. */ relocation += reloc_entry->addend; /* Here the variable relocation holds the final address of the symbol we are relocating against, plus any addend. */ if (howto->pc_relative == true) { /* This is a PC relative relocation. We want to set RELOCATION to the distance between the address of the symbol and the location. RELOCATION is already the address of the symbol. We start by subtracting the address of the section containing the location. If pcrel_offset is set, we must further subtract the position of the location within the section. Some targets arrange for the addend to be the negative of the position of the location within the section; for example, i386-aout does this. For i386-aout, pcrel_offset is false. Some other targets do not include the position of the location; for example, m88kbcs, or ELF. For those targets, pcrel_offset is true. If we are producing relocateable output, then we must ensure that this reloc will be correctly computed when the final relocation is done. If pcrel_offset is false we want to wind up with the negative of the location within the section, which means we must adjust the existing addend by the change in the location within the section. If pcrel_offset is true we do not want to adjust the existing addend at all. FIXME: This seems logical to me, but for the case of producing relocateable output it is not what the code actually does. I don't want to change it, because it seems far too likely that something will break. */ relocation -= input_section->output_section->vma + input_section->output_offset; if (howto->pcrel_offset == true) relocation -= reloc_entry->address; } if (output_bfd != (bfd *) NULL) { if (howto->partial_inplace == false) { /* This is a partial relocation, and we want to apply the relocation to the reloc entry rather than the raw data. Modify the reloc inplace to reflect what we now know. */ reloc_entry->addend = relocation; reloc_entry->address += input_section->output_offset; return flag; } else { /* This is a partial relocation, but inplace, so modify the reloc record a bit. If we've relocated with a symbol with a section, change into a ref to the section belonging to the symbol. */ reloc_entry->address += input_section->output_offset; /* WTF?? */ if (abfd->xvec->flavour == bfd_target_coff_flavour) {#if 1 /* For m68k-coff, the addend was being subtracted twice during relocation with -r. Removing the line below this comment fixes that problem; see PR 2953.However, Ian wrote the following, regarding removing the line below,which explains why it is still enabled: --djmIf you put a patch like that into BFD you need to check all the COFFlinkers. I am fairly certain that patch will break coff-i386 (e.g.,SCO); see coff_i386_reloc in coff-i386.c where I worked around theproblem in a different way. There may very well be a reason that thecode works as it does.Hmmm. The first obvious point is that bfd_perform_relocation shouldnot have any tests that depend upon the flavour. It's seem likeentirely the wrong place for such a thing. The second obvious pointis that the current code ignores the reloc addend when producingrelocateable output for COFF. That's peculiar. In fact, I reallyhave no idea what the point of the line you want to remove is.A typical COFF reloc subtracts the old value of the symbol and adds inthe new value to the location in the object file (if it's a pcrelative reloc it adds the difference between the symbol value and thelocation). When relocating we need to preserve that property.BFD handles this by setting the addend to the negative of the oldvalue of the symbol. Unfortunately it handles common symbols in anon-standard way (it doesn't subtract the old value) but that's adifferent story (we can't change it without losing backwardcompatibility with old object files) (coff-i386 does subtract the oldvalue, to be compatible with existing coff-i386 targets, like SCO).So everything works fine when not producing relocateable output. Whenwe are producing relocateable output, logically we should do exactlywhat we do when not producing relocateable output. Therefore, yourpatch is correct. In fact, it should probably always just setreloc_entry->addend to 0 for all cases, since it is, in fact, going toadd the value into the object file. This won't hurt the COFF code,which doesn't use the addend; I'm not sure what it will do to otherformats (the thing to check for would be whether any formats both usethe addend and set partial_inplace).When I wanted to make coff-i386 produce relocateable output, I raninto the problem that you are running into: I wanted to remove thatline. Rather than risk it, I made the coff-i386 relocs use a specialfunction; it's coff_i386_reloc in coff-i386.c. The functionspecifically adds the addend field into the object file, knowing thatbfd_perform_relocation is not going to. If you remove that line, thencoff-i386.c will wind up adding the addend field in twice. It'strivial to fix; it just needs to be done.The problem with removing the line is just that it may break someworking code. With BFD it's hard to be sure of anything. The rightway to deal with this is simply to build and test at least all thesupported COFF targets. It should be straightforward if time and diskspace consuming. For each target: 1) build the linker 2) generate some executable, and link it using -r (I would probably use paranoia.o and link against newlib/libc.a, which for all the supported targets would be available in /usr/cygnus/progressive/H-host/target/lib/libc.a). 3) make the change to reloc.c 4) rebuild the linker 5) repeat step 2 6) if the resulting object files are the same, you have at least made it no worse 7) if they are different you have to figure out which version is right*/ relocation -= reloc_entry->addend;#endif reloc_entry->addend = 0; } else { reloc_entry->addend = relocation; } } } else { reloc_entry->addend = 0; } /* FIXME: This overflow checking is incomplete, because the value might have overflowed before we get here. For a correct check we need to compute the value in a size larger than bitsize, but we can't reasonably do that for a reloc the same size as a host machine word. FIXME: We should also do overflow checking on the result after adding in the value contained in the object file. */ if (howto->complain_on_overflow != complain_overflow_dont) { bfd_vma check; /* Get the value that will be used for the relocation, but starting at bit position zero. */ if (howto->rightshift > howto->bitpos) check = relocation >> (howto->rightshift - howto->bitpos); else check = relocation << (howto->bitpos - howto->rightshift); switch (howto->complain_on_overflow) { case complain_overflow_signed: { /* Assumes two's complement. */ bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; bfd_signed_vma reloc_signed_min = ~reloc_signed_max; /* The above right shift is incorrect for a signed value. Fix it up by forcing on the upper bits. */ if (howto->rightshift > howto->bitpos && (bfd_signed_vma) relocation < 0) check |= ((bfd_vma) - 1 & ~((bfd_vma) - 1 >> (howto->rightshift - howto->bitpos))); if ((bfd_signed_vma) check > reloc_signed_max || (bfd_signed_vma) check < reloc_signed_min) flag = bfd_reloc_overflow; } break; case complain_overflow_unsigned: { /* Assumes two's complement. This expression avoids overflow if howto->bitsize is the number of bits in bfd_vma. */ bfd_vma reloc_unsigned_max = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?