//===- subzero/src/IceELFSection.cpp - Representation of ELF sections -----===//
//
//                        The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines how ELF sections are represented.
//
//===----------------------------------------------------------------------===//

#include "IceDefs.h"
#include "IceELFSection.h"
#include "IceELFStreamer.h"

using namespace llvm::ELF;

namespace Ice {

// Text sections.

void ELFTextSection::appendData(ELFStreamer &Str,
                                const llvm::StringRef MoreData) {
  Str.writeBytes(MoreData);
  Header.sh_size += MoreData.size();
}

// Data sections.

void ELFDataSection::appendData(ELFStreamer &Str,
                                const llvm::StringRef MoreData) {
  Str.writeBytes(MoreData);
  Header.sh_size += MoreData.size();
}

// Relocation sections.

void ELFRelocationSection::addRelocations(RelocOffsetT BaseOff,
                                          const FixupRefList &FixupRefs) {
  for (const AssemblerFixup *FR : FixupRefs) {
    Fixups.push_back(*FR);
    AssemblerFixup &F = Fixups.back();
    F.set_position(BaseOff + F.position());
  }
}

size_t ELFRelocationSection::getSectionDataSize(
    const GlobalContext &Ctx, const ELFSymbolTableSection *SymTab) const {
  size_t NumWriteableRelocs = 0;
  for (const AssemblerFixup &Fixup : Fixups) {
    const ELFSym *Symbol = SymTab->findSymbol(Fixup.symbol(&Ctx));
    // TODO(jvoung): When the symbol table finally tracks everything,
    // just use the Fixups.size() as the count, and remove the
    // SymTab and Ctx params.
    if (Symbol)
      ++NumWriteableRelocs;
  }
  return NumWriteableRelocs * Header.sh_entsize;
}

// Symbol tables.

void ELFSymbolTableSection::createDefinedSym(const IceString &Name,
                                             uint8_t Type, uint8_t Binding,
                                             ELFSection *Section,
                                             RelocOffsetT Offset, SizeT Size) {
  ELFSym NewSymbol = ELFSym();
  NewSymbol.Sym.setBindingAndType(Binding, Type);
  NewSymbol.Sym.st_value = Offset;
  NewSymbol.Sym.st_size = Size;
  NewSymbol.Section = Section;
  NewSymbol.Number = ELFSym::UnknownNumber;
  bool Unique;
  if (Type == STB_LOCAL)
    Unique = LocalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
  else
    Unique = GlobalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
  assert(Unique);
  (void)Unique;
}

void ELFSymbolTableSection::noteUndefinedSym(const IceString &Name,
                                             ELFSection *NullSection) {
  ELFSym NewSymbol = ELFSym();
  NewSymbol.Sym.setBindingAndType(STB_GLOBAL, STT_NOTYPE);
  NewSymbol.Section = NullSection;
  NewSymbol.Number = ELFSym::UnknownNumber;
  GlobalSymbols.insert(std::make_pair(Name, NewSymbol));
}

const ELFSym *ELFSymbolTableSection::findSymbol(const IceString &Name) const {
  auto I = LocalSymbols.find(Name);
  if (I != LocalSymbols.end())
    return &I->second;
  I = GlobalSymbols.find(Name);
  if (I != GlobalSymbols.end())
    return &I->second;
  return nullptr;
}

void ELFSymbolTableSection::updateIndices(const ELFStringTableSection *StrTab) {
  SizeT SymNumber = 0;
  for (auto &KeyValue : LocalSymbols) {
    const IceString &Name = KeyValue.first;
    ELFSection *Section = KeyValue.second.Section;
    Elf64_Sym &SymInfo = KeyValue.second.Sym;
    if (!Name.empty())
      SymInfo.st_name = StrTab->getIndex(Name);
    SymInfo.st_shndx = Section->getNumber();
    KeyValue.second.setNumber(SymNumber++);
  }
  for (auto &KeyValue : GlobalSymbols) {
    const IceString &Name = KeyValue.first;
    ELFSection *Section = KeyValue.second.Section;
    Elf64_Sym &SymInfo = KeyValue.second.Sym;
    if (!Name.empty())
      SymInfo.st_name = StrTab->getIndex(Name);
    SymInfo.st_shndx = Section->getNumber();
    KeyValue.second.setNumber(SymNumber++);
  }
}

void ELFSymbolTableSection::writeData(ELFStreamer &Str, bool IsELF64) {
  if (IsELF64) {
    writeSymbolMap<true>(Str, LocalSymbols);
    writeSymbolMap<true>(Str, GlobalSymbols);
  } else {
    writeSymbolMap<false>(Str, LocalSymbols);
    writeSymbolMap<false>(Str, GlobalSymbols);
  }
}

// String tables.

void ELFStringTableSection::add(const IceString &Str) {
  assert(!isLaidOut());
  assert(!Str.empty());
  StringToIndexMap.insert(std::make_pair(Str, UnknownIndex));
}

size_t ELFStringTableSection::getIndex(const IceString &Str) const {
  assert(isLaidOut());
  StringToIndexType::const_iterator It = StringToIndexMap.find(Str);
  if (It == StringToIndexMap.end()) {
    llvm_unreachable("String index not found");
    return UnknownIndex;
  }
  return It->second;
}

bool ELFStringTableSection::SuffixComparator::
operator()(const IceString &StrA, const IceString &StrB) const {
  size_t LenA = StrA.size();
  size_t LenB = StrB.size();
  size_t CommonLen = std::min(LenA, LenB);
  // If there is a difference in the common suffix, use that diff to sort.
  for (size_t i = 0; i < CommonLen; ++i) {
    char a = StrA[LenA - i - 1];
    char b = StrB[LenB - i - 1];
    if (a != b)
      return a > b;
  }
  // If the common suffixes are completely equal, let the longer one come
  // first, so that it can be laid out first and its characters shared.
  return LenA > LenB;
}

void ELFStringTableSection::doLayout() {
  assert(!isLaidOut());
  llvm::StringRef Prev;

  // String table starts with 0 byte.
  StringData.push_back(0);

  for (auto &StringIndex : StringToIndexMap) {
    assert(StringIndex.second == UnknownIndex);
    llvm::StringRef Cur = llvm::StringRef(StringIndex.first);
    if (Prev.endswith(Cur)) {
      // Prev is already in the StringData, and Cur is shorter than Prev
      // based on the sort.
      StringIndex.second = StringData.size() - Cur.size() - 1;
      continue;
    }
    StringIndex.second = StringData.size();
    std::copy(Cur.begin(), Cur.end(), back_inserter(StringData));
    StringData.push_back(0);
    Prev = Cur;
  }
}

} // end of namespace Ice
