The ELF relocation record format is different for N64

which many Mips 64 ABIs use than for O64 which many 
if not all other target ABIs use.

Most architectures have the following 64 bit relocation record format:

  typedef struct
  {
    Elf64_Addr   r_offset; /* Address of reference */
    Elf64_Xword  r_info;   /* Symbol index and type of relocation */
  } Elf64_Rel;

  typedef struct
  {
    Elf64_Addr    r_offset;
    Elf64_Xword   r_info;
    Elf64_Sxword  r_addend;
  } Elf64_Rela;

Whereas N64 has the following format:

  typedef struct
  {
    Elf64_Addr    r_offset;/* Address of reference */
    Elf64_Word  r_sym;     /* Symbol index */
    Elf64_Byte  r_ssym;    /* Special symbol */
    Elf64_Byte  r_type3;   /* Relocation type */
    Elf64_Byte  r_type2;   /* Relocation type */
    Elf64_Byte  r_type;    /* Relocation type */
  } Elf64_Rel;

  typedef struct
  {
    Elf64_Addr    r_offset;/* Address of reference */
    Elf64_Word  r_sym;     /* Symbol index */
    Elf64_Byte  r_ssym;    /* Special symbol */
    Elf64_Byte  r_type3;   /* Relocation type */
    Elf64_Byte  r_type2;   /* Relocation type */
    Elf64_Byte  r_type;    /* Relocation type */
    Elf64_Sxword  r_addend;
  } Elf64_Rela;

The structure is the same size, but the r_info data element 
is now 5 separate elements. Besides the content aspects, 
endian byte reordering will be different for the area with 
each element being endianized separately.

I treat this as generic and continue to pass r_type as 
an integer masking and unmasking the byte sized N64 
values for N64 mode. I've implemented this and it causes no 
affect on other current targets.

This passes make check.

Jack

llvm-svn: 159299
This commit is contained in:
Jack Carter 2012-06-27 22:28:30 +00:00
parent fed39aa653
commit 8ad0c272af
4 changed files with 67 additions and 13 deletions

View File

@ -54,11 +54,13 @@ class MCELFObjectTargetWriter {
const uint16_t EMachine;
const unsigned HasRelocationAddend : 1;
const unsigned Is64Bit : 1;
const unsigned IsN64 : 1;
protected:
MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_,
uint16_t EMachine_, bool HasRelocationAddend_);
uint16_t EMachine_, bool HasRelocationAddend,
bool IsN64=false);
public:
static uint8_t getOSABI(Triple::OSType OSType) {
@ -95,7 +97,47 @@ public:
uint16_t getEMachine() { return EMachine; }
bool hasRelocationAddend() { return HasRelocationAddend; }
bool is64Bit() const { return Is64Bit; }
bool isN64() const { return IsN64; }
/// @}
// Instead of changing everyone's API we pack the N64 Type fields
// into the existing 32 bit data unsigned.
#define R_TYPE_SHIFT 0
#define R_TYPE_MASK 0xffffff00
#define R_TYPE2_SHIFT 8
#define R_TYPE2_MASK 0xffff00ff
#define R_TYPE3_SHIFT 16
#define R_TYPE3_MASK 0xff00ffff
#define R_SSYM_SHIFT 24
#define R_SSYM_MASK 0x00ffffff
// N64 relocation type accessors
unsigned getRType(uint32_t Type) const {
return (unsigned)((Type >> R_TYPE_SHIFT) & 0xff);
}
unsigned getRType2(uint32_t Type) const {
return (unsigned)((Type >> R_TYPE2_SHIFT) & 0xff);
}
unsigned getRType3(uint32_t Type) const {
return (unsigned)((Type >> R_TYPE3_SHIFT) & 0xff);
}
unsigned getRSsym(uint32_t Type) const {
return (unsigned)((Type >> R_SSYM_SHIFT) & 0xff);
}
// N64 relocation type setting
unsigned setRType(unsigned Value, unsigned Type) const {
return ((Type & R_TYPE_MASK) | ((Value & 0xff) << R_TYPE_SHIFT));
}
unsigned setRType2(unsigned Value, unsigned Type) const {
return (Type & R_TYPE2_MASK) | ((Value & 0xff) << R_TYPE2_SHIFT);
}
unsigned setRType3(unsigned Value, unsigned Type) const {
return (Type & R_TYPE3_MASK) | ((Value & 0xff) << R_TYPE3_SHIFT);
}
unsigned setRSsym(unsigned Value, unsigned Type) const {
return (Type & R_SSYM_MASK) | ((Value & 0xff) << R_SSYM_SHIFT);
}
};
/// \brief Construct a new ELF writer instance.

View File

@ -1061,11 +1061,19 @@ void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm,
entry.Index += LocalSymbolData.size();
if (is64Bit()) {
String64(*F, entry.r_offset);
if (TargetObjectWriter->isN64()) {
String32(*F, entry.Index);
struct ELF::Elf64_Rela ERE64;
ERE64.setSymbolAndType(entry.Index, entry.Type);
String64(*F, ERE64.r_info);
String8(*F, TargetObjectWriter->getRSsym(entry.Type));
String8(*F, TargetObjectWriter->getRType3(entry.Type));
String8(*F, TargetObjectWriter->getRType2(entry.Type));
String8(*F, TargetObjectWriter->getRType(entry.Type));
}
else {
struct ELF::Elf64_Rela ERE64;
ERE64.setSymbolAndType(entry.Index, entry.Type);
String64(*F, ERE64.r_info);
}
if (hasRelocationAddend())
String64(*F, entry.r_addend);
} else {

View File

@ -15,9 +15,11 @@ using namespace llvm;
MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_,
uint8_t OSABI_,
uint16_t EMachine_,
bool HasRelocationAddend_)
bool HasRelocationAddend_,
bool IsN64_)
: OSABI(OSABI_), EMachine(EMachine_),
HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_) {
HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_),
IsN64(IsN64_){
}
/// Default e_flags = 0

View File

@ -34,7 +34,7 @@ namespace {
class MipsELFObjectWriter : public MCELFObjectTargetWriter {
public:
MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI);
MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI, bool _isN64);
virtual ~MipsELFObjectWriter();
@ -52,9 +52,11 @@ namespace {
};
}
MipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI)
MipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI,
bool _isN64)
: MCELFObjectTargetWriter(_is64Bit, OSABI, ELF::EM_MIPS,
/*HasRelocationAddend*/ false) {}
/*HasRelocationAddend*/ false,
/*IsN64*/ _isN64) {}
MipsELFObjectWriter::~MipsELFObjectWriter() {}
@ -149,7 +151,6 @@ unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target,
Type = ELF::R_MIPS_PC16;
break;
}
return Type;
}
@ -184,7 +185,7 @@ static int CompareOffset(const RelEntry &R0, const RelEntry &R1) {
void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm,
std::vector<ELFRelocationEntry> &Relocs) {
// Call the defualt function first. Relocations are sorted in descending
// Call the default function first. Relocations are sorted in descending
// order of r_offset.
MCELFObjectTargetWriter::sortRelocs(Asm, Relocs);
@ -244,6 +245,7 @@ MCObjectWriter *llvm::createMipsELFObjectWriter(raw_ostream &OS,
uint8_t OSABI,
bool IsLittleEndian,
bool Is64Bit) {
MCELFObjectTargetWriter *MOTW = new MipsELFObjectWriter(Is64Bit, OSABI);
MCELFObjectTargetWriter *MOTW = new MipsELFObjectWriter(Is64Bit, OSABI,
(Is64Bit) ? true : false);
return createELFObjectWriter(MOTW, OS, IsLittleEndian);
}