forked from OSchip/llvm-project
[Object] Support reading 64-bit MIPS ELF archives
The 64-bit MIPS ELF archive file format is used by MIPS64 targets. The main difference from a regular archive file is the symbol table format: 1. ar_name is equal to "/SYM64/" 2. number of symbols and offsets are 64-bit integers http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf Page 96 The patch allows reading of such archive files by llvm-nm, llvm-objdump and other tools. But it does not support archive files with number of symbols and/or offsets exceed 2^32. I think it is a rather rare case requires more significant modification of `Archive` class code. http://reviews.llvm.org/D7546 llvm-svn: 229520
This commit is contained in:
parent
79df187034
commit
1d902b7cc7
|
@ -178,6 +178,7 @@ public:
|
|||
|
||||
enum Kind {
|
||||
K_GNU,
|
||||
K_MIPS64,
|
||||
K_BSD,
|
||||
K_COFF
|
||||
};
|
||||
|
|
|
@ -162,7 +162,7 @@ ErrorOr<StringRef> Archive::Child::getName() const {
|
|||
return object_error::parse_failed;
|
||||
|
||||
// GNU long file names end with a /.
|
||||
if (Parent->kind() == K_GNU) {
|
||||
if (Parent->kind() == K_GNU || Parent->kind() == K_MIPS64) {
|
||||
StringRef::size_type End = StringRef(addr).find('/');
|
||||
return StringRef(addr, End);
|
||||
}
|
||||
|
@ -273,8 +273,16 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec)
|
|||
return;
|
||||
}
|
||||
|
||||
if (Name == "/") {
|
||||
// MIPS 64-bit ELF archives use a special format of a symbol table.
|
||||
// This format is marked by `ar_name` field equals to "/SYM64/".
|
||||
// For detailed description see page 96 in the following document:
|
||||
// http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf
|
||||
|
||||
bool has64SymTable = false;
|
||||
if (Name == "/" || Name == "/SYM64/") {
|
||||
SymbolTable = i;
|
||||
if (Name == "/SYM64/")
|
||||
has64SymTable = true;
|
||||
|
||||
++i;
|
||||
if (i == e) {
|
||||
|
@ -285,7 +293,7 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec)
|
|||
}
|
||||
|
||||
if (Name == "//") {
|
||||
Format = K_GNU;
|
||||
Format = has64SymTable ? K_MIPS64 : K_GNU;
|
||||
StringTable = i;
|
||||
++i;
|
||||
FirstRegular = i;
|
||||
|
@ -294,7 +302,7 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec)
|
|||
}
|
||||
|
||||
if (Name[0] != '/') {
|
||||
Format = K_GNU;
|
||||
Format = has64SymTable ? K_MIPS64 : K_GNU;
|
||||
FirstRegular = i;
|
||||
ec = object_error::success;
|
||||
return;
|
||||
|
@ -348,11 +356,18 @@ StringRef Archive::Symbol::getName() const {
|
|||
|
||||
ErrorOr<Archive::child_iterator> Archive::Symbol::getMember() const {
|
||||
const char *Buf = Parent->SymbolTable->getBuffer().begin();
|
||||
const char *Offsets = Buf + 4;
|
||||
const char *Offsets = Buf;
|
||||
if (Parent->kind() == K_MIPS64)
|
||||
Offsets += sizeof(uint64_t);
|
||||
else
|
||||
Offsets += sizeof(uint32_t);
|
||||
uint32_t Offset = 0;
|
||||
if (Parent->kind() == K_GNU) {
|
||||
Offset =
|
||||
*(reinterpret_cast<const support::ubig32_t *>(Offsets) + SymbolIndex);
|
||||
} else if (Parent->kind() == K_MIPS64) {
|
||||
Offset =
|
||||
*(reinterpret_cast<const support::ubig64_t *>(Offsets) + SymbolIndex);
|
||||
} else if (Parent->kind() == K_BSD) {
|
||||
// The SymbolIndex is an index into the ranlib structs that start at
|
||||
// Offsets (the first uint32_t is the number of bytes of the ranlib
|
||||
|
@ -449,6 +464,9 @@ Archive::symbol_iterator Archive::symbol_begin() const {
|
|||
uint32_t symbol_count = 0;
|
||||
symbol_count = *reinterpret_cast<const support::ubig32_t*>(buf);
|
||||
buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t)));
|
||||
} else if (kind() == K_MIPS64) {
|
||||
uint64_t symbol_count = *reinterpret_cast<const support::ubig64_t *>(buf);
|
||||
buf += sizeof(uint64_t) + (symbol_count * (sizeof(uint64_t)));
|
||||
} else if (kind() == K_BSD) {
|
||||
// The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t
|
||||
// which is the number of bytes of ranlib structs that follow. The ranlib
|
||||
|
@ -486,6 +504,8 @@ Archive::symbol_iterator Archive::symbol_end() const {
|
|||
uint32_t symbol_count = 0;
|
||||
if (kind() == K_GNU) {
|
||||
symbol_count = *reinterpret_cast<const support::ubig32_t*>(buf);
|
||||
} else if (kind() == K_MIPS64) {
|
||||
symbol_count = *reinterpret_cast<const support::ubig64_t*>(buf);
|
||||
} else if (kind() == K_BSD) {
|
||||
symbol_count = (*reinterpret_cast<const support::ulittle32_t *>(buf)) /
|
||||
(sizeof(uint32_t) * 2);
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,27 @@
|
|||
# Check reading IRIX 6.0 64-bit archive file.
|
||||
RUN: llvm-nm %p/Inputs/archive-test.a-irix6-mips64el | FileCheck %s
|
||||
|
||||
CHECK: f1.o:
|
||||
CHECK-NEXT: 00000028 T f1
|
||||
CHECK-NEXT: 00000000 d s_d
|
||||
CHECK-NEXT: 00000000 t s_foo
|
||||
|
||||
CHECK: f2.o:
|
||||
CHECK-NEXT: 00000028 T f2
|
||||
CHECK-NEXT: 00000000 d s_d
|
||||
CHECK-NEXT: 00000000 t s_foo
|
||||
|
||||
CHECK: f3.o:
|
||||
CHECK-NEXT: 00000028 T f3
|
||||
CHECK-NEXT: 00000000 d s_d
|
||||
CHECK-NEXT: 00000000 t s_foo
|
||||
|
||||
CHECK: f4.o:
|
||||
CHECK-NEXT: 00000028 T f4
|
||||
CHECK-NEXT: 00000000 d s_d
|
||||
CHECK-NEXT: 00000000 t s_foo
|
||||
|
||||
CHECK: f5.o:
|
||||
CHECK-NEXT: 00000028 T f5
|
||||
CHECK-NEXT: 00000000 d s_d
|
||||
CHECK-NEXT: 00000000 t s_foo
|
Loading…
Reference in New Issue