[PATCH] D80059: [ELF] Parse SHT_GNU_verneed and respect versioned undefined symbols in shared objects

George Rimar via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed May 20 02:07:16 PDT 2020


grimar added inline comments.


================
Comment at: lld/ELF/InputFiles.cpp:1217
+// sophisticated error checking in llvm-readobj because the value of diagnostics
+// is low.
+template <typename ELFT>
----------------
grimar wrote:
> in llvm-readobj?
It was not addressed. It doesn't read right to me:
"...but do not implement sophisticated error checking in llvm-readobj because..."

I guess you have meant "checking in LLD" or "checking like in llvm-readobj".


================
Comment at: lld/ELF/InputFiles.cpp:1235
+            Twine::utohexstr(verneedBuf - obj.base()));
+      return {};
+    }
----------------
MaskRay wrote:
> grimar wrote:
> > What about introducing a helper lambda:
> > 
> > ```
> > auto checkBuf = [](const uint8_t *Buf, const Twine& Name) {
> >   if (B < secEnd && uintptr_t(verneedBuf) % sizeof(uint32_t) == 0)
> >     return true;
> >   error(... invalid " + Name + " at ... )
> >   return false;
> > }
> > ```
> > 
> > It should simplify the code a bit I guess.
> The similar diagnostics occur twice. For `checkBuf`, we will need:
> 
> ```
> if (!checkBuf(...))
>   return false;
> ```
> 
> The end result will be longer.
I also do not think it is important to use `error()` for invalid objects. In many places
LLD calls `fatal()`. Then you can simplify the code. E.g (I've not checked it):


```
  ArrayRef<uint8_t> data =
      CHECK(obj.template getSectionContentsAsArray<uint8_t>(sec), this);
  const uint8_t *verneedBuf = data.begin();

  auto checkBuf = [&](uint8_t *buf, size_t size, size_t align) {
    if (buf + size > data.end() || uintptr_t(buf) % align != 0)
      fatal(toString(this) + ": unable to parse SHT_GNU_verneed");
    return buf;
  };

  for (unsigned i = 0; i != sec->sh_info; ++i) {
    auto *vn = reinterpret_cast<const typename ELFT::Verneed *>(
        checkBuf(verneedBuf, sizeof(typename ELFT::Verneed), sizeof(uint32_t)));
    const uint8_t *vernauxBuf = verneedBuf + vn->vn_aux;
    for (unsigned j = 0; j != vn->vn_cnt; ++j) {
      auto *aux = reinterpret_cast<const typename ELFT::Vernaux *>(checkBuf(
          vernauxBuf, sizeof(typename ELFT::Vernaux), sizeof(uint32_t)));
      uint16_t version = aux->vna_other & VERSYM_VERSION;
      if (version >= verneeds.size())
        verneeds.resize(version + 1);
      if (aux->vna_name >= this->stringTable.size())
        fatal(toString(this) + ": unable to parse SHT_GNU_verneed");
      verneeds[version] = aux->vna_name;
      vernauxBuf += aux->vna_next;
    }
    verneedBuf += vn->vn_next;
  }
  return verneeds;
}
```


================
Comment at: lld/ELF/InputFiles.cpp:1225
+
+  const uint8_t *verneedBuf = obj.base() + sec->sh_offset;
+  const uint8_t *bufEnd =
----------------
This looks a bit cleaner probably:

```
  ArrayRef<uint8_t> data =
      CHECK(obj.template getSectionContentsAsArray<uint8_t>(sec), this);
  const uint8_t *verneedBuf = data.begin();
```

And then you can just inline `bufEnd` as `data.end()` I think. See below.


================
Comment at: lld/ELF/InputFiles.cpp:1228
+      obj.base() +
+      std::min<size_t>(sec->sh_offset + sec->sh_size, obj.getBufSize());
+  for (unsigned i = 0; i != sec->sh_info; ++i) {
----------------
`sh_offset` for ELF64 is `packed<uint>`, which is `std::conditional_t<Is64, uint64_t, uint32_t>`, i.e. it is `uint64_t`,
so I think `size_t` is not a right thing here.


================
Comment at: lld/ELF/Symbols.cpp:717
 void Symbol::resolveShared(const SharedSymbol &other) {
+
   if (isCommon()) {
----------------
unrelated


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80059/new/

https://reviews.llvm.org/D80059





More information about the llvm-commits mailing list