[llvm] [Object] Provide operator< for ELFSymbolRef (PR #89861)

Amir Ayupov via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 29 07:23:18 PDT 2024


https://github.com/aaupov updated https://github.com/llvm/llvm-project/pull/89861

>From b6630e85ff5d4a35cf8d77fad63ba93791ffa806 Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Tue, 23 Apr 2024 19:34:12 -0700
Subject: [PATCH 1/5] [Object] Provide operator< for ELFSymbolRef

Normally, operator< accepting DataRefImpl is used when comparing
SymbolRef/ELFSymbolRef. However, it uses std::memcmp which interprets
DataRefImpl union as char string. For ELFSymbolRef it's known that it
uses the struct view of the union, therefore a specialized operator< can
be used instead.
---
 llvm/include/llvm/Object/ELFObjectFile.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 1d457be93741f2..8ec0e3fe15dc9d 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -199,6 +199,14 @@ class ELFSymbolRef : public SymbolRef {
   }
 };
 
+inline bool operator<(const ELFSymbolRef &A, const ELFSymbolRef &B) {
+  const DataRefImpl &DRIA = A.getRawDataRefImpl();
+  const DataRefImpl &DRIB = B.getRawDataRefImpl();
+  if (DRIA.d.a == DRIB.d.a)
+    return DRIA.d.b < DRIB.d.b;
+  return DRIA.d.a < DRIB.d.b;
+}
+
 class elf_symbol_iterator : public symbol_iterator {
 public:
   elf_symbol_iterator(const basic_symbol_iterator &B)

>From 0e9aab883f33caf9b2d8ec246f2f81bda63c2a5e Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Wed, 24 Apr 2024 11:39:09 -0700
Subject: [PATCH 2/5] Add ELFObjectFileTest::ELFSymbolRefLess

---
 llvm/unittests/Object/ELFObjectFileTest.cpp | 36 +++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index c4d2b4ae8b9acd..a4a0f6d4a7276d 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -1504,3 +1504,39 @@ TEST(ELFObjectFileTest, GetSectionAndRelocations) {
                "SHT_RELA section with index 1: failed to get a "
                "relocated section: invalid section index: 255");
 }
+
+TEST(ELFObjectFileTest, ELFSymbolRefLess) {
+  SmallString<0> Storage;
+  Expected<ELFObjectFile<ELF64LE>> ElfOrErr = toBinary<ELF64LE>(Storage, R"(
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_X86_64
+)");
+
+  ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+  const ELFObjectFile<ELF64LE> &Obj = *ElfOrErr;
+
+  llvm::object::DataRefImpl Data1;
+  Data1.d.a = 0x00000000;
+  Data1.d.b = 0x00000001;
+  SymbolRef Symbol1(Data1, &Obj);
+  ELFSymbolRef ELFSymbol1(Symbol1);
+
+  llvm::object::DataRefImpl Data2;
+  Data2.d.a = 0x00000000;
+  Data2.d.b = 0x00000100;
+  SymbolRef Symbol2(Data2, &Obj);
+  ELFSymbolRef ELFSymbol2(Symbol2);
+
+  // SymbolRef operator< uses std::memcmp treating the union as char string.
+  if (llvm::sys::IsLittleEndianHost)
+    EXPECT_FALSE(Symbol1 < Symbol2);
+  else
+    EXPECT_TRUE(Symbol1 < Symbol2);
+
+  // ELFSymbolRef operator< compares struct fields.
+  EXPECT_TRUE(ELFSymbol1 < ELFSymbol2);
+}

>From 978d8fb6582c65f28f76789c17a5d3b4f90f73e8 Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Wed, 24 Apr 2024 18:56:02 -0700
Subject: [PATCH 3/5] Fix typo

---
 llvm/include/llvm/Object/ELFObjectFile.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 8ec0e3fe15dc9d..38d3a4f1732cf3 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -204,7 +204,7 @@ inline bool operator<(const ELFSymbolRef &A, const ELFSymbolRef &B) {
   const DataRefImpl &DRIB = B.getRawDataRefImpl();
   if (DRIA.d.a == DRIB.d.a)
     return DRIA.d.b < DRIB.d.b;
-  return DRIA.d.a < DRIB.d.b;
+  return DRIA.d.a < DRIB.d.a;
 }
 
 class elf_symbol_iterator : public symbol_iterator {

>From fb87c76a98c9dc4b14013a55210a4cd6482eecef Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Fri, 26 Apr 2024 10:24:12 -0700
Subject: [PATCH 4/5] Added tests, addressed comments

---
 llvm/unittests/Object/ELFObjectFileTest.cpp | 66 +++++++++++++++------
 1 file changed, 47 insertions(+), 19 deletions(-)

diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index a4a0f6d4a7276d..5b1062c07fdf58 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -1519,24 +1519,52 @@ TEST(ELFObjectFileTest, ELFSymbolRefLess) {
   ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
   const ELFObjectFile<ELF64LE> &Obj = *ElfOrErr;
 
-  llvm::object::DataRefImpl Data1;
-  Data1.d.a = 0x00000000;
-  Data1.d.b = 0x00000001;
-  SymbolRef Symbol1(Data1, &Obj);
-  ELFSymbolRef ELFSymbol1(Symbol1);
-
-  llvm::object::DataRefImpl Data2;
-  Data2.d.a = 0x00000000;
-  Data2.d.b = 0x00000100;
-  SymbolRef Symbol2(Data2, &Obj);
-  ELFSymbolRef ELFSymbol2(Symbol2);
-
-  // SymbolRef operator< uses std::memcmp treating the union as char string.
-  if (llvm::sys::IsLittleEndianHost)
-    EXPECT_FALSE(Symbol1 < Symbol2);
-  else
-    EXPECT_TRUE(Symbol1 < Symbol2);
-
-  // ELFSymbolRef operator< compares struct fields.
+  const uint32_t Val1 = 0x00000001;
+  const uint32_t Val2 = 0x00000100;
+
+  DataRefImpl Data1, Data2, Data3, Data4;
+
+  // Symtab index
+  Data1.d.a = Data2.d.a = Val1;
+  Data3.d.a = Data4.d.a = Val2;
+
+  // Symbol index
+  Data1.d.b = Data3.d.b = Val1;
+  Data2.d.b = Data4.d.b = Val2;
+
+  SymbolRef Symbol1(Data1, &Obj), Symbol2(Data2, &Obj), Symbol3(Data3, &Obj),
+      Symbol4(Data4, &Obj);
+  ELFSymbolRef ELFSymbol1(Symbol1), ELFSymbol2(Symbol2), ELFSymbol3(Symbol3),
+      ELFSymbol4(Symbol4);
+
+  // Symtab index match
+  // left sym index is lower
   EXPECT_TRUE(ELFSymbol1 < ELFSymbol2);
+  EXPECT_TRUE(ELFSymbol3 < ELFSymbol4);
+  // right sym index is lower
+  EXPECT_FALSE(ELFSymbol2 < ELFSymbol1);
+  EXPECT_FALSE(ELFSymbol4 < ELFSymbol3);
+  // sym indexes match
+  EXPECT_FALSE(ELFSymbol1 < ELFSymbol1);
+  EXPECT_FALSE(ELFSymbol2 < ELFSymbol2);
+  EXPECT_FALSE(ELFSymbol3 < ELFSymbol3);
+  EXPECT_FALSE(ELFSymbol4 < ELFSymbol4);
+
+  // Left symtab index is lower
+  // left sym index is lower
+  EXPECT_TRUE(ELFSymbol1 < ELFSymbol4);
+  // right sym index is lower
+  EXPECT_TRUE(ELFSymbol2 < ELFSymbol3);
+  // sym indexes match
+  EXPECT_TRUE(ELFSymbol1 < ELFSymbol3);
+  EXPECT_TRUE(ELFSymbol2 < ELFSymbol4);
+
+  // Right symtab index is lower
+  // left sym index is lower
+  EXPECT_FALSE(ELFSymbol3 < ELFSymbol2);
+  // right sym index is lower
+  EXPECT_FALSE(ELFSymbol4 < ELFSymbol1);
+  // sym indexes match
+  EXPECT_FALSE(ELFSymbol3 < ELFSymbol1);
+  EXPECT_FALSE(ELFSymbol4 < ELFSymbol2);
 }

>From 2249f8d6ae779a3c0590dad5834eb9e53574f673 Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Mon, 29 Apr 2024 07:22:48 -0700
Subject: [PATCH 5/5] Add helper, rename variables, prune redundant checks

---
 llvm/unittests/Object/ELFObjectFileTest.cpp | 73 +++++++++------------
 1 file changed, 32 insertions(+), 41 deletions(-)

diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index 5b1062c07fdf58..946fcd13e5443e 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -1519,52 +1519,43 @@ TEST(ELFObjectFileTest, ELFSymbolRefLess) {
   ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
   const ELFObjectFile<ELF64LE> &Obj = *ElfOrErr;
 
-  const uint32_t Val1 = 0x00000001;
-  const uint32_t Val2 = 0x00000100;
-
-  DataRefImpl Data1, Data2, Data3, Data4;
-
-  // Symtab index
-  Data1.d.a = Data2.d.a = Val1;
-  Data3.d.a = Data4.d.a = Val2;
-
-  // Symbol index
-  Data1.d.b = Data3.d.b = Val1;
-  Data2.d.b = Data4.d.b = Val2;
+  const uint32_t ValLow = 0x00000001;
+  const uint32_t ValHigh = 0x00000100;
+
+  auto MakeSymbol = [&Obj](size_t SymtabIndex, size_t SymbolIndex) {
+    DataRefImpl Data;
+    Data.d.a = SymtabIndex;
+    Data.d.b = SymbolIndex;
+    SymbolRef Sym(Data, &Obj);
+    return ELFSymbolRef(Sym);
+  };
 
-  SymbolRef Symbol1(Data1, &Obj), Symbol2(Data2, &Obj), Symbol3(Data3, &Obj),
-      Symbol4(Data4, &Obj);
-  ELFSymbolRef ELFSymbol1(Symbol1), ELFSymbol2(Symbol2), ELFSymbol3(Symbol3),
-      ELFSymbol4(Symbol4);
+  ELFSymbolRef ELFSymLowLow = MakeSymbol(ValLow, ValLow);
+  ELFSymbolRef ELFSymLowHigh = MakeSymbol(ValLow, ValHigh);
+  ELFSymbolRef ELFSymHighLow = MakeSymbol(ValHigh, ValLow);
+  ELFSymbolRef ELFSymHighHigh = MakeSymbol(ValHigh, ValHigh);
 
   // Symtab index match
-  // left sym index is lower
-  EXPECT_TRUE(ELFSymbol1 < ELFSymbol2);
-  EXPECT_TRUE(ELFSymbol3 < ELFSymbol4);
-  // right sym index is lower
-  EXPECT_FALSE(ELFSymbol2 < ELFSymbol1);
-  EXPECT_FALSE(ELFSymbol4 < ELFSymbol3);
-  // sym indexes match
-  EXPECT_FALSE(ELFSymbol1 < ELFSymbol1);
-  EXPECT_FALSE(ELFSymbol2 < ELFSymbol2);
-  EXPECT_FALSE(ELFSymbol3 < ELFSymbol3);
-  EXPECT_FALSE(ELFSymbol4 < ELFSymbol4);
+  // Left symbol index is lower
+  EXPECT_TRUE(ELFSymLowLow < ELFSymLowHigh);
+  // Right symbol index is lower
+  EXPECT_FALSE(ELFSymLowHigh < ELFSymLowLow);
+  // Symbol indices match
+  EXPECT_FALSE(ELFSymLowLow < ELFSymLowLow);
 
   // Left symtab index is lower
-  // left sym index is lower
-  EXPECT_TRUE(ELFSymbol1 < ELFSymbol4);
-  // right sym index is lower
-  EXPECT_TRUE(ELFSymbol2 < ELFSymbol3);
-  // sym indexes match
-  EXPECT_TRUE(ELFSymbol1 < ELFSymbol3);
-  EXPECT_TRUE(ELFSymbol2 < ELFSymbol4);
+  // Left symbol index is lower
+  EXPECT_TRUE(ELFSymLowLow < ELFSymHighHigh);
+  // Right symbol index is lower
+  EXPECT_TRUE(ELFSymLowHigh < ELFSymHighLow);
+  // Symbol indices match
+  EXPECT_TRUE(ELFSymLowLow < ELFSymHighLow);
 
   // Right symtab index is lower
-  // left sym index is lower
-  EXPECT_FALSE(ELFSymbol3 < ELFSymbol2);
-  // right sym index is lower
-  EXPECT_FALSE(ELFSymbol4 < ELFSymbol1);
-  // sym indexes match
-  EXPECT_FALSE(ELFSymbol3 < ELFSymbol1);
-  EXPECT_FALSE(ELFSymbol4 < ELFSymbol2);
+  // Left symbol index is lower
+  EXPECT_FALSE(ELFSymHighLow < ELFSymLowHigh);
+  // Right symbol index is lower
+  EXPECT_FALSE(ELFSymHighHigh < ELFSymLowLow);
+  // Symbol indices match
+  EXPECT_FALSE(ELFSymHighLow < ELFSymLowLow);
 }



More information about the llvm-commits mailing list