[llvm] 4dd5f1c - [yaml2obj] - Add `ELFYAML::YAMLIntUInt` to fix how we parse a relocation `Addend` key.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 17 04:22:38 PDT 2020


Author: Georgii Rymar
Date: 2020-03-17T14:22:19+03:00
New Revision: 4dd5f1ca9b2b7ae50849efeb7cf3ecfbdb1cf67a

URL: https://github.com/llvm/llvm-project/commit/4dd5f1ca9b2b7ae50849efeb7cf3ecfbdb1cf67a
DIFF: https://github.com/llvm/llvm-project/commit/4dd5f1ca9b2b7ae50849efeb7cf3ecfbdb1cf67a.diff

LOG: [yaml2obj] - Add `ELFYAML::YAMLIntUInt` to fix how we parse a relocation `Addend` key.

This patch makes `Relocation::Addend` to be `ELFYAML::YAMLIntUInt` and not `int64_t`.

`ELFYAML::YAMLIntUInt` it is a new type and it has the following benefits/features:

1) For an 64-bit object any hex/decimal addends
   in the range [INT64_MIN, UINT64_MAX] is accepted.
2) For an 32-bit object any hex/decimal addends
   in range [INT32_MIN, UINT32_MAX] is accepted.
3) Negative hex numbers like -0xffffffff are not accepted.
4) It is printed as decimal. I.e. obj2yaml will print
   something like "Addend: 125", this matches the current behavior.

This fixes all FIXMEs in `relocation-addend.yaml`.

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

Added: 
    

Modified: 
    llvm/include/llvm/ObjectYAML/ELFYAML.h
    llvm/lib/ObjectYAML/ELFYAML.cpp
    llvm/test/tools/yaml2obj/ELF/relocation-addend.yaml

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 60bb2375901b..44f5d7cd069e 100644
--- 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_AFL_FLAGS1)
 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 Group : Section {
 
 struct Relocation {
   llvm::yaml::Hex64 Offset;
-  int64_t Addend;
+  YAMLIntUInt Addend;
   ELF_REL Type;
   Optional<StringRef> Symbol;
 };
@@ -542,6 +543,14 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionName)
 namespace llvm {
 namespace yaml {
 
+template <> struct ScalarTraits<ELFYAML::YAMLIntUInt> {
+  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<ELFYAML::ELF_ET> {
   static void enumeration(IO &IO, ELFYAML::ELF_ET &Value);

diff  --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index d567153af4c2..e9977b4899ee 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -982,6 +982,38 @@ struct NormalizedOther {
 
 } // end anonymous namespace
 
+void ScalarTraits<ELFYAML::YAMLIntUInt>::output(const ELFYAML::YAMLIntUInt &Val,
+                                                void *Ctx, raw_ostream &Out) {
+  Out << Val;
+}
+
+StringRef ScalarTraits<ELFYAML::YAMLIntUInt>::input(StringRef Scalar, void *Ctx,
+                                                    ELFYAML::YAMLIntUInt &Val) {
+  const bool Is64 = static_cast<ELFYAML::Object *>(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<ELFYAML::Symbol>::mapping(IO &IO, ELFYAML::Symbol &Symbol) {
   IO.mapOptional("Name", Symbol.Name, StringRef());
   IO.mapOptional("StName", Symbol.StName);
@@ -1582,7 +1614,7 @@ void MappingTraits<ELFYAML::Relocation>::mapping(IO &IO,
   } else
     IO.mapRequired("Type", Rel.Type);
 
-  IO.mapOptional("Addend", Rel.Addend, (int64_t)0);
+  IO.mapOptional("Addend", Rel.Addend, (ELFYAML::YAMLIntUInt)0);
 }
 
 void MappingTraits<ELFYAML::Object>::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
index 53396765fb59..f4ed870357f4 100644
--- 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 @@ Symbols:
 
 ## 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 @@ Sections:
         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


        


More information about the llvm-commits mailing list