aboutsummaryrefslogtreecommitdiff
path: root/tools/llc/TextStubWriter.cpp
blob: ae6e2f77d387a2146c4788cbb8ecc120978bc1f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Using the high-level representation of an ELF stub, create a text version
// of the ELF stub object.

#include "TextStubWriter.h"

#include <sstream>

#include "ELFStub.h"
#include "llvm/Support/ELF.h"

using namespace llvm;

namespace {

std::string LibShortname(const std::string &fullname) {
  std::string result = fullname;
  if (result.find("lib") != std::string::npos) {
    result = result.substr(3);
  }
  size_t so_pos = result.find(".so");
  if (so_pos != std::string::npos) {
    result = result.substr(0, so_pos);
  }
  return result;
}

const ELF::Elf32_Half kDummyCodeShndx = 5;
const ELF::Elf32_Half kDummyDataShndx = 6;

}  // namespace

namespace llvm {

// Write out the dynamic symbol table information.  The format must be kept
// in sync with the changes in NaCl's version of gold (see gold/metadata.cc).
void WriteTextELFStub(const ELFStub *Stub, std::string *output) {
  std::stringstream ss;

  ss << "#### Symtab for " << Stub->SOName << "\n";
  ss << "@obj " << LibShortname(Stub->SOName) << " " << Stub->SOName << "\n";

  // st_value is usually a relative address for .so, and .exe files.
  // So, make some up.
  ELF::Elf32_Addr fake_relative_addr = 0;
  for (size_t i = 0; i < Stub->Symbols.size(); ++i) {
    const SymbolStub &sym = Stub->Symbols[i];

    ELF::Elf32_Addr st_value = fake_relative_addr;
    ELF::Elf32_Word st_size = sym.Size;
    unsigned int st_info = sym.Type | (sym.Binding << 4);
    unsigned int st_other = sym.Visibility;
    ELF::Elf32_Half st_shndx = sym.Type == ELF::STT_FUNC ?
      kDummyCodeShndx : kDummyDataShndx;
    ELF::Elf32_Half vd_ndx = sym.VersionIndex;
    // Mark non-default versions hidden.
    if (!sym.IsDefault) {
      vd_ndx |= ELF::VERSYM_HIDDEN;
    }

    ss << "@sym "
       << sym.Name << " " // Representative for st_name.
       << (st_value) << " "
       << (st_size) << " "
       << (st_info) << " "
       << (st_other) << " "
       << (st_shndx) << " "
       << (vd_ndx) << " "
       << "\n";
    fake_relative_addr += (sym.Size == 0 ? 4 : sym.Size);
  }

  // Now dump the version map.
  ss << "#### VerDefs for " << Stub->SOName << "\n";
  for (size_t i = 0; i < Stub->VerDefs.size(); ++i) {
    const VersionDefinition &verdef = Stub->VerDefs[i];
    ss << "@ver " << (Elf32_Half)(verdef.Index) << " " << verdef.Name << "\n";
  }

  ss << "\n";

  output->append(ss.str());
}

} // namespace llvm