Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ 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, YAMLInt) // 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; + YAMLInt Addend; ELF_REL Type; Optional Symbol; }; @@ -542,6 +543,12 @@ namespace llvm { namespace yaml { +template <> struct ScalarTraits { + static void output(const ELFYAML::YAMLInt &Val, void *Ctx, raw_ostream &Out); + static StringRef input(StringRef Scalar, void *Ctx, ELFYAML::YAMLInt &Val); + static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, ELFYAML::ELF_ET &Value); Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -982,6 +982,35 @@ } // end anonymous namespace +void ScalarTraits::output(const ELFYAML::YAMLInt &Val, + void *Ctx, raw_ostream &Out) { + Out << Val; +} + +StringRef ScalarTraits::input(StringRef Scalar, void *Ctx, + ELFYAML::YAMLInt &Val) { + const bool Is64 = static_cast(Ctx)->Header.Class == + ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); + StringRef ErrMsg = "invalid number"; + if (Scalar.empty()) + return ErrMsg; + + bool IsNegative = Scalar.front() == '-'; + if (IsNegative) + Scalar = Scalar.drop_front(); + + unsigned long long UInt; + if (getAsUnsignedInteger(Scalar, /*Radix=*/0, UInt)) + return ErrMsg; + + // For a 32-bit target we allow values in a range of a uint32_t. + if (!Is64 && (UInt > UINT32_MAX)) + return ErrMsg; + + Val = IsNegative ? (-UInt) : UInt; + return ""; +} + void MappingTraits::mapping(IO &IO, ELFYAML::Symbol &Symbol) { IO.mapOptional("Name", Symbol.Name, StringRef()); IO.mapOptional("StName", Symbol.StName); @@ -1582,7 +1611,7 @@ } else IO.mapRequired("Type", Rel.Type); - IO.mapOptional("Addend", Rel.Addend, (int64_t)0); + IO.mapOptional("Addend", Rel.Addend, (ELFYAML::YAMLInt)0); } void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { Index: llvm/test/tools/obj2yaml/relocation-addend.yaml =================================================================== --- llvm/test/tools/obj2yaml/relocation-addend.yaml +++ llvm/test/tools/obj2yaml/relocation-addend.yaml @@ -40,9 +40,8 @@ Info: .text Link: .symtab Relocations: - - Type: R_X86_64_PC32 - Offset: 0x0 - Symbol: foo + - Symbol: foo + Type: R_X86_64_PC32 Addend: [[ADDEND]] Symbols: - Name: foo @@ -93,7 +92,6 @@ Link: .symtab Relocations: - Type: R_386_PC32 - Offset: 0x0 Symbol: foo Addend: [[ADDEND]] Symbols: Index: llvm/test/tools/yaml2obj/ELF/relocation-addend.yaml =================================================================== --- llvm/test/tools/yaml2obj/ELF/relocation-addend.yaml +++ llvm/test/tools/yaml2obj/ELF/relocation-addend.yaml @@ -2,36 +2,51 @@ ## 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 [-(2^64 - 1), +(2^64 - 1)]. -# 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 +## Addend == 2^64 - 1. +# 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 -# MAX64: 0x0 R_X86_64_PC32 foo 0x7FFFFFFFFFFFFFFF +## 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 -## 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 == 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 -# OVERFLOW64: error: invalid number +## 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 +# RUN: yaml2obj %s -o %t64.hex.first.neg -DADDEND=-0x1 +# RUN: llvm-readobj -r %t64.hex.first.neg | FileCheck %s --check-prefix=TEST -DADDEND=0xFFFFFFFFFFFFFFFF -## Case 1.3: Document we accept an addend with the -## value INT64_MIN = -2^63 = 0x8000000000000000 = -9223372036854775808. +## Addend == -(2^64 - 1) +# RUN: yaml2obj %s -o %t64.decimal.min -DADDEND=-18446744073709551615 +# RUN: llvm-readobj -r %t64.decimal.min | FileCheck %s --check-prefix=TEST -DADDEND=0x1 +# RUN: yaml2obj %s -o %t64.hex.min -DADDEND=-0xFFFFFFFFFFFFFFFF +# RUN: llvm-readobj -r %t64.hex.min | FileCheck %s --check-prefix=TEST -DADDEND=0x1 -# RUN: yaml2obj %s -o %t3 -D ADDEND=-9223372036854775808 -# RUN: llvm-readobj -r %t3 | FileCheck %s --check-prefix=MIN64 +# 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 == -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 + +# ERR: invalid number --- !ELF FileHeader: @@ -55,43 +70,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 - -# MAX32: 0x0 R_386_PC32 foo 0x7FFFFFFF{{$}} +## Case 2.1: Document we accept any hex/decimal addends in [-(2^32 - 1), +(2^32 - 1)]. -## 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 == 2^32 - 1. +# 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 +# RUN: yaml2obj --docnum=2 %s -o %t32.hex.first.neg -DADDEND=-0x1 +# RUN: llvm-readobj -r %t32.hex.first.neg | FileCheck %s --check-prefix=TEST -DADDEND=0xFFFFFFFF -# 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 == -(2^32 - 1) +# RUN: yaml2obj --docnum=2 %s -o %t32.decimal.min -DADDEND=-4294967295 +# RUN: llvm-readobj -r %t32.decimal.min | FileCheck %s --check-prefix=TEST -DADDEND=0x1 +# RUN: yaml2obj --docnum=2 %s -o %t32.hex.min -DADDEND=-0xFFFFFFFF +# RUN: llvm-readobj -r %t32.hex.min | FileCheck %s --check-prefix=TEST -DADDEND=0x1 -# MIN32: 0x0 R_386_PC32 foo 0x80000000{{$}} +# Case 1.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 %t.err -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 == -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 --- !ELF FileHeader: @@ -112,3 +131,12 @@ Addend: [[ADDEND]] Symbols: - Name: foo + +## Case 4: 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