1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[yaml2obj][obj2yaml] - Use a single "Other" field instead of "Other", "Visibility" and "StOther".

Currenly we can encode the 'st_other' field of symbol using 3 fields.
'Visibility' is used to encode STV_* values.
'Other' is used to encode everything except the visibility, but it can't handle arbitrary values.
'StOther' is used to encode arbitrary values when 'Visibility'/'Other' are not helpfull enough.

'st_other' field is used to encode symbol visibility and platform-dependent
flags and values. Problem to encode it is that it consists of Visibility part (STV_* values)
which are enumeration values and the Other part, which is different and inconsistent.

For MIPS the Other part contains flags for all STO_MIPS_* values except STO_MIPS_MIPS16.
(Like comment in ELFDumper says: "Someones in their infinite wisdom decided to make
STO_MIPS_MIPS16 flag overlapped with other ST_MIPS_xxx flags."...)

And for PPC64 the Other part might actually encode any value.

This patch implements custom logic for handling the st_other and removes
'Visibility' and 'StOther' fields.

Here is an example of a new YAML style this patch allows:

- Name:  foo
  Other: [ 0x4 ]
- Name:  bar
  Other: [ STV_PROTECTED, 4 ]
- Name:  zed
  Other: [ STV_PROTECTED, STO_MIPS_OPTIONAL, 0xf8 ]

Differential revision: https://reviews.llvm.org/D66886

llvm-svn: 370472
This commit is contained in:
George Rimar 2019-08-30 13:39:22 +00:00
parent fc6d78bba9
commit fa73d7c8a9
12 changed files with 182 additions and 188 deletions

View File

@ -54,8 +54,6 @@ LLVM_YAML_STRONG_TYPEDEF(uint64_t, ELF_SHF)
LLVM_YAML_STRONG_TYPEDEF(uint16_t, ELF_SHN)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STB)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STT)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STV)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STO)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_AFL_REG)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_ABI_FP)
@ -108,11 +106,6 @@ struct Symbol {
llvm::yaml::Hex64 Value;
llvm::yaml::Hex64 Size;
Optional<uint8_t> Other;
// This can be used to set any custom value for the st_other field
// when it is not possible to do so using the "Other" field, which only takes
// specific named constants.
Optional<uint8_t> StOther;
};
struct SectionOrType {
@ -401,16 +394,6 @@ struct ScalarEnumerationTraits<ELFYAML::ELF_STT> {
static void enumeration(IO &IO, ELFYAML::ELF_STT &Value);
};
template <>
struct ScalarEnumerationTraits<ELFYAML::ELF_STV> {
static void enumeration(IO &IO, ELFYAML::ELF_STV &Value);
};
template <>
struct ScalarBitSetTraits<ELFYAML::ELF_STO> {
static void bitset(IO &IO, ELFYAML::ELF_STO &Value);
};
template <>
struct ScalarEnumerationTraits<ELFYAML::ELF_REL> {
static void enumeration(IO &IO, ELFYAML::ELF_REL &Value);

View File

@ -748,7 +748,7 @@ public:
IO(void *Ctxt = nullptr);
virtual ~IO();
virtual bool outputting() = 0;
virtual bool outputting() const = 0;
virtual unsigned beginSequence() = 0;
virtual bool preflightElement(unsigned, void *&) = 0;
@ -842,7 +842,7 @@ public:
Val = Val | ConstVal;
}
void *getContext();
void *getContext() const;
void setContext(void *);
template <typename T> void mapRequired(const char *Key, T &Val) {
@ -1402,7 +1402,7 @@ public:
std::error_code error();
private:
bool outputting() override;
bool outputting() const override;
bool mapTag(StringRef, bool) override;
void beginMapping() override;
void endMapping() override;
@ -1549,7 +1549,7 @@ public:
/// anyway.
void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; }
bool outputting() override;
bool outputting() const override;
bool mapTag(StringRef, bool) override;
void beginMapping() override;
void endMapping() override;

View File

@ -464,12 +464,7 @@ toELFSymbols(NameToIdxMap &SN2I, ArrayRef<ELFYAML::Symbol> Symbols,
}
// else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier.
Symbol.st_value = Sym.Value;
if (Sym.Other)
Symbol.st_other = *Sym.Other;
else if (Sym.StOther)
Symbol.st_other = *Sym.StOther;
Symbol.st_other = Sym.Other ? *Sym.Other : 0;
Symbol.st_size = Sym.Size;
}

View File

@ -11,12 +11,14 @@
//===----------------------------------------------------------------------===//
#include "llvm/ObjectYAML/ELFYAML.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MipsABIFlags.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/WithColor.h"
#include <cassert>
#include <cstdint>
@ -592,34 +594,6 @@ void ScalarEnumerationTraits<ELFYAML::ELF_STT>::enumeration(
IO.enumFallback<Hex8>(Value);
}
void ScalarEnumerationTraits<ELFYAML::ELF_STV>::enumeration(
IO &IO, ELFYAML::ELF_STV &Value) {
#define ECase(X) IO.enumCase(Value, #X, ELF::X)
ECase(STV_DEFAULT);
ECase(STV_INTERNAL);
ECase(STV_HIDDEN);
ECase(STV_PROTECTED);
#undef ECase
}
void ScalarBitSetTraits<ELFYAML::ELF_STO>::bitset(IO &IO,
ELFYAML::ELF_STO &Value) {
const auto *Object = static_cast<ELFYAML::Object *>(IO.getContext());
assert(Object && "The IO context is not initialized");
#define BCase(X) IO.bitSetCase(Value, #X, ELF::X)
switch (Object->Header.Machine) {
case ELF::EM_MIPS:
BCase(STO_MIPS_OPTIONAL);
BCase(STO_MIPS_PLT);
BCase(STO_MIPS_PIC);
BCase(STO_MIPS_MICROMIPS);
break;
default:
break; // Nothing to do
}
#undef BCase
#undef BCaseMask
}
void ScalarEnumerationTraits<ELFYAML::ELF_RSS>::enumeration(
IO &IO, ELFYAML::ELF_RSS &Value) {
@ -863,31 +837,112 @@ void MappingTraits<ELFYAML::ProgramHeader>::mapping(
IO.mapOptional("Offset", Phdr.Offset);
}
LLVM_YAML_STRONG_TYPEDEF(StringRef, StOtherPiece)
template <> struct ScalarTraits<StOtherPiece> {
static void output(const StOtherPiece &Val, void *, raw_ostream &Out) {
Out << Val;
}
static StringRef input(StringRef Scalar, void *, StOtherPiece &Val) {
Val = Scalar;
return {};
}
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
};
template <> struct SequenceElementTraits<StOtherPiece> {
static const bool flow = true;
};
namespace {
struct NormalizedOther {
NormalizedOther(IO &) {}
NormalizedOther(IO &, Optional<uint8_t> Original) {
if (uint8_t Val = *Original & 0x3)
Visibility = Val;
if (uint8_t Val = *Original & ~0x3)
Other = Val;
NormalizedOther(IO &IO) : YamlIO(IO) {}
NormalizedOther(IO &IO, Optional<uint8_t> Original) : YamlIO(IO) {
assert(Original && "This constructor is only used for outputting YAML and "
"assumes a non-empty Original");
std::vector<StOtherPiece> Ret;
const auto *Object = static_cast<ELFYAML::Object *>(YamlIO.getContext());
for (std::pair<StringRef, uint8_t> &P :
getFlags(Object->Header.Machine).takeVector()) {
uint8_t FlagValue = P.second;
if ((*Original & FlagValue) != FlagValue)
continue;
*Original &= ~FlagValue;
Ret.push_back({P.first});
}
if (*Original != 0) {
UnknownFlagsHolder = std::to_string(*Original);
Ret.push_back({UnknownFlagsHolder});
}
if (!Ret.empty())
Other = std::move(Ret);
}
uint8_t toValue(StringRef Name) {
const auto *Object = static_cast<ELFYAML::Object *>(YamlIO.getContext());
MapVector<StringRef, uint8_t> Flags = getFlags(Object->Header.Machine);
auto It = Flags.find(Name);
if (It != Flags.end())
return It->second;
uint8_t Val;
if (to_integer(Name, Val))
return Val;
llvm::WithColor::error()
<< "an unknown value is used for symbol's 'Other' field: " << Name
<< ".\n";
exit(1);
}
Optional<uint8_t> denormalize(IO &) {
if (!Visibility && !Other)
if (!Other)
return None;
uint8_t Ret = 0;
if (Visibility)
Ret |= *Visibility;
if (Other)
Ret |= *Other;
for (StOtherPiece &Val : *Other)
Ret |= toValue(Val);
return Ret;
}
Optional<ELFYAML::ELF_STV> Visibility;
Optional<ELFYAML::ELF_STO> Other;
// st_other field is used to encode symbol visibility and platform-dependent
// flags and values. This method returns a name to value map that is used for
// parsing and encoding this field.
MapVector<StringRef, uint8_t> getFlags(unsigned EMachine) {
MapVector<StringRef, uint8_t> Map;
// STV_* values are just enumeration values. We add them in a reversed order
// because when we convert the st_other to named constants when printing
// YAML we want to use a maximum number of bits on each step:
// when we have st_other == 3, we want to print it as STV_PROTECTED (3), but
// not as STV_HIDDEN (2) + STV_INTERNAL (1).
Map["STV_PROTECTED"] = ELF::STV_PROTECTED;
Map["STV_HIDDEN"] = ELF::STV_HIDDEN;
Map["STV_INTERNAL"] = ELF::STV_INTERNAL;
// STV_DEFAULT is used to represent the default visibility and has a value
// 0. We want to be able to read it from YAML documents, but there is no
// reason to print it.
if (!YamlIO.outputting())
Map["STV_DEFAULT"] = ELF::STV_DEFAULT;
// MIPS is not consistent. All of the STO_MIPS_* values are bit flags,
// except STO_MIPS_MIPS16 which overlaps them. It should be checked and
// consumed first when we print the output, because we do not want to print
// any other flags that have the same bits instead.
if (EMachine == ELF::EM_MIPS) {
Map["STO_MIPS_MIPS16"] = ELF::STO_MIPS_MIPS16;
Map["STO_MIPS_MICROMIPS"] = ELF::STO_MIPS_MICROMIPS;
Map["STO_MIPS_PIC"] = ELF::STO_MIPS_PIC;
Map["STO_MIPS_PLT"] = ELF::STO_MIPS_PLT;
Map["STO_MIPS_OPTIONAL"] = ELF::STO_MIPS_OPTIONAL;
}
return Map;
}
const IO &YamlIO;
Optional<std::vector<StOtherPiece>> Other;
std::string UnknownFlagsHolder;
};
} // end anonymous namespace
@ -902,22 +957,13 @@ void MappingTraits<ELFYAML::Symbol>::mapping(IO &IO, ELFYAML::Symbol &Symbol) {
IO.mapOptional("Value", Symbol.Value, Hex64(0));
IO.mapOptional("Size", Symbol.Size, Hex64(0));
// Symbol's Other field is a bit special. It is a bit field that represents
// st_other and usually holds symbol visibility. When we write a YAML document
// we split it into two fields named "Visibility" and "Other". The latter one
// usually holds no value, and so is almost never printed, although some
// targets (e.g. MIPS) may use it to specify the named bits to set (e.g.
// STO_MIPS_OPTIONAL). For producing broken objects we want to allow writing
// any value to st_other. To do this we allow one more field called "StOther".
// If it is present in a YAML document, we set st_other to its integer value
// whatever it is.
// obj2yaml should not print 'StOther', it should print 'Visibility' and
// 'Other' fields instead.
assert(!IO.outputting() || !Symbol.StOther.hasValue());
IO.mapOptional("StOther", Symbol.StOther);
// Symbol's Other field is a bit special. It is usually a field that
// represents st_other and holds the symbol visibility. However, on some
// platforms, it can contain bit fields and regular values, or even sometimes a
// crazy mix of them (see comments for NormalizedOther). Because of this, we
// need special handling.
MappingNormalization<NormalizedOther, Optional<uint8_t>> Keys(IO,
Symbol.Other);
IO.mapOptional("Visibility", Keys->Visibility);
IO.mapOptional("Other", Keys->Other);
}
@ -927,8 +973,6 @@ StringRef MappingTraits<ELFYAML::Symbol>::validate(IO &IO,
return "Index and Section cannot both be specified for Symbol";
if (Symbol.NameIndex && !Symbol.Name.empty())
return "Name and NameIndex cannot both be specified for Symbol";
if (Symbol.StOther && Symbol.Other)
return "StOther cannot be specified for Symbol with either Visibility or Other";
return StringRef();
}

View File

@ -40,7 +40,7 @@ IO::IO(void *Context) : Ctxt(Context) {}
IO::~IO() = default;
void *IO::getContext() {
void *IO::getContext() const {
return Ctxt;
}
@ -79,7 +79,7 @@ void Input::ScalarHNode::anchor() {}
void Input::MapHNode::anchor() {}
void Input::SequenceHNode::anchor() {}
bool Input::outputting() {
bool Input::outputting() const {
return false;
}
@ -440,7 +440,7 @@ Output::Output(raw_ostream &yout, void *context, int WrapColumn)
Output::~Output() = default;
bool Output::outputting() {
bool Output::outputting() const {
return true;
}

View File

@ -34,7 +34,7 @@ Symbols:
Section: .text
Value: 0x1008
Size: 8
Visibility: STV_HIDDEN
Other: [ STV_HIDDEN ]
- Name: defaultGlobal
Type: STT_FUNC
Size: 8
@ -46,14 +46,14 @@ Symbols:
Section: .data
Value: 0x2006
Size: 2
Visibility: STV_HIDDEN
Other: [ STV_HIDDEN ]
Binding: STB_GLOBAL
- Name: hiddenGlobalCommon
Type: STT_OBJECT
Index: SHN_COMMON
Value: 0x2006
Size: 2
Visibility: STV_HIDDEN
Other: [ STV_HIDDEN ]
Binding: STB_GLOBAL
- Name: undefGlobal
Type: STT_FUNC
@ -64,21 +64,21 @@ Symbols:
Section: .data
Value: 0x2002
Size: 2
Visibility: STV_INTERNAL
Other: [ STV_INTERNAL ]
Binding: STB_GLOBAL
- Name: protectedGlobal
Type: STT_OBJECT
Section: .data
Value: 0x2000
Size: 4
Visibility: STV_PROTECTED
Other: [ STV_PROTECTED ]
Binding: STB_GLOBAL
- Name: hiddenWeak
Type: STT_FUNC
Section: .text
Value: 0x1010
Size: 8
Visibility: STV_HIDDEN
Other: [ STV_HIDDEN ]
Binding: STB_WEAK
#CHECK: Relocations [

View File

@ -33,7 +33,7 @@ Symbols:
Section: .text
Value: 0x1001
Size: 4
Visibility: STV_HIDDEN
Other: [ STV_HIDDEN ]
Binding: STB_GLOBAL
- Name: foo
Type: STT_FUNC
@ -45,7 +45,7 @@ Symbols:
Section: .data
Value: 0x2002
Size: 2
Visibility: STV_INTERNAL
Other: [ STV_INTERNAL ]
Binding: STB_GLOBAL
- Name: bar
Type: STT_OBJECT

View File

@ -23,13 +23,13 @@ Symbols:
- Name: default
Section: .text
- Name: internal
Visibility: STV_INTERNAL
Other: [ STV_INTERNAL ]
Section: .text
- Name: hidden
Visibility: STV_HIDDEN
Other: [ STV_HIDDEN ]
Section: .text
- Name: protected
Visibility: STV_PROTECTED
Other: [ STV_PROTECTED ]
Section: .text
- Name: mips_pic
Other: [ STO_MIPS_PIC ]

View File

@ -39,17 +39,17 @@ FileHeader:
Machine: EM_386
Symbols:
- Name: default
Visibility: STV_DEFAULT
Other: [ STV_DEFAULT ]
Binding: STB_GLOBAL
- Name: internal
Visibility: STV_INTERNAL
Other: [ STV_INTERNAL ]
Binding: STB_GLOBAL
- Name: hidden
Visibility: STV_HIDDEN
Other: [ STV_HIDDEN ]
Binding: STB_GLOBAL
- Name: protected
Visibility: STV_PROTECTED
Other: [ STV_PROTECTED ]
Binding: STB_GLOBAL
- Name: other
Binding: STB_GLOBAL
StOther: 4
Other: [ 4 ]

View File

@ -10,12 +10,12 @@
# CHECK-NEXT: Machine: EM_X86_64
# CHECK-NEXT: Symbols:
# CHECK-NEXT: - Name: default
# CHECK-NEXT: - Name: internal
# CHECK-NEXT: Visibility: STV_INTERNAL
# CHECK-NEXT: - Name: hidden
# CHECK-NEXT: Visibility: STV_HIDDEN
# CHECK-NEXT: - Name: protected
# CHECK-NEXT: Visibility: STV_PROTECTED
# CHECK-NEXT: - Name: internal
# CHECK-NEXT: Other: [ STV_INTERNAL ]
# CHECK-NEXT: - Name: hidden
# CHECK-NEXT: Other: [ STV_HIDDEN ]
# CHECK-NEXT: - Name: protected
# CHECK-NEXT: Other: [ STV_PROTECTED ]
# CHECK-NEXT: ...
--- !ELF
@ -25,11 +25,11 @@ FileHeader:
Type: ET_REL
Machine: EM_X86_64
Symbols:
- Name: default
Visibility: STV_DEFAULT
- Name: internal
Visibility: STV_INTERNAL
- Name: hidden
Visibility: STV_HIDDEN
- Name: protected
Visibility: STV_PROTECTED
- Name: default
Other: [ STV_DEFAULT ]
- Name: internal
Other: [ STV_INTERNAL ]
- Name: hidden
Other: [ STV_HIDDEN ]
- Name: protected
Other: [ STV_PROTECTED ]

View File

@ -4,8 +4,7 @@
## to a different machine type to what is specified by the YAML.
# RUN: not yaml2obj --docnum=1 2>&1 %s | FileCheck %s --check-prefix=ERR
# ERR: error: unknown bit value
# ERR-NEXT: Other: [ STO_MIPS_OPTIONAL ]
# ERR: error: an unknown value is used for symbol's 'Other' field: STO_MIPS_OPTIONAL.
--- !ELF
FileHeader:
@ -38,21 +37,23 @@ Symbols:
- Name: foo
Other: [ STO_MIPS_OPTIONAL ]
## Test that instead of using the "Other" field we can use the "StOther" field
## to set st_other to any arbitrary value.
## Test that we can mix named and unnamed constants and set
## st_other to any arbitrary value.
# RUN: yaml2obj --docnum=3 %s > %t3
# RUN: llvm-readobj --symbols %t3 | FileCheck %s --check-prefix=USE-STOTHER
# RUN: yaml2obj --docnum=4 %s > %t4
# RUN: llvm-readobj --symbols %t4 | FileCheck %s --check-prefix=USE-STOTHER
# RUN: llvm-readobj --symbols %t3 | FileCheck %s --check-prefix=VALUE
# USE-STOTHER: Name: foo
# USE-STOTHER: Other [
# USE-STOTHER-SAME: (0x4)
# VALUE: Name: foo
# VALUE: Other [
# VALUE-SAME: (0x4)
# USE-STOTHER: Name: bar
# USE-STOTHER: Other [
# USE-STOTHER-SAME: (0xFF)
# VALUE: Name: bar
# VALUE: Other [
# VALUE-SAME: (0x7)
# VALUE: Name: zed
# VALUE: Other [
# VALUE-SAME: (0xFF)
--- !ELF
FileHeader:
@ -61,48 +62,9 @@ FileHeader:
Type: ET_REL
Machine: EM_MIPS
Symbols:
- Name: foo
StOther: 4
- Name: bar
StOther: 0xff
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_386
Symbols:
- Name: foo
StOther: 4
- Name: bar
StOther: 0xff
## Check we can't set StOther for a symbol if Visibility or Other is also specified.
# RUN: not yaml2obj --docnum=5 2>&1 %s | FileCheck %s --check-prefix=ERR2
# RUN: not yaml2obj --docnum=6 2>&1 %s | FileCheck %s --check-prefix=ERR2
# ERR2: error: StOther cannot be specified for Symbol with either Visibility or Other
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_MIPS
Symbols:
- Name: foo
StOther: 0
Other: [ STO_MIPS_OPTIONAL ]
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_MIPS
Symbols:
- Name: foo
StOther: 0
Visibility: STV_DEFAULT
- Name: foo
Other: [ 0x4 ]
- Name: bar
Other: [ STV_PROTECTED, 4 ]
- Name: zed
Other: [ STV_PROTECTED, STO_MIPS_OPTIONAL, 0xf8 ]

View File

@ -3,7 +3,7 @@
# RUN: yaml2obj %s | llvm-readobj --symbols - | FileCheck --check-prefix OBJ %s
# OBJ: Symbol {
# OBJ: Name: default (1)
# OBJ: Name: default1
# OBJ-NEXT: Value: 0x0
# OBJ-NEXT: Size: 0
# OBJ-NEXT: Binding: Local (0x0)
@ -12,7 +12,16 @@
# OBJ-NEXT: Section: Undefined (0x0)
# OBJ-NEXT: }
# OBJ-NEXT: Symbol {
# OBJ-NEXT: Name: internal (16)
# OBJ-NEXT: Name: default2
# OBJ-NEXT: Value: 0x0
# OBJ-NEXT: Size: 0
# OBJ-NEXT: Binding: Local (0x0)
# OBJ-NEXT: Type: None (0x0)
# OBJ-NEXT: Other: 0
# OBJ-NEXT: Section: Undefined (0x0)
# OBJ-NEXT: }
# OBJ-NEXT: Symbol {
# OBJ-NEXT: Name: internal
# OBJ-NEXT: Value: 0x0
# OBJ-NEXT: Size: 0
# OBJ-NEXT: Binding: Local (0x0)
@ -23,7 +32,7 @@
# OBJ-NEXT: Section: Undefined (0x0)
# OBJ-NEXT: }
# OBJ-NEXT: Symbol {
# OBJ-NEXT: Name: hidden (9)
# OBJ-NEXT: Name: hidden
# OBJ-NEXT: Value: 0x0
# OBJ-NEXT: Size: 0
# OBJ-NEXT: Binding: Local (0x0)
@ -34,7 +43,7 @@
# OBJ-NEXT: Section: Undefined (0x0)
# OBJ-NEXT: }
# OBJ-NEXT: Symbol {
# OBJ-NEXT: Name: protected (25)
# OBJ-NEXT: Name: protected
# OBJ-NEXT: Value: 0x0
# OBJ-NEXT: Size: 0
# OBJ-NEXT: Binding: Local (0x0)
@ -52,11 +61,12 @@ FileHeader:
Type: ET_REL
Machine: EM_X86_64
Symbols:
- Name: default
Visibility: STV_DEFAULT
- Name: internal
Visibility: STV_INTERNAL
- Name: hidden
Visibility: STV_HIDDEN
- Name: protected
Visibility: STV_PROTECTED
- Name: default1
- Name: default2
Other: [ STV_DEFAULT ]
- Name: internal
Other: [ STV_INTERNAL ]
- Name: hidden
Other: [ STV_HIDDEN ]
- Name: protected
Other: [ STV_PROTECTED ]