[llvm-commits] [lld] Supporting archive libraries in lld

Michael Spencer bigcheesegs at gmail.com
Tue Nov 6 14:51:42 PST 2012


On Tue, Nov 6, 2012 at 8:30 AM, Shankar Easwaran
<shankare at codeaurora.org> wrote:
> Hi Nick, Michael,
>
> I incorporated your comments in lld / llvm for supporting reading archive
> libraries.
>
> Please look at the new changes and let me know if you are ok to commit this
> in.
>
> Thanks
>
> Shankar Easwaran
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by
> the Linux Foundation
>

> Index: lib/Object/Archive.cpp
> ===================================================================
> --- lib/Object/Archive.cpp  (revision 167054)
> +++ lib/Object/Archive.cpp  (working copy)
> @@ -122,7 +122,15 @@
>                     + sizeof(ArchiveMemberHeader)
>                     + Parent->StringTable->getSize()))
>        return object_error::parse_failed;
> +
> +    // The filename would exist in the StringTable only if the filename
> +    // is a long filename. The filename be terminated by a /

This should read:

GNU long file names end with a /.

> +    if (Parent->kind() == K_GNU) {
> +      StringRef::size_type end = StringRef(addr).find('/');

End

> +      Result = StringRef(addr, end);
> +    } else {
>      Result = addr;

This needs to be indented.

> +    }
>      return object_error::success;
>    } else if (name.startswith("#1/")) {
>      APInt name_size;
> @@ -187,7 +195,40 @@
>    child_iterator i = begin_children(false);
>    child_iterator e = end_children();
>
> -  if (i != e) ++i; // Nobody cares about the first member.
> +  StringRef name;
> +  if ((ec = i->getName(name)))
> +    return;
> +
> +  // Below is the pattern that is used to figure out the archive format
> +  // GNU archive format
> +  //  First member : / (points to the symbol table )
> +  //  Second member : // (may exist, if it exists, points to the string table)
> +  //  Note : The string table is used if the filename exceeds 15 characters
> +  // BSD archive format
> +  //  First member : __.SYMDEF (points to the symbol table)
> +  //  There is no string table, if the filename exceeds 15 characters or has a
> +  //  embedded space, the filename has #1/<size>, The size represents the size
> +  //  of the filename that needs to be read after the archive header
> +  //  COFF archive format

This should be spaced the same as GNU archive format and BSD archive format.

> +  //  First member : /
> +  //  Second member : / (provides a directory of symbols)
> +  //  Third member : // contains the string table, this is present even if the
> +  //                    string table is empty
> +  if (name == "/") {
> +    SymbolTable = i;
> +    StringTable = e;
> +    if (i != e) ++i;
> +    if ((ec = i->getName(name)))
> +      return;
> +    const char *data = name.data();
> +    if (data[0] != '/') {

You don't need to convert to a const char * to do this. name[0] is the same.

> +      Format = K_GNU;
> +    } else if (data[1] == '/') {
> +      Format = K_GNU;
> +      StringTable = i;
> +      ++i;
> +    } else  {
> +      Format = K_COFF;
>    if (i != e) {
>      SymbolTable = i;
>      ++i;
> @@ -195,7 +236,12 @@
>    if (i != e) {
>      StringTable = i;
>    }

This needs to be indented.

> -
> +    }
> +  } else if (name == "__.SYMDEF") {
> +    Format = K_BSD;
> +    SymbolTable = i;
> +    StringTable = e;
> +  }
>    ec = object_error::success;
>  }
>
> @@ -222,17 +268,28 @@
>
>  error_code Archive::Symbol::getMember(child_iterator &Result) const {
>    const char *buf = Parent->SymbolTable->getBuffer()->getBufferStart();
> -  uint32_t member_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
>    const char *offsets = buf + 4;
> +  uint32_t offset = 0;
> +  if (Parent->kind() == K_GNU) {
> +    offset = *(reinterpret_cast<const support::ubig32_t*>(offsets)
> +                          + SymbolIndex);
> +  } else if (Parent->kind() == K_BSD) {
> +    assert("BSD format is not supported");
> +  } else {
> +    uint32_t member_count = 0;
> +    member_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
>    buf += 4 + (member_count * 4); // Skip offsets.
>    const char *indicies = buf + 4;
> -
>    uint16_t offsetindex =
>      *(reinterpret_cast<const support::ulittle16_t*>(indicies)
>        + SymbolIndex);

Indentation is wrong.

> -
> -  uint32_t offset = *(reinterpret_cast<const support::ulittle32_t*>(offsets)
> +    uint32_t *offsetaddr =
> +             (uint32_t *)(reinterpret_cast<const support::ulittle32_t*>(offsets)
>                        + (offsetindex - 1));
> +    assert((const char *)offsetaddr <
> +           Parent->SymbolTable->getBuffer()->getBufferEnd());
> +    offset = *(offsetaddr);
> +  }
>
>    const char *Loc = Parent->getData().begin() + offset;
>    size_t Size = sizeof(ArchiveMemberHeader) +
> @@ -253,10 +310,20 @@
>
>  Archive::symbol_iterator Archive::begin_symbols() const {
>    const char *buf = SymbolTable->getBuffer()->getBufferStart();
> -  uint32_t member_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
> +  if (kind() == K_GNU) {
> +    uint32_t symbol_count = 0;
> +    symbol_count = *reinterpret_cast<const support::ubig32_t*>(buf);
> +    buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t)));
> +  } else if (kind() == K_BSD) {
> +    assert("BSD archive format is not supported");
> +  } else {
> +    uint32_t member_count = 0;
> +    uint32_t symbol_count = 0;
> +    member_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
>    buf += 4 + (member_count * 4); // Skip offsets.

Indentation.

> -  uint32_t symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
> +    symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
>    buf += 4 + (symbol_count * 2); // Skip indices.

Indentation.

> +  }
>    uint32_t string_start_offset =
>      buf - SymbolTable->getBuffer()->getBufferStart();
>    return symbol_iterator(Symbol(this, 0, string_start_offset));
> @@ -264,9 +331,37 @@
>
>  Archive::symbol_iterator Archive::end_symbols() const {
>    const char *buf = SymbolTable->getBuffer()->getBufferStart();
> -  uint32_t member_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
> +  uint32_t symbol_count = 0;
> +  if (kind() == K_GNU) {
> +    symbol_count = *reinterpret_cast<const support::ubig32_t*>(buf);
> +    buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t)));
> +  } else if (kind() == K_BSD) {
> +    assert("BSD archive format is not supported");
> +  } else {
> +    uint32_t member_count = 0;
> +    member_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
>    buf += 4 + (member_count * 4); // Skip offsets.

Indentation.

> -  uint32_t symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
> +    symbol_count = *reinterpret_cast<const support::ulittle32_t*>(buf);
> +  }
>    return symbol_iterator(
>      Symbol(this, symbol_count, 0));
>  }
> +
> +error_code Archive::findSym(StringRef name, child_iterator &result) const {
> +  error_code ec;
> +  StringRef symname;
> +  Archive::symbol_iterator bs = begin_symbols();
> +  Archive::symbol_iterator es = end_symbols();
> +
> +  for (; bs != es; ++bs)
> +  {

No newline before {.

> +    if ((ec = bs->getName(symname)))
> +        return ec;
> +    if (symname == name) {
> +      if ((ec = bs->getMember(result)))
> +        return ec;
> +      return error_code::success();
> +    }
> +  }
> +  return object_error::parse_failed;

This is not the right error code. parse_failed means that the file is
corrupt. This should return a child_iterator.

> +}
>

- Michael Spencer



More information about the llvm-commits mailing list