diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -65,6 +65,7 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, MIPS_ISA) LLVM_YAML_STRONG_TYPEDEF(StringRef, YAMLFlowString) +LLVM_YAML_STRONG_TYPEDEF(int64_t, YAMLIntUInt) // For now, hardcode 64 bits everywhere that 32 or 64 would be needed // since 64-bit can hold 32-bit values too. @@ -439,7 +440,7 @@ struct Relocation { llvm::yaml::Hex64 Offset; - int64_t Addend; + YAMLIntUInt Addend; ELF_REL Type; Optional Symbol; }; @@ -542,6 +543,14 @@ namespace llvm { namespace yaml { +template <> struct ScalarTraits { + static void output(const ELFYAML::YAMLIntUInt &Val, void *Ctx, + raw_ostream &Out); + static StringRef input(StringRef Scalar, void *Ctx, + ELFYAML::YAMLIntUInt &Val); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, ELFYAML::ELF_ET &Value); diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -982,6 +982,38 @@ } // end anonymous namespace +void ScalarTraits::output(const ELFYAML::YAMLIntUInt &Val, + void *Ctx, raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits::input(StringRef Scalar, void *Ctx, + ELFYAML::YAMLIntUInt &Val) { + const bool Is64 = static_cast(Ctx)->Header.Class == + ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); + StringRef ErrMsg = "invalid number"; + // We do not accept negative hex numbers because their meaning is ambiguous. + // For example, would -0xfffffffff mean 1 or INT32_MIN? + if (Scalar.empty() || Scalar.startswith("-0x")) + return ErrMsg; + + if (Scalar.startswith("-")) { + const int64_t MinVal = Is64 ? INT64_MIN : INT32_MIN; + long long Int; + if (getAsSignedInteger(Scalar, /*Radix=*/0, Int) || (Int < MinVal)) + return ErrMsg; + Val = Int; + return ""; + } + + const uint64_t MaxVal = Is64 ? UINT64_MAX : UINT32_MAX; + unsigned long long UInt; + if (getAsUnsignedInteger(Scalar, /*Radix=*/0, UInt) || (UInt > MaxVal)) + return ErrMsg; + Val = UInt; + return ""; +} + void MappingTraits::mapping(IO &IO, ELFYAML::Symbol &Symbol) { IO.mapOptional("Name", Symbol.Name, StringRef()); IO.mapOptional("StName", Symbol.StName); @@ -1582,7 +1614,7 @@ } else IO.mapRequired("Type", Rel.Type); - IO.mapOptional("Addend", Rel.Addend, (int64_t)0); + IO.mapOptional("Addend", Rel.Addend, (ELFYAML::YAMLIntUInt)0); } void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { diff --git a/llvm/test/tools/yaml2obj/ELF/relocation-addend.yaml b/llvm/test/tools/yaml2obj/ELF/relocation-addend.yaml --- a/llvm/test/tools/yaml2obj/ELF/relocation-addend.yaml +++ b/llvm/test/tools/yaml2obj/ELF/relocation-addend.yaml @@ -2,36 +2,50 @@ ## Case 1: Check a 64-bit object. -## Case 1.1: Document we accept an addend with the -## value INT64_MAX = 2^63-1 = 0x7FFFFFFFFFFFFFFF = 9223372036854775807. +## Case 1.1: Document we accept any hex/decimal addends in [INT64_MIN, UINT64_MAX]. -# RUN: yaml2obj %s -o %t1 -D ADDEND=9223372036854775807 -# RUN: llvm-readobj -r %t1 | FileCheck %s --check-prefix=MAX64 -# RUN: yaml2obj %s -o %t2 -D ADDEND=0x7FFFFFFFFFFFFFFF -# RUN: llvm-readobj -r %t2 | FileCheck %s --check-prefix=MAX64 +## INT64_MIN == -9223372036854775808 +## UINT64_MAX == 0xffffffffffffffff -# MAX64: 0x0 R_X86_64_PC32 foo 0x7FFFFFFFFFFFFFFF +## Addend == UINT64_MAX. +# RUN: yaml2obj %s -o %t64.decimal.max -DADDEND=18446744073709551615 +# RUN: llvm-readobj -r %t64.decimal.max | FileCheck %s --check-prefix=TEST -DADDEND=0xFFFFFFFFFFFFFFFF +# RUN: yaml2obj %s -o %t64.hex.max -DADDEND=0xFFFFFFFFFFFFFFFF +# RUN: llvm-readobj -r %t64.hex.max | FileCheck %s --check-prefix=TEST -DADDEND=0xFFFFFFFFFFFFFFFF -## Case 1.2: Check we report an error when an addend is greater than INT64_MAX and -## it is in decimal form. We use (INT64_MAX + 1). -# RUN: not yaml2obj %s -o %t3 -D ADDEND=9223372036854775808 2>&1 | FileCheck %s --check-prefix=OVERFLOW64 +## Addend == first positive integer. +# RUN: yaml2obj %s -o %t64.decimal.first.pos -DADDEND=1 +# RUN: llvm-readobj -r %t64.decimal.first.pos | FileCheck %s --check-prefix=TEST -DADDEND=0x1 +# RUN: yaml2obj %s -o %t64.hex.first.pos -DADDEND=0x1 +# RUN: llvm-readobj -r %t64.hex.first.pos | FileCheck %s --check-prefix=TEST -DADDEND=0x1 -# OVERFLOW64: error: invalid number +## Addend == 0. +# RUN: yaml2obj %s -o %t64.decimal.null -DADDEND=0 +# RUN: llvm-readobj -r %t64.decimal.null | FileCheck %s --check-prefix=TEST -DADDEND=0x0 +# RUN: yaml2obj %s -o %t64.hex.null -DADDEND=0x0 +# RUN: llvm-readobj -r %t64.hex.null | FileCheck %s --check-prefix=TEST -DADDEND=0x0 -## Case 1.3: Document we accept an addend with the -## value INT64_MIN = -2^63 = 0x8000000000000000 = -9223372036854775808. +## Addend == first negative integer. +# RUN: yaml2obj %s -o %t64.decimal.first.neg -DADDEND=-1 +# RUN: llvm-readobj -r %t64.decimal.first.neg | FileCheck %s --check-prefix=TEST -DADDEND=0xFFFFFFFFFFFFFFFF +## We do not accept negative hex addends. +# RUN: not yaml2obj %s -o /dev/null -DADDEND=-0x1 2>&1 | FileCheck %s --check-prefix=ERR -# RUN: yaml2obj %s -o %t3 -D ADDEND=-9223372036854775808 -# RUN: llvm-readobj -r %t3 | FileCheck %s --check-prefix=MIN64 +## Addend == INT64_MIN. +# RUN: yaml2obj %s -o %t64.decimal.min -DADDEND=-9223372036854775808 +# RUN: llvm-readobj -r %t64.decimal.min | FileCheck %s --check-prefix=TEST -DADDEND=0x8000000000000000 +# TEST: 0x0 R_{{.*}}_PC32 foo [[ADDEND]] -# MIN64: 0x0 R_X86_64_PC32 foo 0x8000000000000000 +# Case 1.2: Document we do not accept any hex/decimal addends outside of the range specified. -## FIXME: We should support the following case instead. -# RUN: not yaml2obj %s -o /dev/null -D ADDEND=0x8000000000000000 2>&1 | FileCheck %s --check-prefix=OVERFLOW64 +## Addend == 2^64. +# RUN: not yaml2obj %s -o /dev/null -DADDEND=18446744073709551616 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not yaml2obj %s -o /dev/null -DADDEND=0x10000000000000000 2>&1 | FileCheck %s --check-prefix=ERR -## Case 1.4: Check we report an error when an addend is less than INT64_MIN and -## it is in decimal form. We use (INT64_MIN - 1). -# RUN: not yaml2obj %s -o /dev/null -D ADDEND=-9223372036854775809 2>&1 | FileCheck %s --check-prefix=OVERFLOW64 +## Addend == INT64_MIN - 1. +# RUN: not yaml2obj %s -o /dev/null -DADDEND=-9223372036854775809 2>&1 | FileCheck %s --check-prefix=ERR + +# ERR: invalid number --- !ELF FileHeader: @@ -55,43 +69,47 @@ ## Case 2: Check a 32-bit object. -## Case 2.1: Document we accept an addend with the -## value INT32_MAX = 2^31-1 = 0x7FFFFFFF = 2,147,483,647. - -# RUN: yaml2obj --docnum=2 %s -o %t4 -D ADDEND=2147483647 -# RUN: llvm-readobj -r %t4 | FileCheck %s --check-prefix=MAX32 -# RUN: yaml2obj --docnum=2 %s -o %t5 -D ADDEND=0x7FFFFFFF -# RUN: cmp %t4 %t5 +## INT32_MIN == -2147483648 +## UINT32_MAX == 0xffffffff -# MAX32: 0x0 R_386_PC32 foo 0x7FFFFFFF{{$}} +## Case 2.1: Document we accept any hex/decimal addends in [INT32_MIN, UINT32_MAX]. -## Case 2.2: Check we report an error when an addend is greater than INT32_MAX and -## it is specified in decimal form. We use (INT32_MAX + 1). +## Addend == UINT32_MAX. +# RUN: yaml2obj --docnum=2 %s -o %t32.decimal.max -DADDEND=4294967295 +# RUN: llvm-readobj -r %t32.decimal.max | FileCheck %s --check-prefix=TEST -DADDEND=0xFFFFFFFF +# RUN: yaml2obj --docnum=2 %s -o %t32.hex.max -DADDEND=0xFFFFFFFF +# RUN: llvm-readobj -r %t32.hex.max | FileCheck %s --check-prefix=TEST -DADDEND=0xFFFFFFFF -## FIXME: The following case should fail, see OVERFLOW64. -# RUN: yaml2obj --docnum=2 %s -o %t6 -D ADDEND=2147483648 -# RUN: llvm-readobj -r %t6 | FileCheck %s --check-prefix=OVERFLOW32-1 +## Addend == first positive integer. +# RUN: yaml2obj --docnum=2 %s -o %t32.decimal.first.pos -DADDEND=1 +# RUN: llvm-readobj -r %t32.decimal.first.pos | FileCheck %s --check-prefix=TEST -DADDEND=0x1 +# RUN: yaml2obj --docnum=2 %s -o %t32.hex.first.pos -DADDEND=0x1 +# RUN: llvm-readobj -r %t32.hex.first.pos | FileCheck %s --check-prefix=TEST -DADDEND=0x1 -# OVERFLOW32-1: 0x0 R_386_PC32 foo 0x80000000{{$}} +## Addend == 0. +# RUN: yaml2obj --docnum=2 %s -o %t32.decimal.null -DADDEND=0 +# RUN: llvm-readobj -r %t32.decimal.null | FileCheck %s --check-prefix=TEST -DADDEND=0x0 +# RUN: yaml2obj --docnum=2 %s -o %t32.hex.null -DADDEND=0x0 +# RUN: llvm-readobj -r %t32.hex.null | FileCheck %s --check-prefix=TEST -DADDEND=0x0 -## Case 2.3: Document we accept an addend with the -## value INT32_MIN = -2^31 = 0x80000000 = -2,147,483,648. +## Addend == first negative integer. +# RUN: yaml2obj --docnum=2 %s -o %t32.decimal.first.neg -DADDEND=-1 +# RUN: llvm-readobj -r %t32.decimal.first.neg | FileCheck %s --check-prefix=TEST -DADDEND=0xFFFFFFFF +## We do not accept negative hex addends. +# RUN: not yaml2obj --docnum=2 %s -o /dev/null -DADDEND=-0x1 2>&1 | FileCheck %s --check-prefix=ERR -# RUN: yaml2obj --docnum=2 %s -o %t7 -D ADDEND=-2147483648 -# RUN: llvm-readobj -r %t7 | FileCheck %s --check-prefix=MIN32 -# RUN: yaml2obj --docnum=2 %s -o %t8 -D ADDEND=0x80000000 -# RUN: cmp %t7 %t8 +## Addend == INT32_MIN +# RUN: yaml2obj --docnum=2 %s -o %t32.decimal.min -DADDEND=-2147483648 +# RUN: llvm-readobj -r %t32.decimal.min | FileCheck %s --check-prefix=TEST -DADDEND=0x80000000 -# MIN32: 0x0 R_386_PC32 foo 0x80000000{{$}} +# Case 2.2: Document we do not accept any hex/decimal addends outside of the range specified. -## Case 2.4: Check we report an error when an addend is less than INT32_MIN and -## it is in decimal form. We use (INT32_MIN - 1). +## Addend == 2^32. +# RUN: not yaml2obj --docnum=2 %s -o /dev/null -DADDEND=4294967296 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not yaml2obj --docnum=2 %s -o /dev/null -DADDEND=0x100000000 2>&1 | FileCheck %s --check-prefix=ERR -## FIXME: The following case should fail, see OVERFLOW64. -# RUN: yaml2obj --docnum=2 %s -o %t9 -D ADDEND=-2147483649 -# RUN: llvm-readobj -r %t9 | FileCheck %s --check-prefix=OVERFLOW32-2 - -# OVERFLOW32-2: 0x0 R_386_PC32 foo 0x7FFFFFFF{{$}} +## Addend == INT32_MIN - 1. +# RUN: not yaml2obj --docnum=2 %s -o /dev/null -DADDEND=-2147483649 2>&1 | FileCheck %s --check-prefix=ERR --- !ELF FileHeader: @@ -112,3 +130,12 @@ Addend: [[ADDEND]] Symbols: - Name: foo + +## Case 3: Check we do not allow invalid values. +# RUN: not yaml2obj %s -D ADDEND=0x1122GGEE 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not yaml2obj %s -D ADDEND=-0x1122GGEE 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not yaml2obj %s -D ADDEND=1234G5 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not yaml2obj %s -D ADDEND=-1234G5 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not yaml2obj %s -D ADDEND=foo 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not yaml2obj %s -D ADDEND=- 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not yaml2obj %s -D ADDEND=--1234 2>&1 | FileCheck %s --check-prefix=ERR