namespace lld {
namespace coff {
-SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
- : Chunk(SectionKind), File(F), Header(H), Repl(this) {
+SectionChunk::SectionChunk(ObjFile *f, const coff_section *h)
+ : Chunk(SectionKind), file(f), header(h), repl(this) {
// Initialize Relocs.
- setRelocs(File->getCOFFObj()->getRelocations(Header));
+ setRelocs(file->getCOFFObj()->getRelocations(header));
// Initialize SectionName.
- StringRef SectionName;
- if (Expected<StringRef> E = File->getCOFFObj()->getSectionName(Header))
- SectionName = *E;
- SectionNameData = SectionName.data();
- SectionNameSize = SectionName.size();
+ StringRef sectionName;
+ if (Expected<StringRef> e = file->getCOFFObj()->getSectionName(header))
+ sectionName = *e;
+ sectionNameData = sectionName.data();
+ sectionNameSize = sectionName.size();
- setAlignment(Header->getAlignment());
+ setAlignment(header->getAlignment());
- HasData = !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
+ hasData = !(header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
// If linker GC is disabled, every chunk starts out alive. If linker GC is
// enabled, treat non-comdat sections as roots. Generally optimized object
// files will be built with -ffunction-sections or /Gy, so most things worth
// stripping will be in a comdat.
- Live = !Config->DoGC || !isCOMDAT();
+ live = !config->doGC || !isCOMDAT();
}
// SectionChunk is one of the most frequently allocated classes, so it is
// below is the size of this class on x64 platforms.
static_assert(sizeof(SectionChunk) <= 88, "SectionChunk grew unexpectedly");
-static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
-static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
-static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
-static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
-static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); }
+static void add16(uint8_t *p, int16_t v) { write16le(p, read16le(p) + v); }
+static void add32(uint8_t *p, int32_t v) { write32le(p, read32le(p) + v); }
+static void add64(uint8_t *p, int64_t v) { write64le(p, read64le(p) + v); }
+static void or16(uint8_t *p, uint16_t v) { write16le(p, read16le(p) | v); }
+static void or32(uint8_t *p, uint32_t v) { write32le(p, read32le(p) | v); }
// Verify that given sections are appropriate targets for SECREL
// relocations. This check is relaxed because unfortunately debug
// sections have section-relative relocations against absolute symbols.
-static bool checkSecRel(const SectionChunk *Sec, OutputSection *OS) {
- if (OS)
+static bool checkSecRel(const SectionChunk *sec, OutputSection *os) {
+ if (os)
return true;
- if (Sec->isCodeView())
+ if (sec->isCodeView())
return false;
error("SECREL relocation cannot be applied to absolute symbols");
return false;
}
-static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
- OutputSection *OS, uint64_t S) {
- if (!checkSecRel(Sec, OS))
+static void applySecRel(const SectionChunk *sec, uint8_t *off,
+ OutputSection *os, uint64_t s) {
+ if (!checkSecRel(sec, os))
return;
- uint64_t SecRel = S - OS->getRVA();
- if (SecRel > UINT32_MAX) {
- error("overflow in SECREL relocation in section: " + Sec->getSectionName());
+ uint64_t secRel = s - os->getRVA();
+ if (secRel > UINT32_MAX) {
+ error("overflow in SECREL relocation in section: " + sec->getSectionName());
return;
}
- add32(Off, SecRel);
+ add32(off, secRel);
}
-static void applySecIdx(uint8_t *Off, OutputSection *OS) {
+static void applySecIdx(uint8_t *off, OutputSection *os) {
// Absolute symbol doesn't have section index, but section index relocation
// against absolute symbol should be resolved to one plus the last output
// section index. This is required for compatibility with MSVC.
- if (OS)
- add16(Off, OS->SectionIndex);
+ if (os)
+ add16(off, os->sectionIndex);
else
- add16(Off, DefinedAbsolute::NumOutputSections + 1);
-}
-
-void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS,
- uint64_t S, uint64_t P) const {
- switch (Type) {
- case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break;
- case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break;
- case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break;
- case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break;
- case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break;
- case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break;
- case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break;
- case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break;
- case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break;
- case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break;
- case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break;
+ add16(off, DefinedAbsolute::numOutputSections + 1);
+}
+
+void SectionChunk::applyRelX64(uint8_t *off, uint16_t type, OutputSection *os,
+ uint64_t s, uint64_t p) const {
+ switch (type) {
+ case IMAGE_REL_AMD64_ADDR32: add32(off, s + config->imageBase); break;
+ case IMAGE_REL_AMD64_ADDR64: add64(off, s + config->imageBase); break;
+ case IMAGE_REL_AMD64_ADDR32NB: add32(off, s); break;
+ case IMAGE_REL_AMD64_REL32: add32(off, s - p - 4); break;
+ case IMAGE_REL_AMD64_REL32_1: add32(off, s - p - 5); break;
+ case IMAGE_REL_AMD64_REL32_2: add32(off, s - p - 6); break;
+ case IMAGE_REL_AMD64_REL32_3: add32(off, s - p - 7); break;
+ case IMAGE_REL_AMD64_REL32_4: add32(off, s - p - 8); break;
+ case IMAGE_REL_AMD64_REL32_5: add32(off, s - p - 9); break;
+ case IMAGE_REL_AMD64_SECTION: applySecIdx(off, os); break;
+ case IMAGE_REL_AMD64_SECREL: applySecRel(this, off, os, s); break;
default:
- error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
- toString(File));
+ error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " +
+ toString(file));
}
}
-void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS,
- uint64_t S, uint64_t P) const {
- switch (Type) {
+void SectionChunk::applyRelX86(uint8_t *off, uint16_t type, OutputSection *os,
+ uint64_t s, uint64_t p) const {
+ switch (type) {
case IMAGE_REL_I386_ABSOLUTE: break;
- case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break;
- case IMAGE_REL_I386_DIR32NB: add32(Off, S); break;
- case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break;
- case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break;
- case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break;
+ case IMAGE_REL_I386_DIR32: add32(off, s + config->imageBase); break;
+ case IMAGE_REL_I386_DIR32NB: add32(off, s); break;
+ case IMAGE_REL_I386_REL32: add32(off, s - p - 4); break;
+ case IMAGE_REL_I386_SECTION: applySecIdx(off, os); break;
+ case IMAGE_REL_I386_SECREL: applySecRel(this, off, os, s); break;
default:
- error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
- toString(File));
+ error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " +
+ toString(file));
}
}
-static void applyMOV(uint8_t *Off, uint16_t V) {
- write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf));
- write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff));
+static void applyMOV(uint8_t *off, uint16_t v) {
+ write16le(off, (read16le(off) & 0xfbf0) | ((v & 0x800) >> 1) | ((v >> 12) & 0xf));
+ write16le(off + 2, (read16le(off + 2) & 0x8f00) | ((v & 0x700) << 4) | (v & 0xff));
}
-static uint16_t readMOV(uint8_t *Off, bool MOVT) {
- uint16_t Op1 = read16le(Off);
- if ((Op1 & 0xfbf0) != (MOVT ? 0xf2c0 : 0xf240))
- error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") +
+static uint16_t readMOV(uint8_t *off, bool movt) {
+ uint16_t op1 = read16le(off);
+ if ((op1 & 0xfbf0) != (movt ? 0xf2c0 : 0xf240))
+ error("unexpected instruction in " + Twine(movt ? "MOVT" : "MOVW") +
" instruction in MOV32T relocation");
- uint16_t Op2 = read16le(Off + 2);
- if ((Op2 & 0x8000) != 0)
- error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") +
+ uint16_t op2 = read16le(off + 2);
+ if ((op2 & 0x8000) != 0)
+ error("unexpected instruction in " + Twine(movt ? "MOVT" : "MOVW") +
" instruction in MOV32T relocation");
- return (Op2 & 0x00ff) | ((Op2 >> 4) & 0x0700) | ((Op1 << 1) & 0x0800) |
- ((Op1 & 0x000f) << 12);
+ return (op2 & 0x00ff) | ((op2 >> 4) & 0x0700) | ((op1 << 1) & 0x0800) |
+ ((op1 & 0x000f) << 12);
}
-void applyMOV32T(uint8_t *Off, uint32_t V) {
- uint16_t ImmW = readMOV(Off, false); // read MOVW operand
- uint16_t ImmT = readMOV(Off + 4, true); // read MOVT operand
- uint32_t Imm = ImmW | (ImmT << 16);
- V += Imm; // add the immediate offset
- applyMOV(Off, V); // set MOVW operand
- applyMOV(Off + 4, V >> 16); // set MOVT operand
+void applyMOV32T(uint8_t *off, uint32_t v) {
+ uint16_t immW = readMOV(off, false); // read MOVW operand
+ uint16_t immT = readMOV(off + 4, true); // read MOVT operand
+ uint32_t imm = immW | (immT << 16);
+ v += imm; // add the immediate offset
+ applyMOV(off, v); // set MOVW operand
+ applyMOV(off + 4, v >> 16); // set MOVT operand
}
-static void applyBranch20T(uint8_t *Off, int32_t V) {
- if (!isInt<21>(V))
+static void applyBranch20T(uint8_t *off, int32_t v) {
+ if (!isInt<21>(v))
error("relocation out of range");
- uint32_t S = V < 0 ? 1 : 0;
- uint32_t J1 = (V >> 19) & 1;
- uint32_t J2 = (V >> 18) & 1;
- or16(Off, (S << 10) | ((V >> 12) & 0x3f));
- or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+ uint32_t s = v < 0 ? 1 : 0;
+ uint32_t j1 = (v >> 19) & 1;
+ uint32_t j2 = (v >> 18) & 1;
+ or16(off, (s << 10) | ((v >> 12) & 0x3f));
+ or16(off + 2, (j1 << 13) | (j2 << 11) | ((v >> 1) & 0x7ff));
}
-void applyBranch24T(uint8_t *Off, int32_t V) {
- if (!isInt<25>(V))
+void applyBranch24T(uint8_t *off, int32_t v) {
+ if (!isInt<25>(v))
error("relocation out of range");
- uint32_t S = V < 0 ? 1 : 0;
- uint32_t J1 = ((~V >> 23) & 1) ^ S;
- uint32_t J2 = ((~V >> 22) & 1) ^ S;
- or16(Off, (S << 10) | ((V >> 12) & 0x3ff));
+ uint32_t s = v < 0 ? 1 : 0;
+ uint32_t j1 = ((~v >> 23) & 1) ^ s;
+ uint32_t j2 = ((~v >> 22) & 1) ^ s;
+ or16(off, (s << 10) | ((v >> 12) & 0x3ff));
// Clear out the J1 and J2 bits which may be set.
- write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+ write16le(off + 2, (read16le(off + 2) & 0xd000) | (j1 << 13) | (j2 << 11) | ((v >> 1) & 0x7ff));
}
-void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
- uint64_t S, uint64_t P) const {
+void SectionChunk::applyRelARM(uint8_t *off, uint16_t type, OutputSection *os,
+ uint64_t s, uint64_t p) const {
// Pointer to thumb code must have the LSB set.
- uint64_t SX = S;
- if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE))
- SX |= 1;
- switch (Type) {
- case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break;
- case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break;
- case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break;
- case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break;
- case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break;
- case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break;
- case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break;
- case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break;
- case IMAGE_REL_ARM_REL32: add32(Off, SX - P - 4); break;
+ uint64_t sx = s;
+ if (os && (os->header.Characteristics & IMAGE_SCN_MEM_EXECUTE))
+ sx |= 1;
+ switch (type) {
+ case IMAGE_REL_ARM_ADDR32: add32(off, sx + config->imageBase); break;
+ case IMAGE_REL_ARM_ADDR32NB: add32(off, sx); break;
+ case IMAGE_REL_ARM_MOV32T: applyMOV32T(off, sx + config->imageBase); break;
+ case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(off, sx - p - 4); break;
+ case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(off, sx - p - 4); break;
+ case IMAGE_REL_ARM_BLX23T: applyBranch24T(off, sx - p - 4); break;
+ case IMAGE_REL_ARM_SECTION: applySecIdx(off, os); break;
+ case IMAGE_REL_ARM_SECREL: applySecRel(this, off, os, s); break;
+ case IMAGE_REL_ARM_REL32: add32(off, sx - p - 4); break;
default:
- error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
- toString(File));
+ error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " +
+ toString(file));
}
}
// Interpret the existing immediate value as a byte offset to the
// target symbol, then update the instruction with the immediate as
// the page offset from the current instruction to the target.
-void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
- uint32_t Orig = read32le(Off);
- uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC);
- S += Imm;
- Imm = (S >> Shift) - (P >> Shift);
- uint32_t ImmLo = (Imm & 0x3) << 29;
- uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
- uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
- write32le(Off, (Orig & ~Mask) | ImmLo | ImmHi);
+void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift) {
+ uint32_t orig = read32le(off);
+ uint64_t imm = ((orig >> 29) & 0x3) | ((orig >> 3) & 0x1FFFFC);
+ s += imm;
+ imm = (s >> shift) - (p >> shift);
+ uint32_t immLo = (imm & 0x3) << 29;
+ uint32_t immHi = (imm & 0x1FFFFC) << 3;
+ uint64_t mask = (0x3 << 29) | (0x1FFFFC << 3);
+ write32le(off, (orig & ~mask) | immLo | immHi);
}
// Update the immediate field in a AARCH64 ldr, str, and add instruction.
// Optionally limit the range of the written immediate by one or more bits
// (RangeLimit).
-void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) {
- uint32_t Orig = read32le(Off);
- Imm += (Orig >> 10) & 0xFFF;
- Orig &= ~(0xFFF << 10);
- write32le(Off, Orig | ((Imm & (0xFFF >> RangeLimit)) << 10));
+void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit) {
+ uint32_t orig = read32le(off);
+ imm += (orig >> 10) & 0xFFF;
+ orig &= ~(0xFFF << 10);
+ write32le(off, orig | ((imm & (0xFFF >> rangeLimit)) << 10));
}
// Add the 12 bit page offset to the existing immediate.
// Even if larger loads/stores have a larger range, limit the
// effective offset to 12 bit, since it is intended to be a
// page offset.
-static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) {
- uint32_t Orig = read32le(Off);
- uint32_t Size = Orig >> 30;
+static void applyArm64Ldr(uint8_t *off, uint64_t imm) {
+ uint32_t orig = read32le(off);
+ uint32_t size = orig >> 30;
// 0x04000000 indicates SIMD/FP registers
// 0x00800000 indicates 128 bit
- if ((Orig & 0x4800000) == 0x4800000)
- Size += 4;
- if ((Imm & ((1 << Size) - 1)) != 0)
+ if ((orig & 0x4800000) == 0x4800000)
+ size += 4;
+ if ((imm & ((1 << size) - 1)) != 0)
error("misaligned ldr/str offset");
- applyArm64Imm(Off, Imm >> Size, Size);
+ applyArm64Imm(off, imm >> size, size);
}
-static void applySecRelLow12A(const SectionChunk *Sec, uint8_t *Off,
- OutputSection *OS, uint64_t S) {
- if (checkSecRel(Sec, OS))
- applyArm64Imm(Off, (S - OS->getRVA()) & 0xfff, 0);
+static void applySecRelLow12A(const SectionChunk *sec, uint8_t *off,
+ OutputSection *os, uint64_t s) {
+ if (checkSecRel(sec, os))
+ applyArm64Imm(off, (s - os->getRVA()) & 0xfff, 0);
}
-static void applySecRelHigh12A(const SectionChunk *Sec, uint8_t *Off,
- OutputSection *OS, uint64_t S) {
- if (!checkSecRel(Sec, OS))
+static void applySecRelHigh12A(const SectionChunk *sec, uint8_t *off,
+ OutputSection *os, uint64_t s) {
+ if (!checkSecRel(sec, os))
return;
- uint64_t SecRel = (S - OS->getRVA()) >> 12;
- if (0xfff < SecRel) {
+ uint64_t secRel = (s - os->getRVA()) >> 12;
+ if (0xfff < secRel) {
error("overflow in SECREL_HIGH12A relocation in section: " +
- Sec->getSectionName());
+ sec->getSectionName());
return;
}
- applyArm64Imm(Off, SecRel & 0xfff, 0);
+ applyArm64Imm(off, secRel & 0xfff, 0);
}
-static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off,
- OutputSection *OS, uint64_t S) {
- if (checkSecRel(Sec, OS))
- applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff);
+static void applySecRelLdr(const SectionChunk *sec, uint8_t *off,
+ OutputSection *os, uint64_t s) {
+ if (checkSecRel(sec, os))
+ applyArm64Ldr(off, (s - os->getRVA()) & 0xfff);
}
-void applyArm64Branch26(uint8_t *Off, int64_t V) {
- if (!isInt<28>(V))
+void applyArm64Branch26(uint8_t *off, int64_t v) {
+ if (!isInt<28>(v))
error("relocation out of range");
- or32(Off, (V & 0x0FFFFFFC) >> 2);
+ or32(off, (v & 0x0FFFFFFC) >> 2);
}
-static void applyArm64Branch19(uint8_t *Off, int64_t V) {
- if (!isInt<21>(V))
+static void applyArm64Branch19(uint8_t *off, int64_t v) {
+ if (!isInt<21>(v))
error("relocation out of range");
- or32(Off, (V & 0x001FFFFC) << 3);
+ or32(off, (v & 0x001FFFFC) << 3);
}
-static void applyArm64Branch14(uint8_t *Off, int64_t V) {
- if (!isInt<16>(V))
+static void applyArm64Branch14(uint8_t *off, int64_t v) {
+ if (!isInt<16>(v))
error("relocation out of range");
- or32(Off, (V & 0x0000FFFC) << 3);
-}
-
-void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
- uint64_t S, uint64_t P) const {
- switch (Type) {
- case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break;
- case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break;
- case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break;
- case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break;
- case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break;
- case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break;
- case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break;
- case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break;
- case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break;
- case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break;
- case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break;
- case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break;
- case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break;
- case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break;
- case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break;
- case IMAGE_REL_ARM64_REL32: add32(Off, S - P - 4); break;
+ or32(off, (v & 0x0000FFFC) << 3);
+}
+
+void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os,
+ uint64_t s, uint64_t p) const {
+ switch (type) {
+ case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(off, s, p, 12); break;
+ case IMAGE_REL_ARM64_REL21: applyArm64Addr(off, s, p, 0); break;
+ case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(off, s & 0xfff, 0); break;
+ case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(off, s & 0xfff); break;
+ case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(off, s - p); break;
+ case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(off, s - p); break;
+ case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(off, s - p); break;
+ case IMAGE_REL_ARM64_ADDR32: add32(off, s + config->imageBase); break;
+ case IMAGE_REL_ARM64_ADDR32NB: add32(off, s); break;
+ case IMAGE_REL_ARM64_ADDR64: add64(off, s + config->imageBase); break;
+ case IMAGE_REL_ARM64_SECREL: applySecRel(this, off, os, s); break;
+ case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, off, os, s); break;
+ case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, off, os, s); break;
+ case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, off, os, s); break;
+ case IMAGE_REL_ARM64_SECTION: applySecIdx(off, os); break;
+ case IMAGE_REL_ARM64_REL32: add32(off, s - p - 4); break;
default:
- error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
- toString(File));
+ error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " +
+ toString(file));
}
}
-static void maybeReportRelocationToDiscarded(const SectionChunk *FromChunk,
- Defined *Sym,
- const coff_relocation &Rel) {
+static void maybeReportRelocationToDiscarded(const SectionChunk *fromChunk,
+ Defined *sym,
+ const coff_relocation &rel) {
// Don't report these errors when the relocation comes from a debug info
// section or in mingw mode. MinGW mode object files (built by GCC) can
// have leftover sections with relocations against discarded comdat
// sections. Such sections are left as is, with relocations untouched.
- if (FromChunk->isCodeView() || FromChunk->isDWARF() || Config->MinGW)
+ if (fromChunk->isCodeView() || fromChunk->isDWARF() || config->mingw)
return;
// Get the name of the symbol. If it's null, it was discarded early, so we
// have to go back to the object file.
- ObjFile *File = FromChunk->File;
- StringRef Name;
- if (Sym) {
- Name = Sym->getName();
+ ObjFile *file = fromChunk->file;
+ StringRef name;
+ if (sym) {
+ name = sym->getName();
} else {
- COFFSymbolRef COFFSym =
- check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex));
- File->getCOFFObj()->getSymbolName(COFFSym, Name);
+ COFFSymbolRef coffSym =
+ check(file->getCOFFObj()->getSymbol(rel.SymbolTableIndex));
+ file->getCOFFObj()->getSymbolName(coffSym, name);
}
- std::vector<std::string> SymbolLocations =
- getSymbolLocations(File, Rel.SymbolTableIndex);
+ std::vector<std::string> symbolLocations =
+ getSymbolLocations(file, rel.SymbolTableIndex);
- std::string Out;
- llvm::raw_string_ostream OS(Out);
- OS << "relocation against symbol in discarded section: " + Name;
- for (const std::string &S : SymbolLocations)
- OS << S;
- error(OS.str());
+ std::string out;
+ llvm::raw_string_ostream os(out);
+ os << "relocation against symbol in discarded section: " + name;
+ for (const std::string &s : symbolLocations)
+ os << s;
+ error(os.str());
}
-void SectionChunk::writeTo(uint8_t *Buf) const {
- if (!HasData)
+void SectionChunk::writeTo(uint8_t *buf) const {
+ if (!hasData)
return;
// Copy section contents from source object file to output file.
- ArrayRef<uint8_t> A = getContents();
- if (!A.empty())
- memcpy(Buf, A.data(), A.size());
+ ArrayRef<uint8_t> a = getContents();
+ if (!a.empty())
+ memcpy(buf, a.data(), a.size());
// Apply relocations.
- size_t InputSize = getSize();
- for (size_t I = 0, E = RelocsSize; I < E; I++) {
- const coff_relocation &Rel = RelocsData[I];
+ size_t inputSize = getSize();
+ for (size_t i = 0, e = relocsSize; i < e; i++) {
+ const coff_relocation &rel = relocsData[i];
// Check for an invalid relocation offset. This check isn't perfect, because
// we don't have the relocation size, which is only known after checking the
// machine and relocation type. As a result, a relocation may overwrite the
// beginning of the following input section.
- if (Rel.VirtualAddress >= InputSize) {
+ if (rel.VirtualAddress >= inputSize) {
error("relocation points beyond the end of its parent section");
continue;
}
- uint8_t *Off = Buf + Rel.VirtualAddress;
+ uint8_t *off = buf + rel.VirtualAddress;
- auto *Sym =
- dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex));
+ auto *sym =
+ dyn_cast_or_null<Defined>(file->getSymbol(rel.SymbolTableIndex));
// Get the output section of the symbol for this relocation. The output
// section is needed to compute SECREL and SECTION relocations used in debug
// info.
- Chunk *C = Sym ? Sym->getChunk() : nullptr;
- OutputSection *OS = C ? C->getOutputSection() : nullptr;
+ Chunk *c = sym ? sym->getChunk() : nullptr;
+ OutputSection *os = c ? c->getOutputSection() : nullptr;
// Skip the relocation if it refers to a discarded section, and diagnose it
// as an error if appropriate. If a symbol was discarded early, it may be
// null. If it was discarded late, the output section will be null, unless
// it was an absolute or synthetic symbol.
- if (!Sym ||
- (!OS && !isa<DefinedAbsolute>(Sym) && !isa<DefinedSynthetic>(Sym))) {
- maybeReportRelocationToDiscarded(this, Sym, Rel);
+ if (!sym ||
+ (!os && !isa<DefinedAbsolute>(sym) && !isa<DefinedSynthetic>(sym))) {
+ maybeReportRelocationToDiscarded(this, sym, rel);
continue;
}
- uint64_t S = Sym->getRVA();
+ uint64_t s = sym->getRVA();
// Compute the RVA of the relocation for relative relocations.
- uint64_t P = RVA + Rel.VirtualAddress;
- switch (Config->Machine) {
+ uint64_t p = rva + rel.VirtualAddress;
+ switch (config->machine) {
case AMD64:
- applyRelX64(Off, Rel.Type, OS, S, P);
+ applyRelX64(off, rel.Type, os, s, p);
break;
case I386:
- applyRelX86(Off, Rel.Type, OS, S, P);
+ applyRelX86(off, rel.Type, os, s, p);
break;
case ARMNT:
- applyRelARM(Off, Rel.Type, OS, S, P);
+ applyRelARM(off, rel.Type, os, s, p);
break;
case ARM64:
- applyRelARM64(Off, Rel.Type, OS, S, P);
+ applyRelARM64(off, rel.Type, os, s, p);
break;
default:
llvm_unreachable("unknown machine type");
}
}
-void SectionChunk::addAssociative(SectionChunk *Child) {
+void SectionChunk::addAssociative(SectionChunk *child) {
// Insert this child at the head of the list.
- assert(Child->AssocChildren == nullptr &&
+ assert(child->assocChildren == nullptr &&
"associated sections cannot have their own associated children");
- Child->AssocChildren = AssocChildren;
- AssocChildren = Child;
+ child->assocChildren = assocChildren;
+ assocChildren = child;
}
-static uint8_t getBaserelType(const coff_relocation &Rel) {
- switch (Config->Machine) {
+static uint8_t getBaserelType(const coff_relocation &rel) {
+ switch (config->machine) {
case AMD64:
- if (Rel.Type == IMAGE_REL_AMD64_ADDR64)
+ if (rel.Type == IMAGE_REL_AMD64_ADDR64)
return IMAGE_REL_BASED_DIR64;
return IMAGE_REL_BASED_ABSOLUTE;
case I386:
- if (Rel.Type == IMAGE_REL_I386_DIR32)
+ if (rel.Type == IMAGE_REL_I386_DIR32)
return IMAGE_REL_BASED_HIGHLOW;
return IMAGE_REL_BASED_ABSOLUTE;
case ARMNT:
- if (Rel.Type == IMAGE_REL_ARM_ADDR32)
+ if (rel.Type == IMAGE_REL_ARM_ADDR32)
return IMAGE_REL_BASED_HIGHLOW;
- if (Rel.Type == IMAGE_REL_ARM_MOV32T)
+ if (rel.Type == IMAGE_REL_ARM_MOV32T)
return IMAGE_REL_BASED_ARM_MOV32T;
return IMAGE_REL_BASED_ABSOLUTE;
case ARM64:
- if (Rel.Type == IMAGE_REL_ARM64_ADDR64)
+ if (rel.Type == IMAGE_REL_ARM64_ADDR64)
return IMAGE_REL_BASED_DIR64;
return IMAGE_REL_BASED_ABSOLUTE;
default:
// Collect all locations that contain absolute addresses, which need to be
// fixed by the loader if load-time relocation is needed.
// Only called when base relocation is enabled.
-void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
- for (size_t I = 0, E = RelocsSize; I < E; I++) {
- const coff_relocation &Rel = RelocsData[I];
- uint8_t Ty = getBaserelType(Rel);
- if (Ty == IMAGE_REL_BASED_ABSOLUTE)
+void SectionChunk::getBaserels(std::vector<Baserel> *res) {
+ for (size_t i = 0, e = relocsSize; i < e; i++) {
+ const coff_relocation &rel = relocsData[i];
+ uint8_t ty = getBaserelType(rel);
+ if (ty == IMAGE_REL_BASED_ABSOLUTE)
continue;
- Symbol *Target = File->getSymbol(Rel.SymbolTableIndex);
- if (!Target || isa<DefinedAbsolute>(Target))
+ Symbol *target = file->getSymbol(rel.SymbolTableIndex);
+ if (!target || isa<DefinedAbsolute>(target))
continue;
- Res->emplace_back(RVA + Rel.VirtualAddress, Ty);
+ res->emplace_back(rva + rel.VirtualAddress, ty);
}
}
// another DLL) This returns the size the relocation is supposed to update,
// in bits, or 0 if the relocation cannot be handled as a runtime pseudo
// relocation.
-static int getRuntimePseudoRelocSize(uint16_t Type) {
+static int getRuntimePseudoRelocSize(uint16_t type) {
// Relocations that either contain an absolute address, or a plain
// relative offset, since the runtime pseudo reloc implementation
// adds 8/16/32/64 bit values to a memory address.
// the image, or temporarily changed at runtime with VirtualProtect.
// Since this only operates on direct address values, it doesn't work for
// ARM/ARM64 relocations, other than the plain ADDR32/ADDR64 relocations.
- switch (Config->Machine) {
+ switch (config->machine) {
case AMD64:
- switch (Type) {
+ switch (type) {
case IMAGE_REL_AMD64_ADDR64:
return 64;
case IMAGE_REL_AMD64_ADDR32:
return 0;
}
case I386:
- switch (Type) {
+ switch (type) {
case IMAGE_REL_I386_DIR32:
case IMAGE_REL_I386_REL32:
return 32;
return 0;
}
case ARMNT:
- switch (Type) {
+ switch (type) {
case IMAGE_REL_ARM_ADDR32:
return 32;
default:
return 0;
}
case ARM64:
- switch (Type) {
+ switch (type) {
case IMAGE_REL_ARM64_ADDR64:
return 64;
case IMAGE_REL_ARM64_ADDR32:
// to a module local variable, which turned out to actually need to be
// imported from another DLL).
void SectionChunk::getRuntimePseudoRelocs(
- std::vector<RuntimePseudoReloc> &Res) {
- for (const coff_relocation &Rel : getRelocs()) {
- auto *Target =
- dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex));
- if (!Target || !Target->IsRuntimePseudoReloc)
+ std::vector<RuntimePseudoReloc> &res) {
+ for (const coff_relocation &rel : getRelocs()) {
+ auto *target =
+ dyn_cast_or_null<Defined>(file->getSymbol(rel.SymbolTableIndex));
+ if (!target || !target->isRuntimePseudoReloc)
continue;
- int SizeInBits = getRuntimePseudoRelocSize(Rel.Type);
- if (SizeInBits == 0) {
- error("unable to automatically import from " + Target->getName() +
+ int sizeInBits = getRuntimePseudoRelocSize(rel.Type);
+ if (sizeInBits == 0) {
+ error("unable to automatically import from " + target->getName() +
" with relocation type " +
- File->getCOFFObj()->getRelocationTypeName(Rel.Type) + " in " +
- toString(File));
+ file->getCOFFObj()->getRelocationTypeName(rel.Type) + " in " +
+ toString(file));
continue;
}
// SizeInBits is used to initialize the Flags field; currently no
// other flags are defined.
- Res.emplace_back(
- RuntimePseudoReloc(Target, this, Rel.VirtualAddress, SizeInBits));
+ res.emplace_back(
+ RuntimePseudoReloc(target, this, rel.VirtualAddress, sizeInBits));
}
}
bool SectionChunk::isCOMDAT() const {
- return Header->Characteristics & IMAGE_SCN_LNK_COMDAT;
+ return header->Characteristics & IMAGE_SCN_LNK_COMDAT;
}
void SectionChunk::printDiscardedMessage() const {
// Removed by dead-stripping. If it's removed by ICF, ICF already
// printed out the name, so don't repeat that here.
- if (Sym && this == Repl)
- message("Discarded " + Sym->getName());
+ if (sym && this == repl)
+ message("Discarded " + sym->getName());
}
StringRef SectionChunk::getDebugName() const {
- if (Sym)
- return Sym->getName();
+ if (sym)
+ return sym->getName();
return "";
}
ArrayRef<uint8_t> SectionChunk::getContents() const {
- ArrayRef<uint8_t> A;
- cantFail(File->getCOFFObj()->getSectionContents(Header, A));
- return A;
+ ArrayRef<uint8_t> a;
+ cantFail(file->getCOFFObj()->getSectionContents(header, a));
+ return a;
}
ArrayRef<uint8_t> SectionChunk::consumeDebugMagic() {
return consumeDebugMagic(getContents(), getSectionName());
}
-ArrayRef<uint8_t> SectionChunk::consumeDebugMagic(ArrayRef<uint8_t> Data,
- StringRef SectionName) {
- if (Data.empty())
+ArrayRef<uint8_t> SectionChunk::consumeDebugMagic(ArrayRef<uint8_t> data,
+ StringRef sectionName) {
+ if (data.empty())
return {};
// First 4 bytes are section magic.
- if (Data.size() < 4)
- fatal("the section is too short: " + SectionName);
+ if (data.size() < 4)
+ fatal("the section is too short: " + sectionName);
- if (!SectionName.startswith(".debug$"))
- fatal("invalid section: " + SectionName);
+ if (!sectionName.startswith(".debug$"))
+ fatal("invalid section: " + sectionName);
- uint32_t Magic = support::endian::read32le(Data.data());
- uint32_t ExpectedMagic = SectionName == ".debug$H"
+ uint32_t magic = support::endian::read32le(data.data());
+ uint32_t expectedMagic = sectionName == ".debug$H"
? DEBUG_HASHES_SECTION_MAGIC
: DEBUG_SECTION_MAGIC;
- if (Magic != ExpectedMagic) {
- warn("ignoring section " + SectionName + " with unrecognized magic 0x" +
- utohexstr(Magic));
+ if (magic != expectedMagic) {
+ warn("ignoring section " + sectionName + " with unrecognized magic 0x" +
+ utohexstr(magic));
return {};
}
- return Data.slice(4);
+ return data.slice(4);
}
-SectionChunk *SectionChunk::findByName(ArrayRef<SectionChunk *> Sections,
- StringRef Name) {
- for (SectionChunk *C : Sections)
- if (C->getSectionName() == Name)
- return C;
+SectionChunk *SectionChunk::findByName(ArrayRef<SectionChunk *> sections,
+ StringRef name) {
+ for (SectionChunk *c : sections)
+ if (c->getSectionName() == name)
+ return c;
return nullptr;
}
-void SectionChunk::replace(SectionChunk *Other) {
- P2Align = std::max(P2Align, Other->P2Align);
- Other->Repl = Repl;
- Other->Live = false;
+void SectionChunk::replace(SectionChunk *other) {
+ p2Align = std::max(p2Align, other->p2Align);
+ other->repl = repl;
+ other->live = false;
}
uint32_t SectionChunk::getSectionNumber() const {
- DataRefImpl R;
- R.p = reinterpret_cast<uintptr_t>(Header);
- SectionRef S(R, File->getCOFFObj());
- return S.getIndex() + 1;
+ DataRefImpl r;
+ r.p = reinterpret_cast<uintptr_t>(header);
+ SectionRef s(r, file->getCOFFObj());
+ return s.getIndex() + 1;
}
-CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) {
+CommonChunk::CommonChunk(const COFFSymbolRef s) : sym(s) {
// The value of a common symbol is its size. Align all common symbols smaller
// than 32 bytes naturally, i.e. round the size up to the next power of two.
// This is what MSVC link.exe does.
- setAlignment(std::min(32U, uint32_t(PowerOf2Ceil(Sym.getValue()))));
- HasData = false;
+ setAlignment(std::min(32U, uint32_t(PowerOf2Ceil(sym.getValue()))));
+ hasData = false;
}
uint32_t CommonChunk::getOutputCharacteristics() const {
IMAGE_SCN_MEM_WRITE;
}
-void StringChunk::writeTo(uint8_t *Buf) const {
- memcpy(Buf, Str.data(), Str.size());
- Buf[Str.size()] = '\0';
+void StringChunk::writeTo(uint8_t *buf) const {
+ memcpy(buf, str.data(), str.size());
+ buf[str.size()] = '\0';
}
-ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImportThunkChunk(S) {
+ImportThunkChunkX64::ImportThunkChunkX64(Defined *s) : ImportThunkChunk(s) {
// Intel Optimization Manual says that all branch targets
// should be 16-byte aligned. MSVC linker does this too.
setAlignment(16);
}
-void ImportThunkChunkX64::writeTo(uint8_t *Buf) const {
- memcpy(Buf, ImportThunkX86, sizeof(ImportThunkX86));
+void ImportThunkChunkX64::writeTo(uint8_t *buf) const {
+ memcpy(buf, importThunkX86, sizeof(importThunkX86));
// The first two bytes is a JMP instruction. Fill its operand.
- write32le(Buf + 2, ImpSymbol->getRVA() - RVA - getSize());
+ write32le(buf + 2, impSymbol->getRVA() - rva - getSize());
}
-void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) {
- Res->emplace_back(getRVA() + 2);
+void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *res) {
+ res->emplace_back(getRVA() + 2);
}
-void ImportThunkChunkX86::writeTo(uint8_t *Buf) const {
- memcpy(Buf, ImportThunkX86, sizeof(ImportThunkX86));
+void ImportThunkChunkX86::writeTo(uint8_t *buf) const {
+ memcpy(buf, importThunkX86, sizeof(importThunkX86));
// The first two bytes is a JMP instruction. Fill its operand.
- write32le(Buf + 2,
- ImpSymbol->getRVA() + Config->ImageBase);
+ write32le(buf + 2,
+ impSymbol->getRVA() + config->imageBase);
}
-void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *Res) {
- Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T);
+void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *res) {
+ res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T);
}
-void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
- memcpy(Buf, ImportThunkARM, sizeof(ImportThunkARM));
+void ImportThunkChunkARM::writeTo(uint8_t *buf) const {
+ memcpy(buf, importThunkARM, sizeof(importThunkARM));
// Fix mov.w and mov.t operands.
- applyMOV32T(Buf, ImpSymbol->getRVA() + Config->ImageBase);
+ applyMOV32T(buf, impSymbol->getRVA() + config->imageBase);
}
-void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
- int64_t Off = ImpSymbol->getRVA() & 0xfff;
- memcpy(Buf, ImportThunkARM64, sizeof(ImportThunkARM64));
- applyArm64Addr(Buf, ImpSymbol->getRVA(), RVA, 12);
- applyArm64Ldr(Buf + 4, Off);
+void ImportThunkChunkARM64::writeTo(uint8_t *buf) const {
+ int64_t off = impSymbol->getRVA() & 0xfff;
+ memcpy(buf, importThunkARM64, sizeof(importThunkARM64));
+ applyArm64Addr(buf, impSymbol->getRVA(), rva, 12);
+ applyArm64Ldr(buf + 4, off);
}
// A Thumb2, PIC, non-interworking range extension thunk.
-const uint8_t ArmThunk[] = {
+const uint8_t armThunk[] = {
0x40, 0xf2, 0x00, 0x0c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
0xe7, 0x44, // L1: add pc, ip
};
size_t RangeExtensionThunkARM::getSize() const {
- assert(Config->Machine == ARMNT);
- return sizeof(ArmThunk);
+ assert(config->machine == ARMNT);
+ return sizeof(armThunk);
}
-void RangeExtensionThunkARM::writeTo(uint8_t *Buf) const {
- assert(Config->Machine == ARMNT);
- uint64_t Offset = Target->getRVA() - RVA - 12;
- memcpy(Buf, ArmThunk, sizeof(ArmThunk));
- applyMOV32T(Buf, uint32_t(Offset));
+void RangeExtensionThunkARM::writeTo(uint8_t *buf) const {
+ assert(config->machine == ARMNT);
+ uint64_t offset = target->getRVA() - rva - 12;
+ memcpy(buf, armThunk, sizeof(armThunk));
+ applyMOV32T(buf, uint32_t(offset));
}
// A position independent ARM64 adrp+add thunk, with a maximum range of
// +/- 4 GB, which is enough for any PE-COFF.
-const uint8_t Arm64Thunk[] = {
+const uint8_t arm64Thunk[] = {
0x10, 0x00, 0x00, 0x90, // adrp x16, Dest
0x10, 0x02, 0x00, 0x91, // add x16, x16, :lo12:Dest
0x00, 0x02, 0x1f, 0xd6, // br x16
};
size_t RangeExtensionThunkARM64::getSize() const {
- assert(Config->Machine == ARM64);
- return sizeof(Arm64Thunk);
+ assert(config->machine == ARM64);
+ return sizeof(arm64Thunk);
}
-void RangeExtensionThunkARM64::writeTo(uint8_t *Buf) const {
- assert(Config->Machine == ARM64);
- memcpy(Buf, Arm64Thunk, sizeof(Arm64Thunk));
- applyArm64Addr(Buf + 0, Target->getRVA(), RVA, 12);
- applyArm64Imm(Buf + 4, Target->getRVA() & 0xfff, 0);
+void RangeExtensionThunkARM64::writeTo(uint8_t *buf) const {
+ assert(config->machine == ARM64);
+ memcpy(buf, arm64Thunk, sizeof(arm64Thunk));
+ applyArm64Addr(buf + 0, target->getRVA(), rva, 12);
+ applyArm64Imm(buf + 4, target->getRVA() & 0xfff, 0);
}
-void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
- Res->emplace_back(getRVA());
+void LocalImportChunk::getBaserels(std::vector<Baserel> *res) {
+ res->emplace_back(getRVA());
}
-size_t LocalImportChunk::getSize() const { return Config->Wordsize; }
+size_t LocalImportChunk::getSize() const { return config->wordsize; }
-void LocalImportChunk::writeTo(uint8_t *Buf) const {
- if (Config->is64()) {
- write64le(Buf, Sym->getRVA() + Config->ImageBase);
+void LocalImportChunk::writeTo(uint8_t *buf) const {
+ if (config->is64()) {
+ write64le(buf, sym->getRVA() + config->imageBase);
} else {
- write32le(Buf, Sym->getRVA() + Config->ImageBase);
+ write32le(buf, sym->getRVA() + config->imageBase);
}
}
-void RVATableChunk::writeTo(uint8_t *Buf) const {
- ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf);
- size_t Cnt = 0;
- for (const ChunkAndOffset &CO : Syms)
- Begin[Cnt++] = CO.InputChunk->getRVA() + CO.Offset;
- std::sort(Begin, Begin + Cnt);
- assert(std::unique(Begin, Begin + Cnt) == Begin + Cnt &&
+void RVATableChunk::writeTo(uint8_t *buf) const {
+ ulittle32_t *begin = reinterpret_cast<ulittle32_t *>(buf);
+ size_t cnt = 0;
+ for (const ChunkAndOffset &co : syms)
+ begin[cnt++] = co.inputChunk->getRVA() + co.offset;
+ std::sort(begin, begin + cnt);
+ assert(std::unique(begin, begin + cnt) == begin + cnt &&
"RVA tables should be de-duplicated");
}
// MinGW specific, for the "automatic import of variables from DLLs" feature.
size_t PseudoRelocTableChunk::getSize() const {
- if (Relocs.empty())
+ if (relocs.empty())
return 0;
- return 12 + 12 * Relocs.size();
+ return 12 + 12 * relocs.size();
}
// MinGW specific.
-void PseudoRelocTableChunk::writeTo(uint8_t *Buf) const {
- if (Relocs.empty())
+void PseudoRelocTableChunk::writeTo(uint8_t *buf) const {
+ if (relocs.empty())
return;
- ulittle32_t *Table = reinterpret_cast<ulittle32_t *>(Buf);
+ ulittle32_t *table = reinterpret_cast<ulittle32_t *>(buf);
// This is the list header, to signal the runtime pseudo relocation v2
// format.
- Table[0] = 0;
- Table[1] = 0;
- Table[2] = 1;
-
- size_t Idx = 3;
- for (const RuntimePseudoReloc &RPR : Relocs) {
- Table[Idx + 0] = RPR.Sym->getRVA();
- Table[Idx + 1] = RPR.Target->getRVA() + RPR.TargetOffset;
- Table[Idx + 2] = RPR.Flags;
- Idx += 3;
+ table[0] = 0;
+ table[1] = 0;
+ table[2] = 1;
+
+ size_t idx = 3;
+ for (const RuntimePseudoReloc &rpr : relocs) {
+ table[idx + 0] = rpr.sym->getRVA();
+ table[idx + 1] = rpr.target->getRVA() + rpr.targetOffset;
+ table[idx + 2] = rpr.flags;
+ idx += 3;
}
}
//
// Usually we have a lot of relocations for each page, so the number of
// bytes for one .reloc entry is close to 2 bytes on average.
-BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) {
+BaserelChunk::BaserelChunk(uint32_t page, Baserel *begin, Baserel *end) {
// Block header consists of 4 byte page RVA and 4 byte block size.
// Each entry is 2 byte. Last entry may be padding.
- Data.resize(alignTo((End - Begin) * 2 + 8, 4));
- uint8_t *P = Data.data();
- write32le(P, Page);
- write32le(P + 4, Data.size());
- P += 8;
- for (Baserel *I = Begin; I != End; ++I) {
- write16le(P, (I->Type << 12) | (I->RVA - Page));
- P += 2;
+ data.resize(alignTo((end - begin) * 2 + 8, 4));
+ uint8_t *p = data.data();
+ write32le(p, page);
+ write32le(p + 4, data.size());
+ p += 8;
+ for (Baserel *i = begin; i != end; ++i) {
+ write16le(p, (i->type << 12) | (i->rva - page));
+ p += 2;
}
}
-void BaserelChunk::writeTo(uint8_t *Buf) const {
- memcpy(Buf, Data.data(), Data.size());
+void BaserelChunk::writeTo(uint8_t *buf) const {
+ memcpy(buf, data.data(), data.size());
}
uint8_t Baserel::getDefaultType() {
- switch (Config->Machine) {
+ switch (config->machine) {
case AMD64:
case ARM64:
return IMAGE_REL_BASED_DIR64;
}
}
-MergeChunk *MergeChunk::Instances[Log2MaxSectionAlignment + 1] = {};
+MergeChunk *MergeChunk::instances[Log2MaxSectionAlignment + 1] = {};
-MergeChunk::MergeChunk(uint32_t Alignment)
- : Builder(StringTableBuilder::RAW, Alignment) {
- setAlignment(Alignment);
+MergeChunk::MergeChunk(uint32_t alignment)
+ : builder(StringTableBuilder::RAW, alignment) {
+ setAlignment(alignment);
}
-void MergeChunk::addSection(SectionChunk *C) {
- assert(isPowerOf2_32(C->getAlignment()));
- uint8_t P2Align = llvm::Log2_32(C->getAlignment());
- assert(P2Align < array_lengthof(Instances));
- auto *&MC = Instances[P2Align];
- if (!MC)
- MC = make<MergeChunk>(C->getAlignment());
- MC->Sections.push_back(C);
+void MergeChunk::addSection(SectionChunk *c) {
+ assert(isPowerOf2_32(c->getAlignment()));
+ uint8_t p2Align = llvm::Log2_32(c->getAlignment());
+ assert(p2Align < array_lengthof(instances));
+ auto *&mc = instances[p2Align];
+ if (!mc)
+ mc = make<MergeChunk>(c->getAlignment());
+ mc->sections.push_back(c);
}
void MergeChunk::finalizeContents() {
- assert(!Finalized && "should only finalize once");
- for (SectionChunk *C : Sections)
- if (C->Live)
- Builder.add(toStringRef(C->getContents()));
- Builder.finalize();
- Finalized = true;
+ assert(!finalized && "should only finalize once");
+ for (SectionChunk *c : sections)
+ if (c->live)
+ builder.add(toStringRef(c->getContents()));
+ builder.finalize();
+ finalized = true;
}
void MergeChunk::assignSubsectionRVAs() {
- for (SectionChunk *C : Sections) {
- if (!C->Live)
+ for (SectionChunk *c : sections) {
+ if (!c->live)
continue;
- size_t Off = Builder.getOffset(toStringRef(C->getContents()));
- C->setRVA(RVA + Off);
+ size_t off = builder.getOffset(toStringRef(c->getContents()));
+ c->setRVA(rva + off);
}
}
}
size_t MergeChunk::getSize() const {
- return Builder.getSize();
+ return builder.getSize();
}
-void MergeChunk::writeTo(uint8_t *Buf) const {
- Builder.write(Buf);
+void MergeChunk::writeTo(uint8_t *buf) const {
+ builder.write(buf);
}
// MinGW specific.
-size_t AbsolutePointerChunk::getSize() const { return Config->Wordsize; }
+size_t AbsolutePointerChunk::getSize() const { return config->wordsize; }
-void AbsolutePointerChunk::writeTo(uint8_t *Buf) const {
- if (Config->is64()) {
- write64le(Buf, Value);
+void AbsolutePointerChunk::writeTo(uint8_t *buf) const {
+ if (config->is64()) {
+ write64le(buf, value);
} else {
- write32le(Buf, Value);
+ write32le(buf, value);
}
}
class Symbol;
// Mask for permissions (discardable, writable, readable, executable, etc).
-const uint32_t PermMask = 0xFE000000;
+const uint32_t permMask = 0xFE000000;
// Mask for section types (code, data, bss).
-const uint32_t TypeMask = 0x000000E0;
+const uint32_t typeMask = 0x000000E0;
// The log base 2 of the largest section alignment, which is log2(8192), or 13.
enum : unsigned { Log2MaxSectionAlignment = 13 };
class Chunk {
public:
enum Kind : uint8_t { SectionKind, OtherKind, ImportThunkKind };
- Kind kind() const { return ChunkKind; }
+ Kind kind() const { return chunkKind; }
// Returns the size of this chunk (even if this is a common or BSS.)
size_t getSize() const;
// Returns chunk alignment in power of two form. Value values are powers of
// two from 1 to 8192.
- uint32_t getAlignment() const { return 1U << P2Align; }
+ uint32_t getAlignment() const { return 1U << p2Align; }
// Update the chunk section alignment measured in bytes. Internally alignment
// is stored in log2.
- void setAlignment(uint32_t Align) {
+ void setAlignment(uint32_t align) {
// Treat zero byte alignment as 1 byte alignment.
- Align = Align ? Align : 1;
- assert(llvm::isPowerOf2_32(Align) && "alignment is not a power of 2");
- P2Align = llvm::Log2_32(Align);
- assert(P2Align <= Log2MaxSectionAlignment &&
+ align = align ? align : 1;
+ assert(llvm::isPowerOf2_32(align) && "alignment is not a power of 2");
+ p2Align = llvm::Log2_32(align);
+ assert(p2Align <= Log2MaxSectionAlignment &&
"impossible requested alignment");
}
// beginning of the file. Because this function may use RVA values
// of other chunks for relocations, you need to set them properly
// before calling this function.
- void writeTo(uint8_t *Buf) const;
+ void writeTo(uint8_t *buf) const;
// The writer sets and uses the addresses. In practice, PE images cannot be
// larger than 2GB. Chunks are always laid as part of the image, so Chunk RVAs
// can be stored with 32 bits.
- uint32_t getRVA() const { return RVA; }
- void setRVA(uint64_t V) {
- RVA = (uint32_t)V;
- assert(RVA == V && "RVA truncated");
+ uint32_t getRVA() const { return rva; }
+ void setRVA(uint64_t v) {
+ rva = (uint32_t)v;
+ assert(rva == v && "RVA truncated");
}
// Returns readable/writable/executable bits.
// An output section has pointers to chunks in the section, and each
// chunk has a back pointer to an output section.
- void setOutputSectionIdx(uint16_t O) { OSIdx = O; }
- uint16_t getOutputSectionIdx() const { return OSIdx; }
+ void setOutputSectionIdx(uint16_t o) { osidx = o; }
+ uint16_t getOutputSectionIdx() const { return osidx; }
OutputSection *getOutputSection() const;
// Windows-specific.
// Collect all locations that contain absolute addresses for base relocations.
- void getBaserels(std::vector<Baserel> *Res);
+ void getBaserels(std::vector<Baserel> *res);
// Returns a human-readable name of this chunk. Chunks are unnamed chunks of
// bytes, so this is used only for logging or debugging.
bool isHotPatchable() const;
protected:
- Chunk(Kind K = OtherKind) : ChunkKind(K), HasData(true), P2Align(0) {}
+ Chunk(Kind k = OtherKind) : chunkKind(k), hasData(true), p2Align(0) {}
- const Kind ChunkKind;
+ const Kind chunkKind;
public:
// Returns true if this has non-zero data. BSS chunks return
// false. If false is returned, the space occupied by this chunk
// will be filled with zeros. Corresponds to the
// IMAGE_SCN_CNT_UNINITIALIZED_DATA section characteristic bit.
- uint8_t HasData : 1;
+ uint8_t hasData : 1;
public:
// The alignment of this chunk, stored in log2 form. The writer uses the
// value.
- uint8_t P2Align : 7;
+ uint8_t p2Align : 7;
// The output section index for this chunk. The first valid section number is
// one.
- uint16_t OSIdx = 0;
+ uint16_t osidx = 0;
// The RVA of this chunk in the output. The writer sets a value.
- uint32_t RVA = 0;
+ uint32_t rva = 0;
};
class NonSectionChunk : public Chunk {
// beginning of the file. Because this function may use RVA values
// of other chunks for relocations, you need to set them properly
// before calling this function.
- virtual void writeTo(uint8_t *Buf) const {}
+ virtual void writeTo(uint8_t *buf) const {}
// Returns the section name if this is a section chunk.
// It is illegal to call this function on non-section chunks.
// Windows-specific.
// Collect all locations that contain absolute addresses for base relocations.
- virtual void getBaserels(std::vector<Baserel> *Res) {}
+ virtual void getBaserels(std::vector<Baserel> *res) {}
// Returns a human-readable name of this chunk. Chunks are unnamed chunks of
// bytes, so this is used only for logging or debugging.
virtual StringRef getDebugName() const { return ""; }
- static bool classof(const Chunk *C) { return C->kind() != SectionKind; }
+ static bool classof(const Chunk *c) { return c->kind() != SectionKind; }
protected:
- NonSectionChunk(Kind K = OtherKind) : Chunk(K) {}
+ NonSectionChunk(Kind k = OtherKind) : Chunk(k) {}
};
// A chunk corresponding a section of an input file.
std::random_access_iterator_tag, Symbol *> {
friend SectionChunk;
- ObjFile *File;
+ ObjFile *file;
- symbol_iterator(ObjFile *File, const coff_relocation *I)
- : symbol_iterator::iterator_adaptor_base(I), File(File) {}
+ symbol_iterator(ObjFile *file, const coff_relocation *i)
+ : symbol_iterator::iterator_adaptor_base(i), file(file) {}
public:
symbol_iterator() = default;
- Symbol *operator*() const { return File->getSymbol(I->SymbolTableIndex); }
+ Symbol *operator*() const { return file->getSymbol(I->SymbolTableIndex); }
};
- SectionChunk(ObjFile *File, const coff_section *Header);
- static bool classof(const Chunk *C) { return C->kind() == SectionKind; }
- size_t getSize() const { return Header->SizeOfRawData; }
+ SectionChunk(ObjFile *file, const coff_section *header);
+ static bool classof(const Chunk *c) { return c->kind() == SectionKind; }
+ size_t getSize() const { return header->SizeOfRawData; }
ArrayRef<uint8_t> getContents() const;
- void writeTo(uint8_t *Buf) const;
+ void writeTo(uint8_t *buf) const;
uint32_t getOutputCharacteristics() const {
- return Header->Characteristics & (PermMask | TypeMask);
+ return header->Characteristics & (permMask | typeMask);
}
StringRef getSectionName() const {
- return StringRef(SectionNameData, SectionNameSize);
+ return StringRef(sectionNameData, sectionNameSize);
}
- void getBaserels(std::vector<Baserel> *Res);
+ void getBaserels(std::vector<Baserel> *res);
bool isCOMDAT() const;
- void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
- uint64_t P) const;
- void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
- uint64_t P) const;
- void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
- uint64_t P) const;
- void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
- uint64_t P) const;
+ void applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
+ uint64_t p) const;
+ void applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
+ uint64_t p) const;
+ void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
+ uint64_t p) const;
+ void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
+ uint64_t p) const;
- void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &Res);
+ void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &res);
// Called if the garbage collector decides to not include this chunk
// in a final output. It's supposed to print out a log message to stdout.
// Adds COMDAT associative sections to this COMDAT section. A chunk
// and its children are treated as a group by the garbage collector.
- void addAssociative(SectionChunk *Child);
+ void addAssociative(SectionChunk *child);
StringRef getDebugName() const;
// Allow iteration over the bodies of this chunk's relocated symbols.
llvm::iterator_range<symbol_iterator> symbols() const {
- return llvm::make_range(symbol_iterator(File, RelocsData),
- symbol_iterator(File, RelocsData + RelocsSize));
+ return llvm::make_range(symbol_iterator(file, relocsData),
+ symbol_iterator(file, relocsData + relocsSize));
}
ArrayRef<coff_relocation> getRelocs() const {
- return llvm::makeArrayRef(RelocsData, RelocsSize);
+ return llvm::makeArrayRef(relocsData, relocsSize);
}
// Reloc setter used by ARM range extension thunk insertion.
- void setRelocs(ArrayRef<coff_relocation> NewRelocs) {
- RelocsData = NewRelocs.data();
- RelocsSize = NewRelocs.size();
- assert(RelocsSize == NewRelocs.size() && "reloc size truncation");
+ void setRelocs(ArrayRef<coff_relocation> newRelocs) {
+ relocsData = newRelocs.data();
+ relocsSize = newRelocs.size();
+ assert(relocsSize == newRelocs.size() && "reloc size truncation");
}
// Single linked list iterator for associated comdat children.
AssociatedIterator, std::forward_iterator_tag, SectionChunk> {
public:
AssociatedIterator() = default;
- AssociatedIterator(SectionChunk *Head) : Cur(Head) {}
- AssociatedIterator &operator=(const AssociatedIterator &R) {
- Cur = R.Cur;
+ AssociatedIterator(SectionChunk *head) : cur(head) {}
+ AssociatedIterator &operator=(const AssociatedIterator &r) {
+ cur = r.cur;
return *this;
}
- bool operator==(const AssociatedIterator &R) const { return Cur == R.Cur; }
- const SectionChunk &operator*() const { return *Cur; }
- SectionChunk &operator*() { return *Cur; }
+ bool operator==(const AssociatedIterator &r) const { return cur == r.cur; }
+ const SectionChunk &operator*() const { return *cur; }
+ SectionChunk &operator*() { return *cur; }
AssociatedIterator &operator++() {
- Cur = Cur->AssocChildren;
+ cur = cur->assocChildren;
return *this;
}
private:
- SectionChunk *Cur = nullptr;
+ SectionChunk *cur = nullptr;
};
// Allow iteration over the associated child chunks for this section.
llvm::iterator_range<AssociatedIterator> children() const {
- return llvm::make_range(AssociatedIterator(AssocChildren),
+ return llvm::make_range(AssociatedIterator(assocChildren),
AssociatedIterator(nullptr));
}
ArrayRef<uint8_t> consumeDebugMagic();
- static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data,
- StringRef SectionName);
+ static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> data,
+ StringRef sectionName);
- static SectionChunk *findByName(ArrayRef<SectionChunk *> Sections,
- StringRef Name);
+ static SectionChunk *findByName(ArrayRef<SectionChunk *> sections,
+ StringRef name);
// The file that this chunk was created from.
- ObjFile *File;
+ ObjFile *file;
// Pointer to the COFF section header in the input file.
- const coff_section *Header;
+ const coff_section *header;
// The COMDAT leader symbol if this is a COMDAT chunk.
- DefinedRegular *Sym = nullptr;
+ DefinedRegular *sym = nullptr;
// The CRC of the contents as described in the COFF spec 4.5.5.
// Auxiliary Format 5: Section Definitions. Used for ICF.
- uint32_t Checksum = 0;
+ uint32_t checksum = 0;
// Used by the garbage collector.
- bool Live;
+ bool live;
// Whether this section needs to be kept distinct from other sections during
// ICF. This is set by the driver using address-significance tables.
- bool KeepUnique = false;
+ bool keepUnique = false;
// The COMDAT selection if this is a COMDAT chunk.
- llvm::COFF::COMDATType Selection = (llvm::COFF::COMDATType)0;
+ llvm::COFF::COMDATType selection = (llvm::COFF::COMDATType)0;
// A pointer pointing to a replacement for this chunk.
// Initially it points to "this" object. If this chunk is merged
// with other chunk by ICF, it points to another chunk,
// and this chunk is considered as dead.
- SectionChunk *Repl;
+ SectionChunk *repl;
private:
- SectionChunk *AssocChildren = nullptr;
+ SectionChunk *assocChildren = nullptr;
// Used for ICF (Identical COMDAT Folding)
- void replace(SectionChunk *Other);
- uint32_t Class[2] = {0, 0};
+ void replace(SectionChunk *other);
+ uint32_t eqClass[2] = {0, 0};
// Relocations for this section. Size is stored below.
- const coff_relocation *RelocsData;
+ const coff_relocation *relocsData;
// Section name string. Size is stored below.
- const char *SectionNameData;
+ const char *sectionNameData;
- uint32_t RelocsSize = 0;
- uint32_t SectionNameSize = 0;
+ uint32_t relocsSize = 0;
+ uint32_t sectionNameSize = 0;
};
// Inline methods to implement faux-virtual dispatch for SectionChunk.
->getOutputCharacteristics();
}
-inline void Chunk::writeTo(uint8_t *Buf) const {
+inline void Chunk::writeTo(uint8_t *buf) const {
if (isa<SectionChunk>(this))
- static_cast<const SectionChunk *>(this)->writeTo(Buf);
+ static_cast<const SectionChunk *>(this)->writeTo(buf);
else
- static_cast<const NonSectionChunk *>(this)->writeTo(Buf);
+ static_cast<const NonSectionChunk *>(this)->writeTo(buf);
}
inline StringRef Chunk::getSectionName() const {
return static_cast<const NonSectionChunk *>(this)->getSectionName();
}
-inline void Chunk::getBaserels(std::vector<Baserel> *Res) {
+inline void Chunk::getBaserels(std::vector<Baserel> *res) {
if (isa<SectionChunk>(this))
- static_cast<SectionChunk *>(this)->getBaserels(Res);
+ static_cast<SectionChunk *>(this)->getBaserels(res);
else
- static_cast<NonSectionChunk *>(this)->getBaserels(Res);
+ static_cast<NonSectionChunk *>(this)->getBaserels(res);
}
inline StringRef Chunk::getDebugName() const {
// on the offsets assigned by the StringTableBuilder.
class MergeChunk : public NonSectionChunk {
public:
- MergeChunk(uint32_t Alignment);
- static void addSection(SectionChunk *C);
+ MergeChunk(uint32_t alignment);
+ static void addSection(SectionChunk *c);
void finalizeContents();
void assignSubsectionRVAs();
uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return ".rdata"; }
size_t getSize() const override;
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *buf) const override;
- static MergeChunk *Instances[Log2MaxSectionAlignment + 1];
- std::vector<SectionChunk *> Sections;
+ static MergeChunk *instances[Log2MaxSectionAlignment + 1];
+ std::vector<SectionChunk *> sections;
private:
- llvm::StringTableBuilder Builder;
- bool Finalized = false;
+ llvm::StringTableBuilder builder;
+ bool finalized = false;
};
// A chunk for common symbols. Common chunks don't have actual data.
class CommonChunk : public NonSectionChunk {
public:
- CommonChunk(const COFFSymbolRef Sym);
- size_t getSize() const override { return Sym.getValue(); }
+ CommonChunk(const COFFSymbolRef sym);
+ size_t getSize() const override { return sym.getValue(); }
uint32_t getOutputCharacteristics() const override;
StringRef getSectionName() const override { return ".bss"; }
private:
- const COFFSymbolRef Sym;
+ const COFFSymbolRef sym;
};
// A chunk for linker-created strings.
class StringChunk : public NonSectionChunk {
public:
- explicit StringChunk(StringRef S) : Str(S) {}
- size_t getSize() const override { return Str.size() + 1; }
- void writeTo(uint8_t *Buf) const override;
+ explicit StringChunk(StringRef s) : str(s) {}
+ size_t getSize() const override { return str.size() + 1; }
+ void writeTo(uint8_t *buf) const override;
private:
- StringRef Str;
+ StringRef str;
};
-static const uint8_t ImportThunkX86[] = {
+static const uint8_t importThunkX86[] = {
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
};
-static const uint8_t ImportThunkARM[] = {
+static const uint8_t importThunkARM[] = {
0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
};
-static const uint8_t ImportThunkARM64[] = {
+static const uint8_t importThunkARM64[] = {
0x10, 0x00, 0x00, 0x90, // adrp x16, #0
0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16]
0x00, 0x02, 0x1f, 0xd6, // br x16
// contents will be a JMP instruction to some __imp_ symbol.
class ImportThunkChunk : public NonSectionChunk {
public:
- ImportThunkChunk(Defined *S)
- : NonSectionChunk(ImportThunkKind), ImpSymbol(S) {}
- static bool classof(const Chunk *C) { return C->kind() == ImportThunkKind; }
+ ImportThunkChunk(Defined *s)
+ : NonSectionChunk(ImportThunkKind), impSymbol(s) {}
+ static bool classof(const Chunk *c) { return c->kind() == ImportThunkKind; }
protected:
- Defined *ImpSymbol;
+ Defined *impSymbol;
};
class ImportThunkChunkX64 : public ImportThunkChunk {
public:
- explicit ImportThunkChunkX64(Defined *S);
- size_t getSize() const override { return sizeof(ImportThunkX86); }
- void writeTo(uint8_t *Buf) const override;
+ explicit ImportThunkChunkX64(Defined *s);
+ size_t getSize() const override { return sizeof(importThunkX86); }
+ void writeTo(uint8_t *buf) const override;
};
class ImportThunkChunkX86 : public ImportThunkChunk {
public:
- explicit ImportThunkChunkX86(Defined *S) : ImportThunkChunk(S) {}
- size_t getSize() const override { return sizeof(ImportThunkX86); }
- void getBaserels(std::vector<Baserel> *Res) override;
- void writeTo(uint8_t *Buf) const override;
+ explicit ImportThunkChunkX86(Defined *s) : ImportThunkChunk(s) {}
+ size_t getSize() const override { return sizeof(importThunkX86); }
+ void getBaserels(std::vector<Baserel> *res) override;
+ void writeTo(uint8_t *buf) const override;
};
class ImportThunkChunkARM : public ImportThunkChunk {
public:
- explicit ImportThunkChunkARM(Defined *S) : ImportThunkChunk(S) {}
- size_t getSize() const override { return sizeof(ImportThunkARM); }
- void getBaserels(std::vector<Baserel> *Res) override;
- void writeTo(uint8_t *Buf) const override;
+ explicit ImportThunkChunkARM(Defined *s) : ImportThunkChunk(s) {}
+ size_t getSize() const override { return sizeof(importThunkARM); }
+ void getBaserels(std::vector<Baserel> *res) override;
+ void writeTo(uint8_t *buf) const override;
};
class ImportThunkChunkARM64 : public ImportThunkChunk {
public:
- explicit ImportThunkChunkARM64(Defined *S) : ImportThunkChunk(S) {}
- size_t getSize() const override { return sizeof(ImportThunkARM64); }
- void writeTo(uint8_t *Buf) const override;
+ explicit ImportThunkChunkARM64(Defined *s) : ImportThunkChunk(s) {}
+ size_t getSize() const override { return sizeof(importThunkARM64); }
+ void writeTo(uint8_t *buf) const override;
};
class RangeExtensionThunkARM : public NonSectionChunk {
public:
- explicit RangeExtensionThunkARM(Defined *T) : Target(T) {}
+ explicit RangeExtensionThunkARM(Defined *t) : target(t) {}
size_t getSize() const override;
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *buf) const override;
- Defined *Target;
+ Defined *target;
};
class RangeExtensionThunkARM64 : public NonSectionChunk {
public:
- explicit RangeExtensionThunkARM64(Defined *T) : Target(T) {}
+ explicit RangeExtensionThunkARM64(Defined *t) : target(t) {}
size_t getSize() const override;
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *buf) const override;
- Defined *Target;
+ Defined *target;
};
// Windows-specific.
// See comments for DefinedLocalImport class.
class LocalImportChunk : public NonSectionChunk {
public:
- explicit LocalImportChunk(Defined *S) : Sym(S) {
- setAlignment(Config->Wordsize);
+ explicit LocalImportChunk(Defined *s) : sym(s) {
+ setAlignment(config->wordsize);
}
size_t getSize() const override;
- void getBaserels(std::vector<Baserel> *Res) override;
- void writeTo(uint8_t *Buf) const override;
+ void getBaserels(std::vector<Baserel> *res) override;
+ void writeTo(uint8_t *buf) const override;
private:
- Defined *Sym;
+ Defined *sym;
};
// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and
// offset into the chunk. Order does not matter as the RVA table will be sorted
// later.
struct ChunkAndOffset {
- Chunk *InputChunk;
- uint32_t Offset;
+ Chunk *inputChunk;
+ uint32_t offset;
struct DenseMapInfo {
static ChunkAndOffset getEmptyKey() {
static ChunkAndOffset getTombstoneKey() {
return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0};
}
- static unsigned getHashValue(const ChunkAndOffset &CO) {
+ static unsigned getHashValue(const ChunkAndOffset &co) {
return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue(
- {CO.InputChunk, CO.Offset});
+ {co.inputChunk, co.offset});
}
- static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) {
- return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset;
+ static bool isEqual(const ChunkAndOffset &lhs, const ChunkAndOffset &rhs) {
+ return lhs.inputChunk == rhs.inputChunk && lhs.offset == rhs.offset;
}
};
};
// Table which contains symbol RVAs. Used for /safeseh and /guard:cf.
class RVATableChunk : public NonSectionChunk {
public:
- explicit RVATableChunk(SymbolRVASet S) : Syms(std::move(S)) {}
- size_t getSize() const override { return Syms.size() * 4; }
- void writeTo(uint8_t *Buf) const override;
+ explicit RVATableChunk(SymbolRVASet s) : syms(std::move(s)) {}
+ size_t getSize() const override { return syms.size() * 4; }
+ void writeTo(uint8_t *buf) const override;
private:
- SymbolRVASet Syms;
+ SymbolRVASet syms;
};
// Windows-specific.
// See the PE/COFF spec 5.6 for details.
class BaserelChunk : public NonSectionChunk {
public:
- BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End);
- size_t getSize() const override { return Data.size(); }
- void writeTo(uint8_t *Buf) const override;
+ BaserelChunk(uint32_t page, Baserel *begin, Baserel *end);
+ size_t getSize() const override { return data.size(); }
+ void writeTo(uint8_t *buf) const override;
private:
- std::vector<uint8_t> Data;
+ std::vector<uint8_t> data;
};
class Baserel {
public:
- Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {}
- explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {}
+ Baserel(uint32_t v, uint8_t ty) : rva(v), type(ty) {}
+ explicit Baserel(uint32_t v) : Baserel(v, getDefaultType()) {}
uint8_t getDefaultType();
- uint32_t RVA;
- uint8_t Type;
+ uint32_t rva;
+ uint8_t type;
};
// This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a
public:
EmptyChunk() {}
size_t getSize() const override { return 0; }
- void writeTo(uint8_t *Buf) const override {}
+ void writeTo(uint8_t *buf) const override {}
};
// MinGW specific, for the "automatic import of variables from DLLs" feature.
// code.
class PseudoRelocTableChunk : public NonSectionChunk {
public:
- PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &Relocs)
- : Relocs(std::move(Relocs)) {
+ PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &relocs)
+ : relocs(std::move(relocs)) {
setAlignment(4);
}
size_t getSize() const override;
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *buf) const override;
private:
- std::vector<RuntimePseudoReloc> Relocs;
+ std::vector<RuntimePseudoReloc> relocs;
};
// MinGW specific; information about one individual location in the image
// one individual element in the PseudoRelocTableChunk table.
class RuntimePseudoReloc {
public:
- RuntimePseudoReloc(Defined *Sym, SectionChunk *Target, uint32_t TargetOffset,
- int Flags)
- : Sym(Sym), Target(Target), TargetOffset(TargetOffset), Flags(Flags) {}
+ RuntimePseudoReloc(Defined *sym, SectionChunk *target, uint32_t targetOffset,
+ int flags)
+ : sym(sym), target(target), targetOffset(targetOffset), flags(flags) {}
- Defined *Sym;
- SectionChunk *Target;
- uint32_t TargetOffset;
+ Defined *sym;
+ SectionChunk *target;
+ uint32_t targetOffset;
// The Flags field contains the size of the relocation, in bits. No other
// flags are currently defined.
- int Flags;
+ int flags;
};
// MinGW specific. A Chunk that contains one pointer-sized absolute value.
class AbsolutePointerChunk : public NonSectionChunk {
public:
- AbsolutePointerChunk(uint64_t Value) : Value(Value) {
+ AbsolutePointerChunk(uint64_t value) : value(value) {
setAlignment(getSize());
}
size_t getSize() const override;
- void writeTo(uint8_t *Buf) const override;
+ void writeTo(uint8_t *buf) const override;
private:
- uint64_t Value;
+ uint64_t value;
};
// Return true if this file has the hotpatch flag set to true in the S_COMPILE3
// record in codeview debug info. Also returns true for some thunks synthesized
// by the linker.
inline bool Chunk::isHotPatchable() const {
- if (auto *SC = dyn_cast<SectionChunk>(this))
- return SC->File->HotPatchable;
+ if (auto *sc = dyn_cast<SectionChunk>(this))
+ return sc->file->hotPatchable;
else if (isa<ImportThunkChunk>(this))
return true;
return false;
}
-void applyMOV32T(uint8_t *Off, uint32_t V);
-void applyBranch24T(uint8_t *Off, int32_t V);
+void applyMOV32T(uint8_t *off, uint32_t v);
+void applyBranch24T(uint8_t *off, int32_t v);
-void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift);
-void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit);
-void applyArm64Branch26(uint8_t *Off, int64_t V);
+void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift);
+void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit);
+void applyArm64Branch26(uint8_t *off, int64_t v);
} // namespace coff
} // namespace lld
// Represents an /export option.
struct Export {
- StringRef Name; // N in /export:N or /export:E=N
- StringRef ExtName; // E in /export:E=N
- Symbol *Sym = nullptr;
- uint16_t Ordinal = 0;
- bool Noname = false;
- bool Data = false;
- bool Private = false;
- bool Constant = false;
+ StringRef name; // N in /export:N or /export:E=N
+ StringRef extName; // E in /export:E=N
+ Symbol *sym = nullptr;
+ uint16_t ordinal = 0;
+ bool noname = false;
+ bool data = false;
+ bool isPrivate = false;
+ bool constant = false;
// If an export is a form of /export:foo=dllname.bar, that means
// that foo should be exported as an alias to bar in the DLL.
// ForwardTo is set to "dllname.bar" part. Usually empty.
- StringRef ForwardTo;
- StringChunk *ForwardChunk = nullptr;
+ StringRef forwardTo;
+ StringChunk *forwardChunk = nullptr;
// True if this /export option was in .drectves section.
- bool Directives = false;
- StringRef SymbolName;
- StringRef ExportName; // Name in DLL
-
- bool operator==(const Export &E) {
- return (Name == E.Name && ExtName == E.ExtName &&
- Ordinal == E.Ordinal && Noname == E.Noname &&
- Data == E.Data && Private == E.Private);
+ bool directives = false;
+ StringRef symbolName;
+ StringRef exportName; // Name in DLL
+
+ bool operator==(const Export &e) {
+ return (name == e.name && extName == e.extName &&
+ ordinal == e.ordinal && noname == e.noname &&
+ data == e.data && isPrivate == e.isPrivate);
}
};
// Global configuration.
struct Configuration {
enum ManifestKind { SideBySide, Embed, No };
- bool is64() { return Machine == AMD64 || Machine == ARM64; }
-
- llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
- size_t Wordsize;
- bool Verbose = false;
- WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
- Symbol *Entry = nullptr;
- bool NoEntry = false;
- std::string OutputFile;
- std::string ImportName;
- bool Demangle = true;
- bool DoGC = true;
- bool DoICF = true;
- bool TailMerge;
- bool Relocatable = true;
- bool ForceMultiple = false;
- bool ForceMultipleRes = false;
- bool ForceUnresolved = false;
- bool Debug = false;
- bool DebugDwarf = false;
- bool DebugGHashes = false;
- bool DebugSymtab = false;
- bool ShowTiming = false;
- bool ShowSummary = false;
- unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
- std::vector<std::string> NatvisFiles;
- llvm::SmallString<128> PDBAltPath;
- llvm::SmallString<128> PDBPath;
- llvm::SmallString<128> PDBSourcePath;
- std::vector<llvm::StringRef> Argv;
+ bool is64() { return machine == AMD64 || machine == ARM64; }
+
+ llvm::COFF::MachineTypes machine = IMAGE_FILE_MACHINE_UNKNOWN;
+ size_t wordsize;
+ bool verbose = false;
+ WindowsSubsystem subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
+ Symbol *entry = nullptr;
+ bool noEntry = false;
+ std::string outputFile;
+ std::string importName;
+ bool demangle = true;
+ bool doGC = true;
+ bool doICF = true;
+ bool tailMerge;
+ bool relocatable = true;
+ bool forceMultiple = false;
+ bool forceMultipleRes = false;
+ bool forceUnresolved = false;
+ bool debug = false;
+ bool debugDwarf = false;
+ bool debugGHashes = false;
+ bool debugSymtab = false;
+ bool showTiming = false;
+ bool showSummary = false;
+ unsigned debugTypes = static_cast<unsigned>(DebugType::None);
+ std::vector<std::string> natvisFiles;
+ llvm::SmallString<128> pdbAltPath;
+ llvm::SmallString<128> pdbPath;
+ llvm::SmallString<128> pdbSourcePath;
+ std::vector<llvm::StringRef> argv;
// Symbols in this set are considered as live by the garbage collector.
- std::vector<Symbol *> GCRoot;
+ std::vector<Symbol *> gCRoot;
- std::set<std::string> NoDefaultLibs;
- bool NoDefaultLibAll = false;
+ std::set<std::string> noDefaultLibs;
+ bool noDefaultLibAll = false;
// True if we are creating a DLL.
- bool DLL = false;
- StringRef Implib;
- std::vector<Export> Exports;
- std::set<std::string> DelayLoads;
- std::map<std::string, int> DLLOrder;
- Symbol *DelayLoadHelper = nullptr;
+ bool dll = false;
+ StringRef implib;
+ std::vector<Export> exports;
+ std::set<std::string> delayLoads;
+ std::map<std::string, int> dllOrder;
+ Symbol *delayLoadHelper = nullptr;
- bool SaveTemps = false;
+ bool saveTemps = false;
// /guard:cf
- GuardCFLevel GuardCF = GuardCFLevel::Off;
+ GuardCFLevel guardCF = GuardCFLevel::Off;
// Used for SafeSEH.
- Symbol *SEHTable = nullptr;
- Symbol *SEHCount = nullptr;
+ Symbol *sehTable = nullptr;
+ Symbol *sehCount = nullptr;
// Used for /opt:lldlto=N
- unsigned LTOO = 2;
+ unsigned ltoo = 2;
// Used for /opt:lldltojobs=N
- unsigned ThinLTOJobs = 0;
+ unsigned thinLTOJobs = 0;
// Used for /opt:lldltopartitions=N
- unsigned LTOPartitions = 1;
+ unsigned ltoPartitions = 1;
// Used for /opt:lldltocache=path
- StringRef LTOCache;
+ StringRef ltoCache;
// Used for /opt:lldltocachepolicy=policy
- llvm::CachePruningPolicy LTOCachePolicy;
+ llvm::CachePruningPolicy ltoCachePolicy;
// Used for /merge:from=to (e.g. /merge:.rdata=.text)
- std::map<StringRef, StringRef> Merge;
+ std::map<StringRef, StringRef> merge;
// Used for /section=.name,{DEKPRSW} to set section attributes.
- std::map<StringRef, uint32_t> Section;
+ std::map<StringRef, uint32_t> section;
// Options for manifest files.
- ManifestKind Manifest = No;
- int ManifestID = 1;
- StringRef ManifestDependency;
- bool ManifestUAC = true;
- std::vector<std::string> ManifestInput;
- StringRef ManifestLevel = "'asInvoker'";
- StringRef ManifestUIAccess = "'false'";
- StringRef ManifestFile;
+ ManifestKind manifest = No;
+ int manifestID = 1;
+ StringRef manifestDependency;
+ bool manifestUAC = true;
+ std::vector<std::string> manifestInput;
+ StringRef manifestLevel = "'asInvoker'";
+ StringRef manifestUIAccess = "'false'";
+ StringRef manifestFile;
// Used for /aligncomm.
- std::map<std::string, int> AlignComm;
+ std::map<std::string, int> alignComm;
// Used for /failifmismatch.
- std::map<StringRef, std::pair<StringRef, InputFile *>> MustMatch;
+ std::map<StringRef, std::pair<StringRef, InputFile *>> mustMatch;
// Used for /alternatename.
- std::map<StringRef, StringRef> AlternateNames;
+ std::map<StringRef, StringRef> alternateNames;
// Used for /order.
- llvm::StringMap<int> Order;
+ llvm::StringMap<int> order;
// Used for /lldmap.
- std::string MapFile;
-
- uint64_t ImageBase = -1;
- uint64_t FileAlign = 512;
- uint64_t StackReserve = 1024 * 1024;
- uint64_t StackCommit = 4096;
- uint64_t HeapReserve = 1024 * 1024;
- uint64_t HeapCommit = 4096;
- uint32_t MajorImageVersion = 0;
- uint32_t MinorImageVersion = 0;
- uint32_t MajorOSVersion = 6;
- uint32_t MinorOSVersion = 0;
- uint32_t Timestamp = 0;
- uint32_t FunctionPadMin = 0;
- bool DynamicBase = true;
- bool AllowBind = true;
- bool NxCompat = true;
- bool AllowIsolation = true;
- bool TerminalServerAware = true;
- bool LargeAddressAware = false;
- bool HighEntropyVA = false;
- bool AppContainer = false;
- bool MinGW = false;
- bool WarnMissingOrderSymbol = true;
- bool WarnLocallyDefinedImported = true;
- bool WarnDebugInfoUnusable = true;
- bool Incremental = true;
- bool IntegrityCheck = false;
- bool KillAt = false;
- bool Repro = false;
- bool SwaprunCD = false;
- bool SwaprunNet = false;
+ std::string mapFile;
+
+ uint64_t imageBase = -1;
+ uint64_t fileAlign = 512;
+ uint64_t stackReserve = 1024 * 1024;
+ uint64_t stackCommit = 4096;
+ uint64_t heapReserve = 1024 * 1024;
+ uint64_t heapCommit = 4096;
+ uint32_t majorImageVersion = 0;
+ uint32_t minorImageVersion = 0;
+ uint32_t majorOSVersion = 6;
+ uint32_t minorOSVersion = 0;
+ uint32_t timestamp = 0;
+ uint32_t functionPadMin = 0;
+ bool dynamicBase = true;
+ bool allowBind = true;
+ bool nxCompat = true;
+ bool allowIsolation = true;
+ bool terminalServerAware = true;
+ bool largeAddressAware = false;
+ bool highEntropyVA = false;
+ bool appContainer = false;
+ bool mingw = false;
+ bool warnMissingOrderSymbol = true;
+ bool warnLocallyDefinedImported = true;
+ bool warnDebugInfoUnusable = true;
+ bool incremental = true;
+ bool integrityCheck = false;
+ bool killAt = false;
+ bool repro = false;
+ bool swaprunCD = false;
+ bool swaprunNet = false;
};
-extern Configuration *Config;
+extern Configuration *config;
} // namespace coff
} // namespace lld
// A chunk for the import descriptor table.
class HintNameChunk : public NonSectionChunk {
public:
- HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {}
+ HintNameChunk(StringRef n, uint16_t h) : name(n), hint(h) {}
size_t getSize() const override {
// Starts with 2 byte Hint field, followed by a null-terminated string,
// ends with 0 or 1 byte padding.
- return alignTo(Name.size() + 3, 2);
+ return alignTo(name.size() + 3, 2);
}
- void writeTo(uint8_t *Buf) const override {
- memset(Buf, 0, getSize());
- write16le(Buf, Hint);
- memcpy(Buf + 2, Name.data(), Name.size());
+ void writeTo(uint8_t *buf) const override {
+ memset(buf, 0, getSize());
+ write16le(buf, hint);
+ memcpy(buf + 2, name.data(), name.size());
}
private:
- StringRef Name;
- uint16_t Hint;
+ StringRef name;
+ uint16_t hint;
};
// A chunk for the import descriptor table.
class LookupChunk : public NonSectionChunk {
public:
- explicit LookupChunk(Chunk *C) : HintName(C) {
- setAlignment(Config->Wordsize);
+ explicit LookupChunk(Chunk *c) : hintName(c) {
+ setAlignment(config->wordsize);
}
- size_t getSize() const override { return Config->Wordsize; }
+ size_t getSize() const override { return config->wordsize; }
- void writeTo(uint8_t *Buf) const override {
- if (Config->is64())
- write64le(Buf, HintName->getRVA());
+ void writeTo(uint8_t *buf) const override {
+ if (config->is64())
+ write64le(buf, hintName->getRVA());
else
- write32le(Buf, HintName->getRVA());
+ write32le(buf, hintName->getRVA());
}
- Chunk *HintName;
+ Chunk *hintName;
};
// A chunk for the import descriptor table.
// See Microsoft PE/COFF spec 7.1. Import Header for details.
class OrdinalOnlyChunk : public NonSectionChunk {
public:
- explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {
- setAlignment(Config->Wordsize);
+ explicit OrdinalOnlyChunk(uint16_t v) : ordinal(v) {
+ setAlignment(config->wordsize);
}
- size_t getSize() const override { return Config->Wordsize; }
+ size_t getSize() const override { return config->wordsize; }
- void writeTo(uint8_t *Buf) const override {
+ void writeTo(uint8_t *buf) const override {
// An import-by-ordinal slot has MSB 1 to indicate that
// this is import-by-ordinal (and not import-by-name).
- if (Config->is64()) {
- write64le(Buf, (1ULL << 63) | Ordinal);
+ if (config->is64()) {
+ write64le(buf, (1ULL << 63) | ordinal);
} else {
- write32le(Buf, (1ULL << 31) | Ordinal);
+ write32le(buf, (1ULL << 31) | ordinal);
}
}
- uint16_t Ordinal;
+ uint16_t ordinal;
};
// A chunk for the import descriptor table.
class ImportDirectoryChunk : public NonSectionChunk {
public:
- explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {}
+ explicit ImportDirectoryChunk(Chunk *n) : dllName(n) {}
size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
- void writeTo(uint8_t *Buf) const override {
- memset(Buf, 0, getSize());
+ void writeTo(uint8_t *buf) const override {
+ memset(buf, 0, getSize());
- auto *E = (coff_import_directory_table_entry *)(Buf);
- E->ImportLookupTableRVA = LookupTab->getRVA();
- E->NameRVA = DLLName->getRVA();
- E->ImportAddressTableRVA = AddressTab->getRVA();
+ auto *e = (coff_import_directory_table_entry *)(buf);
+ e->ImportLookupTableRVA = lookupTab->getRVA();
+ e->NameRVA = dllName->getRVA();
+ e->ImportAddressTableRVA = addressTab->getRVA();
}
- Chunk *DLLName;
- Chunk *LookupTab;
- Chunk *AddressTab;
+ Chunk *dllName;
+ Chunk *lookupTab;
+ Chunk *addressTab;
};
// A chunk representing null terminator in the import table.
// Contents of this chunk is always null bytes.
class NullChunk : public NonSectionChunk {
public:
- explicit NullChunk(size_t N) : Size(N) { HasData = false; }
- size_t getSize() const override { return Size; }
+ explicit NullChunk(size_t n) : size(n) { hasData = false; }
+ size_t getSize() const override { return size; }
- void writeTo(uint8_t *Buf) const override {
- memset(Buf, 0, Size);
+ void writeTo(uint8_t *buf) const override {
+ memset(buf, 0, size);
}
private:
- size_t Size;
+ size_t size;
};
static std::vector<std::vector<DefinedImportData *>>
-binImports(const std::vector<DefinedImportData *> &Imports) {
+binImports(const std::vector<DefinedImportData *> &imports) {
// Group DLL-imported symbols by DLL name because that's how
// symbols are layed out in the import descriptor table.
- auto Less = [](const std::string &A, const std::string &B) {
- return Config->DLLOrder[A] < Config->DLLOrder[B];
+ auto less = [](const std::string &a, const std::string &b) {
+ return config->dllOrder[a] < config->dllOrder[b];
};
std::map<std::string, std::vector<DefinedImportData *>,
- bool(*)(const std::string &, const std::string &)> M(Less);
- for (DefinedImportData *Sym : Imports)
- M[Sym->getDLLName().lower()].push_back(Sym);
+ bool(*)(const std::string &, const std::string &)> m(less);
+ for (DefinedImportData *sym : imports)
+ m[sym->getDLLName().lower()].push_back(sym);
- std::vector<std::vector<DefinedImportData *>> V;
- for (auto &KV : M) {
+ std::vector<std::vector<DefinedImportData *>> v;
+ for (auto &kv : m) {
// Sort symbols by name for each group.
- std::vector<DefinedImportData *> &Syms = KV.second;
- std::sort(Syms.begin(), Syms.end(),
- [](DefinedImportData *A, DefinedImportData *B) {
- return A->getName() < B->getName();
+ std::vector<DefinedImportData *> &syms = kv.second;
+ std::sort(syms.begin(), syms.end(),
+ [](DefinedImportData *a, DefinedImportData *b) {
+ return a->getName() < b->getName();
});
- V.push_back(std::move(Syms));
+ v.push_back(std::move(syms));
}
- return V;
+ return v;
}
// Export table
// A chunk for the delay import descriptor table etnry.
class DelayDirectoryChunk : public NonSectionChunk {
public:
- explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {}
+ explicit DelayDirectoryChunk(Chunk *n) : dllName(n) {}
size_t getSize() const override {
return sizeof(delay_import_directory_table_entry);
}
- void writeTo(uint8_t *Buf) const override {
- memset(Buf, 0, getSize());
+ void writeTo(uint8_t *buf) const override {
+ memset(buf, 0, getSize());
- auto *E = (delay_import_directory_table_entry *)(Buf);
- E->Attributes = 1;
- E->Name = DLLName->getRVA();
- E->ModuleHandle = ModuleHandle->getRVA();
- E->DelayImportAddressTable = AddressTab->getRVA();
- E->DelayImportNameTable = NameTab->getRVA();
+ auto *e = (delay_import_directory_table_entry *)(buf);
+ e->Attributes = 1;
+ e->Name = dllName->getRVA();
+ e->ModuleHandle = moduleHandle->getRVA();
+ e->DelayImportAddressTable = addressTab->getRVA();
+ e->DelayImportNameTable = nameTab->getRVA();
}
- Chunk *DLLName;
- Chunk *ModuleHandle;
- Chunk *AddressTab;
- Chunk *NameTab;
+ Chunk *dllName;
+ Chunk *moduleHandle;
+ Chunk *addressTab;
+ Chunk *nameTab;
};
// Initial contents for delay-loaded functions.
// This code calls __delayLoadHelper2 function to resolve a symbol
// and then overwrites its jump table slot with the result
// for subsequent function calls.
-static const uint8_t ThunkX64[] = {
+static const uint8_t thunkX64[] = {
0x51, // push rcx
0x52, // push rdx
0x41, 0x50, // push r8
0xFF, 0xE0, // jmp rax
};
-static const uint8_t ThunkX86[] = {
+static const uint8_t thunkX86[] = {
0x51, // push ecx
0x52, // push edx
0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME>
0xFF, 0xE0, // jmp eax
};
-static const uint8_t ThunkARM[] = {
+static const uint8_t thunkARM[] = {
0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_<FUNCNAME>
0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_<FUNCNAME>
0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr}
0x60, 0x47, // bx ip
};
-static const uint8_t ThunkARM64[] = {
+static const uint8_t thunkARM64[] = {
0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME>
0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME>
0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]!
// A chunk for the delay import thunk.
class ThunkChunkX64 : public NonSectionChunk {
public:
- ThunkChunkX64(Defined *I, Chunk *D, Defined *H)
- : Imp(I), Desc(D), Helper(H) {}
+ ThunkChunkX64(Defined *i, Chunk *d, Defined *h)
+ : imp(i), desc(d), helper(h) {}
- size_t getSize() const override { return sizeof(ThunkX64); }
+ size_t getSize() const override { return sizeof(thunkX64); }
- void writeTo(uint8_t *Buf) const override {
- memcpy(Buf, ThunkX64, sizeof(ThunkX64));
- write32le(Buf + 36, Imp->getRVA() - RVA - 40);
- write32le(Buf + 43, Desc->getRVA() - RVA - 47);
- write32le(Buf + 48, Helper->getRVA() - RVA - 52);
+ void writeTo(uint8_t *buf) const override {
+ memcpy(buf, thunkX64, sizeof(thunkX64));
+ write32le(buf + 36, imp->getRVA() - rva - 40);
+ write32le(buf + 43, desc->getRVA() - rva - 47);
+ write32le(buf + 48, helper->getRVA() - rva - 52);
}
- Defined *Imp = nullptr;
- Chunk *Desc = nullptr;
- Defined *Helper = nullptr;
+ Defined *imp = nullptr;
+ Chunk *desc = nullptr;
+ Defined *helper = nullptr;
};
class ThunkChunkX86 : public NonSectionChunk {
public:
- ThunkChunkX86(Defined *I, Chunk *D, Defined *H)
- : Imp(I), Desc(D), Helper(H) {}
+ ThunkChunkX86(Defined *i, Chunk *d, Defined *h)
+ : imp(i), desc(d), helper(h) {}
- size_t getSize() const override { return sizeof(ThunkX86); }
+ size_t getSize() const override { return sizeof(thunkX86); }
- void writeTo(uint8_t *Buf) const override {
- memcpy(Buf, ThunkX86, sizeof(ThunkX86));
- write32le(Buf + 3, Imp->getRVA() + Config->ImageBase);
- write32le(Buf + 8, Desc->getRVA() + Config->ImageBase);
- write32le(Buf + 13, Helper->getRVA() - RVA - 17);
+ void writeTo(uint8_t *buf) const override {
+ memcpy(buf, thunkX86, sizeof(thunkX86));
+ write32le(buf + 3, imp->getRVA() + config->imageBase);
+ write32le(buf + 8, desc->getRVA() + config->imageBase);
+ write32le(buf + 13, helper->getRVA() - rva - 17);
}
- void getBaserels(std::vector<Baserel> *Res) override {
- Res->emplace_back(RVA + 3);
- Res->emplace_back(RVA + 8);
+ void getBaserels(std::vector<Baserel> *res) override {
+ res->emplace_back(rva + 3);
+ res->emplace_back(rva + 8);
}
- Defined *Imp = nullptr;
- Chunk *Desc = nullptr;
- Defined *Helper = nullptr;
+ Defined *imp = nullptr;
+ Chunk *desc = nullptr;
+ Defined *helper = nullptr;
};
class ThunkChunkARM : public NonSectionChunk {
public:
- ThunkChunkARM(Defined *I, Chunk *D, Defined *H)
- : Imp(I), Desc(D), Helper(H) {}
+ ThunkChunkARM(Defined *i, Chunk *d, Defined *h)
+ : imp(i), desc(d), helper(h) {}
- size_t getSize() const override { return sizeof(ThunkARM); }
+ size_t getSize() const override { return sizeof(thunkARM); }
- void writeTo(uint8_t *Buf) const override {
- memcpy(Buf, ThunkARM, sizeof(ThunkARM));
- applyMOV32T(Buf + 0, Imp->getRVA() + Config->ImageBase);
- applyMOV32T(Buf + 22, Desc->getRVA() + Config->ImageBase);
- applyBranch24T(Buf + 30, Helper->getRVA() - RVA - 34);
+ void writeTo(uint8_t *buf) const override {
+ memcpy(buf, thunkARM, sizeof(thunkARM));
+ applyMOV32T(buf + 0, imp->getRVA() + config->imageBase);
+ applyMOV32T(buf + 22, desc->getRVA() + config->imageBase);
+ applyBranch24T(buf + 30, helper->getRVA() - rva - 34);
}
- void getBaserels(std::vector<Baserel> *Res) override {
- Res->emplace_back(RVA + 0, IMAGE_REL_BASED_ARM_MOV32T);
- Res->emplace_back(RVA + 22, IMAGE_REL_BASED_ARM_MOV32T);
+ void getBaserels(std::vector<Baserel> *res) override {
+ res->emplace_back(rva + 0, IMAGE_REL_BASED_ARM_MOV32T);
+ res->emplace_back(rva + 22, IMAGE_REL_BASED_ARM_MOV32T);
}
- Defined *Imp = nullptr;
- Chunk *Desc = nullptr;
- Defined *Helper = nullptr;
+ Defined *imp = nullptr;
+ Chunk *desc = nullptr;
+ Defined *helper = nullptr;
};
class ThunkChunkARM64 : public NonSectionChunk {
public:
- ThunkChunkARM64(Defined *I, Chunk *D, Defined *H)
- : Imp(I), Desc(D), Helper(H) {}
-
- size_t getSize() const override { return sizeof(ThunkARM64); }
-
- void writeTo(uint8_t *Buf) const override {
- memcpy(Buf, ThunkARM64, sizeof(ThunkARM64));
- applyArm64Addr(Buf + 0, Imp->getRVA(), RVA + 0, 12);
- applyArm64Imm(Buf + 4, Imp->getRVA() & 0xfff, 0);
- applyArm64Addr(Buf + 52, Desc->getRVA(), RVA + 52, 12);
- applyArm64Imm(Buf + 56, Desc->getRVA() & 0xfff, 0);
- applyArm64Branch26(Buf + 60, Helper->getRVA() - RVA - 60);
+ ThunkChunkARM64(Defined *i, Chunk *d, Defined *h)
+ : imp(i), desc(d), helper(h) {}
+
+ size_t getSize() const override { return sizeof(thunkARM64); }
+
+ void writeTo(uint8_t *buf) const override {
+ memcpy(buf, thunkARM64, sizeof(thunkARM64));
+ applyArm64Addr(buf + 0, imp->getRVA(), rva + 0, 12);
+ applyArm64Imm(buf + 4, imp->getRVA() & 0xfff, 0);
+ applyArm64Addr(buf + 52, desc->getRVA(), rva + 52, 12);
+ applyArm64Imm(buf + 56, desc->getRVA() & 0xfff, 0);
+ applyArm64Branch26(buf + 60, helper->getRVA() - rva - 60);
}
- Defined *Imp = nullptr;
- Chunk *Desc = nullptr;
- Defined *Helper = nullptr;
+ Defined *imp = nullptr;
+ Chunk *desc = nullptr;
+ Defined *helper = nullptr;
};
// A chunk for the import descriptor table.
class DelayAddressChunk : public NonSectionChunk {
public:
- explicit DelayAddressChunk(Chunk *C) : Thunk(C) {
- setAlignment(Config->Wordsize);
+ explicit DelayAddressChunk(Chunk *c) : thunk(c) {
+ setAlignment(config->wordsize);
}
- size_t getSize() const override { return Config->Wordsize; }
+ size_t getSize() const override { return config->wordsize; }
- void writeTo(uint8_t *Buf) const override {
- if (Config->is64()) {
- write64le(Buf, Thunk->getRVA() + Config->ImageBase);
+ void writeTo(uint8_t *buf) const override {
+ if (config->is64()) {
+ write64le(buf, thunk->getRVA() + config->imageBase);
} else {
- uint32_t Bit = 0;
+ uint32_t bit = 0;
// Pointer to thumb code must have the LSB set, so adjust it.
- if (Config->Machine == ARMNT)
- Bit = 1;
- write32le(Buf, (Thunk->getRVA() + Config->ImageBase) | Bit);
+ if (config->machine == ARMNT)
+ bit = 1;
+ write32le(buf, (thunk->getRVA() + config->imageBase) | bit);
}
}
- void getBaserels(std::vector<Baserel> *Res) override {
- Res->emplace_back(RVA);
+ void getBaserels(std::vector<Baserel> *res) override {
+ res->emplace_back(rva);
}
- Chunk *Thunk;
+ Chunk *thunk;
};
// Export table
// A chunk for the export descriptor table.
class ExportDirectoryChunk : public NonSectionChunk {
public:
- ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O)
- : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N),
- OrdinalTab(O) {}
+ ExportDirectoryChunk(int i, int j, Chunk *d, Chunk *a, Chunk *n, Chunk *o)
+ : maxOrdinal(i), nameTabSize(j), dllName(d), addressTab(a), nameTab(n),
+ ordinalTab(o) {}
size_t getSize() const override {
return sizeof(export_directory_table_entry);
}
- void writeTo(uint8_t *Buf) const override {
- memset(Buf, 0, getSize());
-
- auto *E = (export_directory_table_entry *)(Buf);
- E->NameRVA = DLLName->getRVA();
- E->OrdinalBase = 0;
- E->AddressTableEntries = MaxOrdinal + 1;
- E->NumberOfNamePointers = NameTabSize;
- E->ExportAddressTableRVA = AddressTab->getRVA();
- E->NamePointerRVA = NameTab->getRVA();
- E->OrdinalTableRVA = OrdinalTab->getRVA();
+ void writeTo(uint8_t *buf) const override {
+ memset(buf, 0, getSize());
+
+ auto *e = (export_directory_table_entry *)(buf);
+ e->NameRVA = dllName->getRVA();
+ e->OrdinalBase = 0;
+ e->AddressTableEntries = maxOrdinal + 1;
+ e->NumberOfNamePointers = nameTabSize;
+ e->ExportAddressTableRVA = addressTab->getRVA();
+ e->NamePointerRVA = nameTab->getRVA();
+ e->OrdinalTableRVA = ordinalTab->getRVA();
}
- uint16_t MaxOrdinal;
- uint16_t NameTabSize;
- Chunk *DLLName;
- Chunk *AddressTab;
- Chunk *NameTab;
- Chunk *OrdinalTab;
+ uint16_t maxOrdinal;
+ uint16_t nameTabSize;
+ Chunk *dllName;
+ Chunk *addressTab;
+ Chunk *nameTab;
+ Chunk *ordinalTab;
};
class AddressTableChunk : public NonSectionChunk {
public:
- explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {}
- size_t getSize() const override { return Size * 4; }
+ explicit AddressTableChunk(size_t maxOrdinal) : size(maxOrdinal + 1) {}
+ size_t getSize() const override { return size * 4; }
- void writeTo(uint8_t *Buf) const override {
- memset(Buf, 0, getSize());
+ void writeTo(uint8_t *buf) const override {
+ memset(buf, 0, getSize());
- for (const Export &E : Config->Exports) {
- uint8_t *P = Buf + E.Ordinal * 4;
- uint32_t Bit = 0;
+ for (const Export &e : config->exports) {
+ uint8_t *p = buf + e.ordinal * 4;
+ uint32_t bit = 0;
// Pointer to thumb code must have the LSB set, so adjust it.
- if (Config->Machine == ARMNT && !E.Data)
- Bit = 1;
- if (E.ForwardChunk) {
- write32le(P, E.ForwardChunk->getRVA() | Bit);
+ if (config->machine == ARMNT && !e.data)
+ bit = 1;
+ if (e.forwardChunk) {
+ write32le(p, e.forwardChunk->getRVA() | bit);
} else {
- write32le(P, cast<Defined>(E.Sym)->getRVA() | Bit);
+ write32le(p, cast<Defined>(e.sym)->getRVA() | bit);
}
}
}
private:
- size_t Size;
+ size_t size;
};
class NamePointersChunk : public NonSectionChunk {
public:
- explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {}
- size_t getSize() const override { return Chunks.size() * 4; }
+ explicit NamePointersChunk(std::vector<Chunk *> &v) : chunks(v) {}
+ size_t getSize() const override { return chunks.size() * 4; }
- void writeTo(uint8_t *Buf) const override {
- for (Chunk *C : Chunks) {
- write32le(Buf, C->getRVA());
- Buf += 4;
+ void writeTo(uint8_t *buf) const override {
+ for (Chunk *c : chunks) {
+ write32le(buf, c->getRVA());
+ buf += 4;
}
}
private:
- std::vector<Chunk *> Chunks;
+ std::vector<Chunk *> chunks;
};
class ExportOrdinalChunk : public NonSectionChunk {
public:
- explicit ExportOrdinalChunk(size_t I) : Size(I) {}
- size_t getSize() const override { return Size * 2; }
+ explicit ExportOrdinalChunk(size_t i) : size(i) {}
+ size_t getSize() const override { return size * 2; }
- void writeTo(uint8_t *Buf) const override {
- for (Export &E : Config->Exports) {
- if (E.Noname)
+ void writeTo(uint8_t *buf) const override {
+ for (Export &e : config->exports) {
+ if (e.noname)
continue;
- write16le(Buf, E.Ordinal);
- Buf += 2;
+ write16le(buf, e.ordinal);
+ buf += 2;
}
}
private:
- size_t Size;
+ size_t size;
};
} // anonymous namespace
void IdataContents::create() {
- std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+ std::vector<std::vector<DefinedImportData *>> v = binImports(imports);
// Create .idata contents for each DLL.
- for (std::vector<DefinedImportData *> &Syms : V) {
+ for (std::vector<DefinedImportData *> &syms : v) {
// Create lookup and address tables. If they have external names,
// we need to create HintName chunks to store the names.
// If they don't (if they are import-by-ordinals), we store only
// ordinal values to the table.
- size_t Base = Lookups.size();
- for (DefinedImportData *S : Syms) {
- uint16_t Ord = S->getOrdinal();
- if (S->getExternalName().empty()) {
- Lookups.push_back(make<OrdinalOnlyChunk>(Ord));
- Addresses.push_back(make<OrdinalOnlyChunk>(Ord));
+ size_t base = lookups.size();
+ for (DefinedImportData *s : syms) {
+ uint16_t ord = s->getOrdinal();
+ if (s->getExternalName().empty()) {
+ lookups.push_back(make<OrdinalOnlyChunk>(ord));
+ addresses.push_back(make<OrdinalOnlyChunk>(ord));
continue;
}
- auto *C = make<HintNameChunk>(S->getExternalName(), Ord);
- Lookups.push_back(make<LookupChunk>(C));
- Addresses.push_back(make<LookupChunk>(C));
- Hints.push_back(C);
+ auto *c = make<HintNameChunk>(s->getExternalName(), ord);
+ lookups.push_back(make<LookupChunk>(c));
+ addresses.push_back(make<LookupChunk>(c));
+ hints.push_back(c);
}
// Terminate with null values.
- Lookups.push_back(make<NullChunk>(Config->Wordsize));
- Addresses.push_back(make<NullChunk>(Config->Wordsize));
+ lookups.push_back(make<NullChunk>(config->wordsize));
+ addresses.push_back(make<NullChunk>(config->wordsize));
- for (int I = 0, E = Syms.size(); I < E; ++I)
- Syms[I]->setLocation(Addresses[Base + I]);
+ for (int i = 0, e = syms.size(); i < e; ++i)
+ syms[i]->setLocation(addresses[base + i]);
// Create the import table header.
- DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
- auto *Dir = make<ImportDirectoryChunk>(DLLNames.back());
- Dir->LookupTab = Lookups[Base];
- Dir->AddressTab = Addresses[Base];
- Dirs.push_back(Dir);
+ dllNames.push_back(make<StringChunk>(syms[0]->getDLLName()));
+ auto *dir = make<ImportDirectoryChunk>(dllNames.back());
+ dir->lookupTab = lookups[base];
+ dir->addressTab = addresses[base];
+ dirs.push_back(dir);
}
// Add null terminator.
- Dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry)));
+ dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry)));
}
std::vector<Chunk *> DelayLoadContents::getChunks() {
- std::vector<Chunk *> V;
- V.insert(V.end(), Dirs.begin(), Dirs.end());
- V.insert(V.end(), Names.begin(), Names.end());
- V.insert(V.end(), HintNames.begin(), HintNames.end());
- V.insert(V.end(), DLLNames.begin(), DLLNames.end());
- return V;
+ std::vector<Chunk *> v;
+ v.insert(v.end(), dirs.begin(), dirs.end());
+ v.insert(v.end(), names.begin(), names.end());
+ v.insert(v.end(), hintNames.begin(), hintNames.end());
+ v.insert(v.end(), dllNames.begin(), dllNames.end());
+ return v;
}
std::vector<Chunk *> DelayLoadContents::getDataChunks() {
- std::vector<Chunk *> V;
- V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end());
- V.insert(V.end(), Addresses.begin(), Addresses.end());
- return V;
+ std::vector<Chunk *> v;
+ v.insert(v.end(), moduleHandles.begin(), moduleHandles.end());
+ v.insert(v.end(), addresses.begin(), addresses.end());
+ return v;
}
uint64_t DelayLoadContents::getDirSize() {
- return Dirs.size() * sizeof(delay_import_directory_table_entry);
+ return dirs.size() * sizeof(delay_import_directory_table_entry);
}
-void DelayLoadContents::create(Defined *H) {
- Helper = H;
- std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+void DelayLoadContents::create(Defined *h) {
+ helper = h;
+ std::vector<std::vector<DefinedImportData *>> v = binImports(imports);
// Create .didat contents for each DLL.
- for (std::vector<DefinedImportData *> &Syms : V) {
+ for (std::vector<DefinedImportData *> &syms : v) {
// Create the delay import table header.
- DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
- auto *Dir = make<DelayDirectoryChunk>(DLLNames.back());
-
- size_t Base = Addresses.size();
- for (DefinedImportData *S : Syms) {
- Chunk *T = newThunkChunk(S, Dir);
- auto *A = make<DelayAddressChunk>(T);
- Addresses.push_back(A);
- Thunks.push_back(T);
- StringRef ExtName = S->getExternalName();
- if (ExtName.empty()) {
- Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal()));
+ dllNames.push_back(make<StringChunk>(syms[0]->getDLLName()));
+ auto *dir = make<DelayDirectoryChunk>(dllNames.back());
+
+ size_t base = addresses.size();
+ for (DefinedImportData *s : syms) {
+ Chunk *t = newThunkChunk(s, dir);
+ auto *a = make<DelayAddressChunk>(t);
+ addresses.push_back(a);
+ thunks.push_back(t);
+ StringRef extName = s->getExternalName();
+ if (extName.empty()) {
+ names.push_back(make<OrdinalOnlyChunk>(s->getOrdinal()));
} else {
- auto *C = make<HintNameChunk>(ExtName, 0);
- Names.push_back(make<LookupChunk>(C));
- HintNames.push_back(C);
+ auto *c = make<HintNameChunk>(extName, 0);
+ names.push_back(make<LookupChunk>(c));
+ hintNames.push_back(c);
}
}
// Terminate with null values.
- Addresses.push_back(make<NullChunk>(8));
- Names.push_back(make<NullChunk>(8));
+ addresses.push_back(make<NullChunk>(8));
+ names.push_back(make<NullChunk>(8));
- for (int I = 0, E = Syms.size(); I < E; ++I)
- Syms[I]->setLocation(Addresses[Base + I]);
- auto *MH = make<NullChunk>(8);
- MH->setAlignment(8);
- ModuleHandles.push_back(MH);
+ for (int i = 0, e = syms.size(); i < e; ++i)
+ syms[i]->setLocation(addresses[base + i]);
+ auto *mh = make<NullChunk>(8);
+ mh->setAlignment(8);
+ moduleHandles.push_back(mh);
// Fill the delay import table header fields.
- Dir->ModuleHandle = MH;
- Dir->AddressTab = Addresses[Base];
- Dir->NameTab = Names[Base];
- Dirs.push_back(Dir);
+ dir->moduleHandle = mh;
+ dir->addressTab = addresses[base];
+ dir->nameTab = names[base];
+ dirs.push_back(dir);
}
// Add null terminator.
- Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
+ dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
}
-Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
- switch (Config->Machine) {
+Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s, Chunk *dir) {
+ switch (config->machine) {
case AMD64:
- return make<ThunkChunkX64>(S, Dir, Helper);
+ return make<ThunkChunkX64>(s, dir, helper);
case I386:
- return make<ThunkChunkX86>(S, Dir, Helper);
+ return make<ThunkChunkX86>(s, dir, helper);
case ARMNT:
- return make<ThunkChunkARM>(S, Dir, Helper);
+ return make<ThunkChunkARM>(s, dir, helper);
case ARM64:
- return make<ThunkChunkARM64>(S, Dir, Helper);
+ return make<ThunkChunkARM64>(s, dir, helper);
default:
llvm_unreachable("unsupported machine type");
}
}
EdataContents::EdataContents() {
- uint16_t MaxOrdinal = 0;
- for (Export &E : Config->Exports)
- MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
-
- auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile));
- auto *AddressTab = make<AddressTableChunk>(MaxOrdinal);
- std::vector<Chunk *> Names;
- for (Export &E : Config->Exports)
- if (!E.Noname)
- Names.push_back(make<StringChunk>(E.ExportName));
-
- std::vector<Chunk *> Forwards;
- for (Export &E : Config->Exports) {
- if (E.ForwardTo.empty())
+ uint16_t maxOrdinal = 0;
+ for (Export &e : config->exports)
+ maxOrdinal = std::max(maxOrdinal, e.ordinal);
+
+ auto *dllName = make<StringChunk>(sys::path::filename(config->outputFile));
+ auto *addressTab = make<AddressTableChunk>(maxOrdinal);
+ std::vector<Chunk *> names;
+ for (Export &e : config->exports)
+ if (!e.noname)
+ names.push_back(make<StringChunk>(e.exportName));
+
+ std::vector<Chunk *> forwards;
+ for (Export &e : config->exports) {
+ if (e.forwardTo.empty())
continue;
- E.ForwardChunk = make<StringChunk>(E.ForwardTo);
- Forwards.push_back(E.ForwardChunk);
+ e.forwardChunk = make<StringChunk>(e.forwardTo);
+ forwards.push_back(e.forwardChunk);
}
- auto *NameTab = make<NamePointersChunk>(Names);
- auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size());
- auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName,
- AddressTab, NameTab, OrdinalTab);
- Chunks.push_back(Dir);
- Chunks.push_back(DLLName);
- Chunks.push_back(AddressTab);
- Chunks.push_back(NameTab);
- Chunks.push_back(OrdinalTab);
- Chunks.insert(Chunks.end(), Names.begin(), Names.end());
- Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end());
+ auto *nameTab = make<NamePointersChunk>(names);
+ auto *ordinalTab = make<ExportOrdinalChunk>(names.size());
+ auto *dir = make<ExportDirectoryChunk>(maxOrdinal, names.size(), dllName,
+ addressTab, nameTab, ordinalTab);
+ chunks.push_back(dir);
+ chunks.push_back(dllName);
+ chunks.push_back(addressTab);
+ chunks.push_back(nameTab);
+ chunks.push_back(ordinalTab);
+ chunks.insert(chunks.end(), names.begin(), names.end());
+ chunks.insert(chunks.end(), forwards.begin(), forwards.end());
}
} // namespace coff
// call create() to populate the chunk vectors.
class IdataContents {
public:
- void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
- bool empty() { return Imports.empty(); }
+ void add(DefinedImportData *sym) { imports.push_back(sym); }
+ bool empty() { return imports.empty(); }
void create();
- std::vector<DefinedImportData *> Imports;
- std::vector<Chunk *> Dirs;
- std::vector<Chunk *> Lookups;
- std::vector<Chunk *> Addresses;
- std::vector<Chunk *> Hints;
- std::vector<Chunk *> DLLNames;
+ std::vector<DefinedImportData *> imports;
+ std::vector<Chunk *> dirs;
+ std::vector<Chunk *> lookups;
+ std::vector<Chunk *> addresses;
+ std::vector<Chunk *> hints;
+ std::vector<Chunk *> dllNames;
};
// Windows-specific.
// DelayLoadContents creates all chunks for the delay-load DLL import table.
class DelayLoadContents {
public:
- void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
- bool empty() { return Imports.empty(); }
- void create(Defined *Helper);
+ void add(DefinedImportData *sym) { imports.push_back(sym); }
+ bool empty() { return imports.empty(); }
+ void create(Defined *helper);
std::vector<Chunk *> getChunks();
std::vector<Chunk *> getDataChunks();
- ArrayRef<Chunk *> getCodeChunks() { return Thunks; }
+ ArrayRef<Chunk *> getCodeChunks() { return thunks; }
- uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
+ uint64_t getDirRVA() { return dirs[0]->getRVA(); }
uint64_t getDirSize();
private:
- Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir);
+ Chunk *newThunkChunk(DefinedImportData *s, Chunk *dir);
- Defined *Helper;
- std::vector<DefinedImportData *> Imports;
- std::vector<Chunk *> Dirs;
- std::vector<Chunk *> ModuleHandles;
- std::vector<Chunk *> Addresses;
- std::vector<Chunk *> Names;
- std::vector<Chunk *> HintNames;
- std::vector<Chunk *> Thunks;
- std::vector<Chunk *> DLLNames;
+ Defined *helper;
+ std::vector<DefinedImportData *> imports;
+ std::vector<Chunk *> dirs;
+ std::vector<Chunk *> moduleHandles;
+ std::vector<Chunk *> addresses;
+ std::vector<Chunk *> names;
+ std::vector<Chunk *> hintNames;
+ std::vector<Chunk *> thunks;
+ std::vector<Chunk *> dllNames;
};
// Windows-specific.
class EdataContents {
public:
EdataContents();
- std::vector<Chunk *> Chunks;
+ std::vector<Chunk *> chunks;
- uint64_t getRVA() { return Chunks[0]->getRVA(); }
+ uint64_t getRVA() { return chunks[0]->getRVA(); }
uint64_t getSize() {
- return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA();
+ return chunks.back()->getRVA() + chunks.back()->getSize() - getRVA();
}
};
// before any dependent OBJ.
class TypeServerSource : public TpiSource {
public:
- explicit TypeServerSource(MemoryBufferRef M, llvm::pdb::NativeSession *S)
- : TpiSource(PDB, nullptr), Session(S), MB(M) {}
+ explicit TypeServerSource(MemoryBufferRef m, llvm::pdb::NativeSession *s)
+ : TpiSource(PDB, nullptr), session(s), mb(m) {}
// Queue a PDB type server for loading in the COFF Driver
- static void enqueue(const ObjFile *DependentFile,
- const TypeServer2Record &TS);
+ static void enqueue(const ObjFile *dependentFile,
+ const TypeServer2Record &ts);
// Create an instance
- static Expected<TypeServerSource *> getInstance(MemoryBufferRef M);
+ static Expected<TypeServerSource *> getInstance(MemoryBufferRef m);
// Fetch the PDB instance loaded for a corresponding dependent OBJ.
static Expected<TypeServerSource *>
- findFromFile(const ObjFile *DependentFile);
+ findFromFile(const ObjFile *dependentFile);
static std::map<std::string, std::pair<std::string, TypeServerSource *>>
- Instances;
+ instances;
// The interface to the PDB (if it was opened successfully)
- std::unique_ptr<llvm::pdb::NativeSession> Session;
+ std::unique_ptr<llvm::pdb::NativeSession> session;
private:
- MemoryBufferRef MB;
+ MemoryBufferRef mb;
};
// This class represents the debug type stream of an OBJ file that depends on a
// PDB type server (see TypeServerSource).
class UseTypeServerSource : public TpiSource {
public:
- UseTypeServerSource(const ObjFile *F, const TypeServer2Record *TS)
- : TpiSource(UsingPDB, F), TypeServerDependency(*TS) {}
+ UseTypeServerSource(const ObjFile *f, const TypeServer2Record *ts)
+ : TpiSource(UsingPDB, f), typeServerDependency(*ts) {}
// Information about the PDB type server dependency, that needs to be loaded
// in before merging this OBJ.
- TypeServer2Record TypeServerDependency;
+ TypeServer2Record typeServerDependency;
};
// This class represents the debug type stream of a Microsoft precompiled
// such files, clang does not.
class PrecompSource : public TpiSource {
public:
- PrecompSource(const ObjFile *F) : TpiSource(PCH, F) {}
+ PrecompSource(const ObjFile *f) : TpiSource(PCH, f) {}
};
// This class represents the debug type stream of an OBJ file that depends on a
// Microsoft precompiled headers OBJ (see PrecompSource).
class UsePrecompSource : public TpiSource {
public:
- UsePrecompSource(const ObjFile *F, const PrecompRecord *Precomp)
- : TpiSource(UsingPCH, F), PrecompDependency(*Precomp) {}
+ UsePrecompSource(const ObjFile *f, const PrecompRecord *precomp)
+ : TpiSource(UsingPCH, f), precompDependency(*precomp) {}
// Information about the Precomp OBJ dependency, that needs to be loaded in
// before merging this OBJ.
- PrecompRecord PrecompDependency;
+ PrecompRecord precompDependency;
};
} // namespace
static std::vector<std::unique_ptr<TpiSource>> GC;
-TpiSource::TpiSource(TpiKind K, const ObjFile *F) : Kind(K), File(F) {
+TpiSource::TpiSource(TpiKind k, const ObjFile *f) : kind(k), file(f) {
GC.push_back(std::unique_ptr<TpiSource>(this));
}
-TpiSource *lld::coff::makeTpiSource(const ObjFile *F) {
- return new TpiSource(TpiSource::Regular, F);
+TpiSource *lld::coff::makeTpiSource(const ObjFile *f) {
+ return new TpiSource(TpiSource::Regular, f);
}
-TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *F,
- const TypeServer2Record *TS) {
- TypeServerSource::enqueue(F, *TS);
- return new UseTypeServerSource(F, TS);
+TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *f,
+ const TypeServer2Record *ts) {
+ TypeServerSource::enqueue(f, *ts);
+ return new UseTypeServerSource(f, ts);
}
-TpiSource *lld::coff::makePrecompSource(const ObjFile *F) {
- return new PrecompSource(F);
+TpiSource *lld::coff::makePrecompSource(const ObjFile *f) {
+ return new PrecompSource(f);
}
-TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *F,
- const PrecompRecord *Precomp) {
- return new UsePrecompSource(F, Precomp);
+TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *f,
+ const PrecompRecord *precomp) {
+ return new UsePrecompSource(f, precomp);
}
namespace lld {
namespace coff {
template <>
-const PrecompRecord &retrieveDependencyInfo(const TpiSource *Source) {
- assert(Source->Kind == TpiSource::UsingPCH);
- return ((const UsePrecompSource *)Source)->PrecompDependency;
+const PrecompRecord &retrieveDependencyInfo(const TpiSource *source) {
+ assert(source->kind == TpiSource::UsingPCH);
+ return ((const UsePrecompSource *)source)->precompDependency;
}
template <>
-const TypeServer2Record &retrieveDependencyInfo(const TpiSource *Source) {
- assert(Source->Kind == TpiSource::UsingPDB);
- return ((const UseTypeServerSource *)Source)->TypeServerDependency;
+const TypeServer2Record &retrieveDependencyInfo(const TpiSource *source) {
+ assert(source->kind == TpiSource::UsingPDB);
+ return ((const UseTypeServerSource *)source)->typeServerDependency;
}
} // namespace coff
} // namespace lld
std::map<std::string, std::pair<std::string, TypeServerSource *>>
- TypeServerSource::Instances;
+ TypeServerSource::instances;
// Make a PDB path assuming the PDB is in the same folder as the OBJ
-static std::string getPdbBaseName(const ObjFile *File, StringRef TSPath) {
- StringRef LocalPath =
- !File->ParentName.empty() ? File->ParentName : File->getName();
- SmallString<128> Path = sys::path::parent_path(LocalPath);
+static std::string getPdbBaseName(const ObjFile *file, StringRef tSPath) {
+ StringRef localPath =
+ !file->parentName.empty() ? file->parentName : file->getName();
+ SmallString<128> path = sys::path::parent_path(localPath);
// Currently, type server PDBs are only created by MSVC cl, which only runs
// on Windows, so we can assume type server paths are Windows style.
- sys::path::append(Path, sys::path::filename(TSPath, sys::path::Style::windows));
- return Path.str();
+ sys::path::append(path, sys::path::filename(tSPath, sys::path::Style::windows));
+ return path.str();
}
// The casing of the PDB path stamped in the OBJ can differ from the actual path
}
// If existing, return the actual PDB path on disk.
-static Optional<std::string> findPdbPath(StringRef PDBPath,
- const ObjFile *DependentFile) {
+static Optional<std::string> findPdbPath(StringRef pdbPath,
+ const ObjFile *dependentFile) {
// Ensure the file exists before anything else. In some cases, if the path
// points to a removable device, Driver::enqueuePath() would fail with an
// error (EAGAIN, "resource unavailable try again") which we want to skip
// silently.
- if (llvm::sys::fs::exists(PDBPath))
- return normalizePdbPath(PDBPath);
- std::string Ret = getPdbBaseName(DependentFile, PDBPath);
- if (llvm::sys::fs::exists(Ret))
- return normalizePdbPath(Ret);
+ if (llvm::sys::fs::exists(pdbPath))
+ return normalizePdbPath(pdbPath);
+ std::string ret = getPdbBaseName(dependentFile, pdbPath);
+ if (llvm::sys::fs::exists(ret))
+ return normalizePdbPath(ret);
return None;
}
// Fetch the PDB instance that was already loaded by the COFF Driver.
Expected<TypeServerSource *>
-TypeServerSource::findFromFile(const ObjFile *DependentFile) {
- const TypeServer2Record &TS =
- retrieveDependencyInfo<TypeServer2Record>(DependentFile->DebugTypesObj);
+TypeServerSource::findFromFile(const ObjFile *dependentFile) {
+ const TypeServer2Record &ts =
+ retrieveDependencyInfo<TypeServer2Record>(dependentFile->debugTypesObj);
- Optional<std::string> P = findPdbPath(TS.Name, DependentFile);
- if (!P)
- return createFileError(TS.Name, errorCodeToError(std::error_code(
+ Optional<std::string> p = findPdbPath(ts.Name, dependentFile);
+ if (!p)
+ return createFileError(ts.Name, errorCodeToError(std::error_code(
ENOENT, std::generic_category())));
- auto It = TypeServerSource::Instances.find(*P);
+ auto it = TypeServerSource::instances.find(*p);
// The PDB file exists on disk, at this point we expect it to have been
// inserted in the map by TypeServerSource::loadPDB()
- assert(It != TypeServerSource::Instances.end());
+ assert(it != TypeServerSource::instances.end());
- std::pair<std::string, TypeServerSource *> &PDB = It->second;
+ std::pair<std::string, TypeServerSource *> &pdb = it->second;
- if (!PDB.second)
+ if (!pdb.second)
return createFileError(
- *P, createStringError(inconvertibleErrorCode(), PDB.first.c_str()));
+ *p, createStringError(inconvertibleErrorCode(), pdb.first.c_str()));
- pdb::PDBFile &PDBFile = (PDB.second)->Session->getPDBFile();
- pdb::InfoStream &Info = cantFail(PDBFile.getPDBInfoStream());
+ pdb::PDBFile &pdbFile = (pdb.second)->session->getPDBFile();
+ pdb::InfoStream &info = cantFail(pdbFile.getPDBInfoStream());
// Just because a file with a matching name was found doesn't mean it can be
// used. The GUID must match between the PDB header and the OBJ
// TypeServer2 record. The 'Age' is used by MSVC incremental compilation.
- if (Info.getGuid() != TS.getGuid())
+ if (info.getGuid() != ts.getGuid())
return createFileError(
- TS.Name,
+ ts.Name,
make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
- return PDB.second;
+ return pdb.second;
}
// FIXME: Temporary interface until PDBLinker::maybeMergeTypeServerPDB() is
// moved here.
Expected<llvm::pdb::NativeSession *>
-lld::coff::findTypeServerSource(const ObjFile *F) {
- Expected<TypeServerSource *> TS = TypeServerSource::findFromFile(F);
- if (!TS)
- return TS.takeError();
- return TS.get()->Session.get();
+lld::coff::findTypeServerSource(const ObjFile *f) {
+ Expected<TypeServerSource *> ts = TypeServerSource::findFromFile(f);
+ if (!ts)
+ return ts.takeError();
+ return ts.get()->session.get();
}
// Queue a PDB type server for loading in the COFF Driver
-void TypeServerSource::enqueue(const ObjFile *DependentFile,
- const TypeServer2Record &TS) {
+void TypeServerSource::enqueue(const ObjFile *dependentFile,
+ const TypeServer2Record &ts) {
// Start by finding where the PDB is located (either the record path or next
// to the OBJ file)
- Optional<std::string> P = findPdbPath(TS.Name, DependentFile);
- if (!P)
+ Optional<std::string> p = findPdbPath(ts.Name, dependentFile);
+ if (!p)
return;
- auto It = TypeServerSource::Instances.emplace(
- *P, std::pair<std::string, TypeServerSource *>{});
- if (!It.second)
+ auto it = TypeServerSource::instances.emplace(
+ *p, std::pair<std::string, TypeServerSource *>{});
+ if (!it.second)
return; // another OBJ already scheduled this PDB for load
- Driver->enqueuePath(*P, false);
+ driver->enqueuePath(*p, false);
}
// Create an instance of TypeServerSource or an error string if the PDB couldn't
// will be merged in. NOTE - a PDB load failure is not a link error: some
// debug info will simply be missing from the final PDB - that is the default
// accepted behavior.
-void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef M) {
- std::string Path = normalizePdbPath(M.getBufferIdentifier());
+void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef m) {
+ std::string path = normalizePdbPath(m.getBufferIdentifier());
- Expected<TypeServerSource *> TS = TypeServerSource::getInstance(M);
- if (!TS)
- TypeServerSource::Instances[Path] = {toString(TS.takeError()), nullptr};
+ Expected<TypeServerSource *> ts = TypeServerSource::getInstance(m);
+ if (!ts)
+ TypeServerSource::instances[path] = {toString(ts.takeError()), nullptr};
else
- TypeServerSource::Instances[Path] = {{}, *TS};
+ TypeServerSource::instances[path] = {{}, *ts};
}
-Expected<TypeServerSource *> TypeServerSource::getInstance(MemoryBufferRef M) {
- std::unique_ptr<llvm::pdb::IPDBSession> ISession;
- Error Err = pdb::NativeSession::createFromPdb(
- MemoryBuffer::getMemBuffer(M, false), ISession);
- if (Err)
- return std::move(Err);
+Expected<TypeServerSource *> TypeServerSource::getInstance(MemoryBufferRef m) {
+ std::unique_ptr<llvm::pdb::IPDBSession> iSession;
+ Error err = pdb::NativeSession::createFromPdb(
+ MemoryBuffer::getMemBuffer(m, false), iSession);
+ if (err)
+ return std::move(err);
- std::unique_ptr<llvm::pdb::NativeSession> Session(
- static_cast<pdb::NativeSession *>(ISession.release()));
+ std::unique_ptr<llvm::pdb::NativeSession> session(
+ static_cast<pdb::NativeSession *>(iSession.release()));
- pdb::PDBFile &PDBFile = Session->getPDBFile();
- Expected<pdb::InfoStream &> Info = PDBFile.getPDBInfoStream();
+ pdb::PDBFile &pdbFile = session->getPDBFile();
+ Expected<pdb::InfoStream &> info = pdbFile.getPDBInfoStream();
// All PDB Files should have an Info stream.
- if (!Info)
- return Info.takeError();
- return new TypeServerSource(M, Session.release());
+ if (!info)
+ return info.takeError();
+ return new TypeServerSource(m, session.release());
}
public:
enum TpiKind { Regular, PCH, UsingPCH, PDB, UsingPDB };
- TpiSource(TpiKind K, const ObjFile *F);
+ TpiSource(TpiKind k, const ObjFile *f);
virtual ~TpiSource() {}
- const TpiKind Kind;
- const ObjFile *File;
+ const TpiKind kind;
+ const ObjFile *file;
};
-TpiSource *makeTpiSource(const ObjFile *F);
-TpiSource *makeUseTypeServerSource(const ObjFile *F,
- const llvm::codeview::TypeServer2Record *TS);
-TpiSource *makePrecompSource(const ObjFile *F);
-TpiSource *makeUsePrecompSource(const ObjFile *F,
- const llvm::codeview::PrecompRecord *Precomp);
+TpiSource *makeTpiSource(const ObjFile *f);
+TpiSource *makeUseTypeServerSource(const ObjFile *f,
+ const llvm::codeview::TypeServer2Record *ts);
+TpiSource *makePrecompSource(const ObjFile *f);
+TpiSource *makeUsePrecompSource(const ObjFile *f,
+ const llvm::codeview::PrecompRecord *precomp);
-void loadTypeServerSource(llvm::MemoryBufferRef M);
+void loadTypeServerSource(llvm::MemoryBufferRef m);
// Temporary interface to get the dependency
-template <typename T> const T &retrieveDependencyInfo(const TpiSource *Source);
+template <typename T> const T &retrieveDependencyInfo(const TpiSource *source);
// Temporary interface until we move PDBLinker::maybeMergeTypeServerPDB here
llvm::Expected<llvm::pdb::NativeSession *>
-findTypeServerSource(const ObjFile *F);
+findTypeServerSource(const ObjFile *f);
} // namespace coff
} // namespace lld
namespace lld {
namespace coff {
-static Timer InputFileTimer("Input File Reading", Timer::root());
+static Timer inputFileTimer("Input File Reading", Timer::root());
-Configuration *Config;
-LinkerDriver *Driver;
+Configuration *config;
+LinkerDriver *driver;
-bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) {
- errorHandler().LogName = args::getFilenameWithoutExe(Args[0]);
- errorHandler().ErrorOS = &Diag;
- errorHandler().ColorDiagnostics = Diag.has_colors();
- errorHandler().ErrorLimitExceededMsg =
+bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &diag) {
+ errorHandler().logName = args::getFilenameWithoutExe(args[0]);
+ errorHandler().errorOS = &diag;
+ errorHandler().colorDiagnostics = diag.has_colors();
+ errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now"
" (use /errorlimit:0 to see all errors)";
- errorHandler().ExitEarly = CanExitEarly;
- Config = make<Configuration>();
+ errorHandler().exitEarly = canExitEarly;
+ config = make<Configuration>();
- Symtab = make<SymbolTable>();
+ symtab = make<SymbolTable>();
- Driver = make<LinkerDriver>();
- Driver->link(Args);
+ driver = make<LinkerDriver>();
+ driver->link(args);
// Call exit() if we can to avoid calling destructors.
- if (CanExitEarly)
+ if (canExitEarly)
exitLld(errorCount() ? 1 : 0);
freeArena();
- ObjFile::Instances.clear();
- ImportFile::Instances.clear();
- BitcodeFile::Instances.clear();
- memset(MergeChunk::Instances, 0, sizeof(MergeChunk::Instances));
+ ObjFile::instances.clear();
+ ImportFile::instances.clear();
+ BitcodeFile::instances.clear();
+ memset(MergeChunk::instances, 0, sizeof(MergeChunk::instances));
return !errorCount();
}
// Drop directory components and replace extension with ".exe" or ".dll".
-static std::string getOutputPath(StringRef Path) {
- auto P = Path.find_last_of("\\/");
- StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1);
- const char* E = Config->DLL ? ".dll" : ".exe";
- return (S.substr(0, S.rfind('.')) + E).str();
+static std::string getOutputPath(StringRef path) {
+ auto p = path.find_last_of("\\/");
+ StringRef s = (p == StringRef::npos) ? path : path.substr(p + 1);
+ const char* e = config->dll ? ".dll" : ".exe";
+ return (s.substr(0, s.rfind('.')) + e).str();
}
// Returns true if S matches /crtend.?\.o$/.
-static bool isCrtend(StringRef S) {
- if (!S.endswith(".o"))
+static bool isCrtend(StringRef s) {
+ if (!s.endswith(".o"))
return false;
- S = S.drop_back(2);
- if (S.endswith("crtend"))
+ s = s.drop_back(2);
+ if (s.endswith("crtend"))
return true;
- return !S.empty() && S.drop_back().endswith("crtend");
+ return !s.empty() && s.drop_back().endswith("crtend");
}
// ErrorOr is not default constructible, so it cannot be used as the type
// Create a std::future that opens and maps a file using the best strategy for
// the host platform.
-static std::future<MBErrPair> createFutureForFile(std::string Path) {
+static std::future<MBErrPair> createFutureForFile(std::string path) {
#if _WIN32
// On Windows, file I/O is relatively slow so it is best to do this
// asynchronously.
auto Strategy = std::launch::async;
#else
- auto Strategy = std::launch::deferred;
+ auto strategy = std::launch::deferred;
#endif
- return std::async(Strategy, [=]() {
- auto MBOrErr = MemoryBuffer::getFile(Path,
+ return std::async(strategy, [=]() {
+ auto mbOrErr = MemoryBuffer::getFile(path,
/*FileSize*/ -1,
/*RequiresNullTerminator*/ false);
- if (!MBOrErr)
- return MBErrPair{nullptr, MBOrErr.getError()};
- return MBErrPair{std::move(*MBOrErr), std::error_code()};
+ if (!mbOrErr)
+ return MBErrPair{nullptr, mbOrErr.getError()};
+ return MBErrPair{std::move(*mbOrErr), std::error_code()};
});
}
// Symbol names are mangled by prepending "_" on x86.
-static StringRef mangle(StringRef Sym) {
- assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN);
- if (Config->Machine == I386)
- return Saver.save("_" + Sym);
- return Sym;
+static StringRef mangle(StringRef sym) {
+ assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN);
+ if (config->machine == I386)
+ return saver.save("_" + sym);
+ return sym;
}
-static bool findUnderscoreMangle(StringRef Sym) {
- Symbol *S = Symtab->findMangle(mangle(Sym));
- return S && !isa<Undefined>(S);
+static bool findUnderscoreMangle(StringRef sym) {
+ Symbol *s = symtab->findMangle(mangle(sym));
+ return s && !isa<Undefined>(s);
}
-MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
- MemoryBufferRef MBRef = *MB;
- make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership
+MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) {
+ MemoryBufferRef mbref = *mb;
+ make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take ownership
- if (Driver->Tar)
- Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()),
- MBRef.getBuffer());
- return MBRef;
+ if (driver->tar)
+ driver->tar->append(relativeToRoot(mbref.getBufferIdentifier()),
+ mbref.getBuffer());
+ return mbref;
}
-void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB,
- bool WholeArchive) {
- StringRef Filename = MB->getBufferIdentifier();
+void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
+ bool wholeArchive) {
+ StringRef filename = mb->getBufferIdentifier();
- MemoryBufferRef MBRef = takeBuffer(std::move(MB));
- FilePaths.push_back(Filename);
+ MemoryBufferRef mbref = takeBuffer(std::move(mb));
+ filePaths.push_back(filename);
// File type is detected by contents, not by file extension.
- switch (identify_magic(MBRef.getBuffer())) {
+ switch (identify_magic(mbref.getBuffer())) {
case file_magic::windows_resource:
- Resources.push_back(MBRef);
+ resources.push_back(mbref);
break;
case file_magic::archive:
- if (WholeArchive) {
- std::unique_ptr<Archive> File =
- CHECK(Archive::create(MBRef), Filename + ": failed to parse archive");
+ if (wholeArchive) {
+ std::unique_ptr<Archive> file =
+ CHECK(Archive::create(mbref), filename + ": failed to parse archive");
- for (MemoryBufferRef M : getArchiveMembers(File.get()))
- addArchiveBuffer(M, "<whole-archive>", Filename, 0);
+ for (MemoryBufferRef m : getArchiveMembers(file.get()))
+ addArchiveBuffer(m, "<whole-archive>", filename, 0);
return;
}
- Symtab->addFile(make<ArchiveFile>(MBRef));
+ symtab->addFile(make<ArchiveFile>(mbref));
break;
case file_magic::bitcode:
- Symtab->addFile(make<BitcodeFile>(MBRef, "", 0));
+ symtab->addFile(make<BitcodeFile>(mbref, "", 0));
break;
case file_magic::coff_object:
case file_magic::coff_import_library:
- Symtab->addFile(make<ObjFile>(MBRef));
+ symtab->addFile(make<ObjFile>(mbref));
break;
case file_magic::pdb:
- loadTypeServerSource(MBRef);
+ loadTypeServerSource(mbref);
break;
case file_magic::coff_cl_gl_object:
- error(Filename + ": is not a native COFF file. Recompile without /GL");
+ error(filename + ": is not a native COFF file. Recompile without /GL");
break;
case file_magic::pecoff_executable:
- if (Filename.endswith_lower(".dll")) {
- error(Filename + ": bad file type. Did you specify a DLL instead of an "
+ if (filename.endswith_lower(".dll")) {
+ error(filename + ": bad file type. Did you specify a DLL instead of an "
"import library?");
break;
}
LLVM_FALLTHROUGH;
default:
- error(MBRef.getBufferIdentifier() + ": unknown file type");
+ error(mbref.getBufferIdentifier() + ": unknown file type");
break;
}
}
-void LinkerDriver::enqueuePath(StringRef Path, bool WholeArchive) {
- auto Future =
- std::make_shared<std::future<MBErrPair>>(createFutureForFile(Path));
- std::string PathStr = Path;
+void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) {
+ auto future =
+ std::make_shared<std::future<MBErrPair>>(createFutureForFile(path));
+ std::string pathStr = path;
enqueueTask([=]() {
- auto MBOrErr = Future->get();
- if (MBOrErr.second) {
- std::string Msg =
- "could not open '" + PathStr + "': " + MBOrErr.second.message();
+ auto mbOrErr = future->get();
+ if (mbOrErr.second) {
+ std::string msg =
+ "could not open '" + pathStr + "': " + mbOrErr.second.message();
// Check if the filename is a typo for an option flag. OptTable thinks
// that all args that are not known options and that start with / are
// filenames, but e.g. `/nodefaultlibs` is more likely a typo for
// the option `/nodefaultlib` than a reference to a file in the root
// directory.
- std::string Nearest;
- if (COFFOptTable().findNearest(PathStr, Nearest) > 1)
- error(Msg);
+ std::string nearest;
+ if (COFFOptTable().findNearest(pathStr, nearest) > 1)
+ error(msg);
else
- error(Msg + "; did you mean '" + Nearest + "'");
+ error(msg + "; did you mean '" + nearest + "'");
} else
- Driver->addBuffer(std::move(MBOrErr.first), WholeArchive);
+ driver->addBuffer(std::move(mbOrErr.first), wholeArchive);
});
}
-void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
- StringRef ParentName,
- uint64_t OffsetInArchive) {
- file_magic Magic = identify_magic(MB.getBuffer());
- if (Magic == file_magic::coff_import_library) {
- InputFile *Imp = make<ImportFile>(MB);
- Imp->ParentName = ParentName;
- Symtab->addFile(Imp);
+void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,
+ StringRef parentName,
+ uint64_t offsetInArchive) {
+ file_magic magic = identify_magic(mb.getBuffer());
+ if (magic == file_magic::coff_import_library) {
+ InputFile *imp = make<ImportFile>(mb);
+ imp->parentName = parentName;
+ symtab->addFile(imp);
return;
}
- InputFile *Obj;
- if (Magic == file_magic::coff_object) {
- Obj = make<ObjFile>(MB);
- } else if (Magic == file_magic::bitcode) {
- Obj = make<BitcodeFile>(MB, ParentName, OffsetInArchive);
+ InputFile *obj;
+ if (magic == file_magic::coff_object) {
+ obj = make<ObjFile>(mb);
+ } else if (magic == file_magic::bitcode) {
+ obj = make<BitcodeFile>(mb, parentName, offsetInArchive);
} else {
- error("unknown file type: " + MB.getBufferIdentifier());
+ error("unknown file type: " + mb.getBufferIdentifier());
return;
}
- Obj->ParentName = ParentName;
- Symtab->addFile(Obj);
- log("Loaded " + toString(Obj) + " for " + SymName);
+ obj->parentName = parentName;
+ symtab->addFile(obj);
+ log("Loaded " + toString(obj) + " for " + symName);
}
-void LinkerDriver::enqueueArchiveMember(const Archive::Child &C,
- StringRef SymName,
- StringRef ParentName) {
+void LinkerDriver::enqueueArchiveMember(const Archive::Child &c,
+ StringRef symName,
+ StringRef parentName) {
- auto ReportBufferError = [=](Error &&E,
- StringRef ChildName) {
+ auto reportBufferError = [=](Error &&e,
+ StringRef childName) {
fatal("could not get the buffer for the member defining symbol " +
- SymName + ": " + ParentName + "(" + ChildName + "): " +
- toString(std::move(E)));
+ symName + ": " + parentName + "(" + childName + "): " +
+ toString(std::move(e)));
};
- if (!C.getParent()->isThin()) {
- uint64_t OffsetInArchive = C.getChildOffset();
- Expected<MemoryBufferRef> MBOrErr = C.getMemoryBufferRef();
- if (!MBOrErr)
- ReportBufferError(MBOrErr.takeError(), check(C.getFullName()));
- MemoryBufferRef MB = MBOrErr.get();
+ if (!c.getParent()->isThin()) {
+ uint64_t offsetInArchive = c.getChildOffset();
+ Expected<MemoryBufferRef> mbOrErr = c.getMemoryBufferRef();
+ if (!mbOrErr)
+ reportBufferError(mbOrErr.takeError(), check(c.getFullName()));
+ MemoryBufferRef mb = mbOrErr.get();
enqueueTask([=]() {
- Driver->addArchiveBuffer(MB, SymName, ParentName, OffsetInArchive);
+ driver->addArchiveBuffer(mb, symName, parentName, offsetInArchive);
});
return;
}
- std::string ChildName = CHECK(
- C.getFullName(),
+ std::string childName = CHECK(
+ c.getFullName(),
"could not get the filename for the member defining symbol " +
- SymName);
- auto Future = std::make_shared<std::future<MBErrPair>>(
- createFutureForFile(ChildName));
+ symName);
+ auto future = std::make_shared<std::future<MBErrPair>>(
+ createFutureForFile(childName));
enqueueTask([=]() {
- auto MBOrErr = Future->get();
- if (MBOrErr.second)
- ReportBufferError(errorCodeToError(MBOrErr.second), ChildName);
- Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName,
- ParentName, /* OffsetInArchive */ 0);
+ auto mbOrErr = future->get();
+ if (mbOrErr.second)
+ reportBufferError(errorCodeToError(mbOrErr.second), childName);
+ driver->addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), symName,
+ parentName, /* OffsetInArchive */ 0);
});
}
-static bool isDecorated(StringRef Sym) {
- return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") ||
- (!Config->MinGW && Sym.contains('@'));
+static bool isDecorated(StringRef sym) {
+ return sym.startswith("@") || sym.contains("@@") || sym.startswith("?") ||
+ (!config->mingw && sym.contains('@'));
}
// Parses .drectve section contents and returns a list of files
// specified by /defaultlib.
-void LinkerDriver::parseDirectives(InputFile *File) {
- StringRef S = File->getDirectives();
- if (S.empty())
+void LinkerDriver::parseDirectives(InputFile *file) {
+ StringRef s = file->getDirectives();
+ if (s.empty())
return;
- log("Directives: " + toString(File) + ": " + S);
+ log("Directives: " + toString(file) + ": " + s);
- ArgParser Parser;
+ ArgParser parser;
// .drectve is always tokenized using Windows shell rules.
// /EXPORT: option can appear too many times, processing in fastpath.
- opt::InputArgList Args;
- std::vector<StringRef> Exports;
- std::tie(Args, Exports) = Parser.parseDirectives(S);
+ opt::InputArgList args;
+ std::vector<StringRef> exports;
+ std::tie(args, exports) = parser.parseDirectives(s);
- for (StringRef E : Exports) {
+ for (StringRef e : exports) {
// If a common header file contains dllexported function
// declarations, many object files may end up with having the
// same /EXPORT options. In order to save cost of parsing them,
// we dedup them first.
- if (!DirectivesExports.insert(E).second)
+ if (!directivesExports.insert(e).second)
continue;
- Export Exp = parseExport(E);
- if (Config->Machine == I386 && Config->MinGW) {
- if (!isDecorated(Exp.Name))
- Exp.Name = Saver.save("_" + Exp.Name);
- if (!Exp.ExtName.empty() && !isDecorated(Exp.ExtName))
- Exp.ExtName = Saver.save("_" + Exp.ExtName);
+ Export exp = parseExport(e);
+ if (config->machine == I386 && config->mingw) {
+ if (!isDecorated(exp.name))
+ exp.name = saver.save("_" + exp.name);
+ if (!exp.extName.empty() && !isDecorated(exp.extName))
+ exp.extName = saver.save("_" + exp.extName);
}
- Exp.Directives = true;
- Config->Exports.push_back(Exp);
+ exp.directives = true;
+ config->exports.push_back(exp);
}
- for (auto *Arg : Args) {
- switch (Arg->getOption().getID()) {
+ for (auto *arg : args) {
+ switch (arg->getOption().getID()) {
case OPT_aligncomm:
- parseAligncomm(Arg->getValue());
+ parseAligncomm(arg->getValue());
break;
case OPT_alternatename:
- parseAlternateName(Arg->getValue());
+ parseAlternateName(arg->getValue());
break;
case OPT_defaultlib:
- if (Optional<StringRef> Path = findLib(Arg->getValue()))
- enqueuePath(*Path, false);
+ if (Optional<StringRef> path = findLib(arg->getValue()))
+ enqueuePath(*path, false);
break;
case OPT_entry:
- Config->Entry = addUndefined(mangle(Arg->getValue()));
+ config->entry = addUndefined(mangle(arg->getValue()));
break;
case OPT_failifmismatch:
- checkFailIfMismatch(Arg->getValue(), File);
+ checkFailIfMismatch(arg->getValue(), file);
break;
case OPT_incl:
- addUndefined(Arg->getValue());
+ addUndefined(arg->getValue());
break;
case OPT_merge:
- parseMerge(Arg->getValue());
+ parseMerge(arg->getValue());
break;
case OPT_nodefaultlib:
- Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()).lower());
+ config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower());
break;
case OPT_section:
- parseSection(Arg->getValue());
+ parseSection(arg->getValue());
break;
case OPT_subsystem:
- parseSubsystem(Arg->getValue(), &Config->Subsystem,
- &Config->MajorOSVersion, &Config->MinorOSVersion);
+ parseSubsystem(arg->getValue(), &config->subsystem,
+ &config->majorOSVersion, &config->minorOSVersion);
break;
// Only add flags here that link.exe accepts in
// `#pragma comment(linker, "/flag")`-generated sections.
case OPT_throwingnew:
break;
default:
- error(Arg->getSpelling() + " is not allowed in .drectve");
+ error(arg->getSpelling() + " is not allowed in .drectve");
}
}
}
// Find file from search paths. You can omit ".obj", this function takes
// care of that. Note that the returned path is not guaranteed to exist.
-StringRef LinkerDriver::doFindFile(StringRef Filename) {
- bool HasPathSep = (Filename.find_first_of("/\\") != StringRef::npos);
- if (HasPathSep)
- return Filename;
- bool HasExt = Filename.contains('.');
- for (StringRef Dir : SearchPaths) {
- SmallString<128> Path = Dir;
- sys::path::append(Path, Filename);
- if (sys::fs::exists(Path.str()))
- return Saver.save(Path.str());
- if (!HasExt) {
- Path.append(".obj");
- if (sys::fs::exists(Path.str()))
- return Saver.save(Path.str());
+StringRef LinkerDriver::doFindFile(StringRef filename) {
+ bool hasPathSep = (filename.find_first_of("/\\") != StringRef::npos);
+ if (hasPathSep)
+ return filename;
+ bool hasExt = filename.contains('.');
+ for (StringRef dir : searchPaths) {
+ SmallString<128> path = dir;
+ sys::path::append(path, filename);
+ if (sys::fs::exists(path.str()))
+ return saver.save(path.str());
+ if (!hasExt) {
+ path.append(".obj");
+ if (sys::fs::exists(path.str()))
+ return saver.save(path.str());
}
}
- return Filename;
+ return filename;
}
-static Optional<sys::fs::UniqueID> getUniqueID(StringRef Path) {
- sys::fs::UniqueID Ret;
- if (sys::fs::getUniqueID(Path, Ret))
+static Optional<sys::fs::UniqueID> getUniqueID(StringRef path) {
+ sys::fs::UniqueID ret;
+ if (sys::fs::getUniqueID(path, ret))
return None;
- return Ret;
+ return ret;
}
// Resolves a file path. This never returns the same path
// (in that case, it returns None).
-Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
- StringRef Path = doFindFile(Filename);
+Optional<StringRef> LinkerDriver::findFile(StringRef filename) {
+ StringRef path = doFindFile(filename);
- if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) {
- bool Seen = !VisitedFiles.insert(*ID).second;
- if (Seen)
+ if (Optional<sys::fs::UniqueID> id = getUniqueID(path)) {
+ bool seen = !visitedFiles.insert(*id).second;
+ if (seen)
return None;
}
- if (Path.endswith_lower(".lib"))
- VisitedLibs.insert(sys::path::filename(Path));
- return Path;
+ if (path.endswith_lower(".lib"))
+ visitedLibs.insert(sys::path::filename(path));
+ return path;
}
// MinGW specific. If an embedded directive specified to link to
// foo.lib, but it isn't found, try libfoo.a instead.
-StringRef LinkerDriver::doFindLibMinGW(StringRef Filename) {
- if (Filename.contains('/') || Filename.contains('\\'))
- return Filename;
-
- SmallString<128> S = Filename;
- sys::path::replace_extension(S, ".a");
- StringRef LibName = Saver.save("lib" + S.str());
- return doFindFile(LibName);
+StringRef LinkerDriver::doFindLibMinGW(StringRef filename) {
+ if (filename.contains('/') || filename.contains('\\'))
+ return filename;
+
+ SmallString<128> s = filename;
+ sys::path::replace_extension(s, ".a");
+ StringRef libName = saver.save("lib" + s.str());
+ return doFindFile(libName);
}
// Find library file from search path.
-StringRef LinkerDriver::doFindLib(StringRef Filename) {
+StringRef LinkerDriver::doFindLib(StringRef filename) {
// Add ".lib" to Filename if that has no file extension.
- bool HasExt = Filename.contains('.');
- if (!HasExt)
- Filename = Saver.save(Filename + ".lib");
- StringRef Ret = doFindFile(Filename);
+ bool hasExt = filename.contains('.');
+ if (!hasExt)
+ filename = saver.save(filename + ".lib");
+ StringRef ret = doFindFile(filename);
// For MinGW, if the find above didn't turn up anything, try
// looking for a MinGW formatted library name.
- if (Config->MinGW && Ret == Filename)
- return doFindLibMinGW(Filename);
- return Ret;
+ if (config->mingw && ret == filename)
+ return doFindLibMinGW(filename);
+ return ret;
}
// Resolves a library path. /nodefaultlib options are taken into
// consideration. This never returns the same path (in that case,
// it returns None).
-Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
- if (Config->NoDefaultLibAll)
+Optional<StringRef> LinkerDriver::findLib(StringRef filename) {
+ if (config->noDefaultLibAll)
return None;
- if (!VisitedLibs.insert(Filename.lower()).second)
+ if (!visitedLibs.insert(filename.lower()).second)
return None;
- StringRef Path = doFindLib(Filename);
- if (Config->NoDefaultLibs.count(Path.lower()))
+ StringRef path = doFindLib(filename);
+ if (config->noDefaultLibs.count(path.lower()))
return None;
- if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path))
- if (!VisitedFiles.insert(*ID).second)
+ if (Optional<sys::fs::UniqueID> id = getUniqueID(path))
+ if (!visitedFiles.insert(*id).second)
return None;
- return Path;
+ return path;
}
// Parses LIB environment which contains a list of search paths.
void LinkerDriver::addLibSearchPaths() {
- Optional<std::string> EnvOpt = Process::GetEnv("LIB");
- if (!EnvOpt.hasValue())
+ Optional<std::string> envOpt = Process::GetEnv("LIB");
+ if (!envOpt.hasValue())
return;
- StringRef Env = Saver.save(*EnvOpt);
- while (!Env.empty()) {
- StringRef Path;
- std::tie(Path, Env) = Env.split(';');
- SearchPaths.push_back(Path);
+ StringRef env = saver.save(*envOpt);
+ while (!env.empty()) {
+ StringRef path;
+ std::tie(path, env) = env.split(';');
+ searchPaths.push_back(path);
}
}
-Symbol *LinkerDriver::addUndefined(StringRef Name) {
- Symbol *B = Symtab->addUndefined(Name);
- if (!B->IsGCRoot) {
- B->IsGCRoot = true;
- Config->GCRoot.push_back(B);
+Symbol *LinkerDriver::addUndefined(StringRef name) {
+ Symbol *b = symtab->addUndefined(name);
+ if (!b->isGCRoot) {
+ b->isGCRoot = true;
+ config->gCRoot.push_back(b);
}
- return B;
+ return b;
}
-StringRef LinkerDriver::mangleMaybe(Symbol *S) {
+StringRef LinkerDriver::mangleMaybe(Symbol *s) {
// If the plain symbol name has already been resolved, do nothing.
- Undefined *Unmangled = dyn_cast<Undefined>(S);
- if (!Unmangled)
+ Undefined *unmangled = dyn_cast<Undefined>(s);
+ if (!unmangled)
return "";
// Otherwise, see if a similar, mangled symbol exists in the symbol table.
- Symbol *Mangled = Symtab->findMangle(Unmangled->getName());
- if (!Mangled)
+ Symbol *mangled = symtab->findMangle(unmangled->getName());
+ if (!mangled)
return "";
// If we find a similar mangled symbol, make this an alias to it and return
// its name.
- log(Unmangled->getName() + " aliased to " + Mangled->getName());
- Unmangled->WeakAlias = Symtab->addUndefined(Mangled->getName());
- return Mangled->getName();
+ log(unmangled->getName() + " aliased to " + mangled->getName());
+ unmangled->weakAlias = symtab->addUndefined(mangled->getName());
+ return mangled->getName();
}
// Windows specific -- find default entry point name.
// each of which corresponds to a user-defined "main" function. This function
// infers an entry point from a user-defined "main" function.
StringRef LinkerDriver::findDefaultEntry() {
- assert(Config->Subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
+ assert(config->subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
"must handle /subsystem before calling this");
- if (Config->MinGW)
- return mangle(Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI
+ if (config->mingw)
+ return mangle(config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI
? "WinMainCRTStartup"
: "mainCRTStartup");
- if (Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
+ if (config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
if (findUnderscoreMangle("wWinMain")) {
if (!findUnderscoreMangle("WinMain"))
return mangle("wWinMainCRTStartup");
}
WindowsSubsystem LinkerDriver::inferSubsystem() {
- if (Config->DLL)
+ if (config->dll)
return IMAGE_SUBSYSTEM_WINDOWS_GUI;
- if (Config->MinGW)
+ if (config->mingw)
return IMAGE_SUBSYSTEM_WINDOWS_CUI;
// Note that link.exe infers the subsystem from the presence of these
// functions even if /entry: or /nodefaultlib are passed which causes them
// to not be called.
- bool HaveMain = findUnderscoreMangle("main");
- bool HaveWMain = findUnderscoreMangle("wmain");
- bool HaveWinMain = findUnderscoreMangle("WinMain");
- bool HaveWWinMain = findUnderscoreMangle("wWinMain");
- if (HaveMain || HaveWMain) {
- if (HaveWinMain || HaveWWinMain) {
- warn(std::string("found ") + (HaveMain ? "main" : "wmain") + " and " +
- (HaveWinMain ? "WinMain" : "wWinMain") +
+ bool haveMain = findUnderscoreMangle("main");
+ bool haveWMain = findUnderscoreMangle("wmain");
+ bool haveWinMain = findUnderscoreMangle("WinMain");
+ bool haveWWinMain = findUnderscoreMangle("wWinMain");
+ if (haveMain || haveWMain) {
+ if (haveWinMain || haveWWinMain) {
+ warn(std::string("found ") + (haveMain ? "main" : "wmain") + " and " +
+ (haveWinMain ? "WinMain" : "wWinMain") +
"; defaulting to /subsystem:console");
}
return IMAGE_SUBSYSTEM_WINDOWS_CUI;
}
- if (HaveWinMain || HaveWWinMain)
+ if (haveWinMain || haveWWinMain)
return IMAGE_SUBSYSTEM_WINDOWS_GUI;
return IMAGE_SUBSYSTEM_UNKNOWN;
}
static uint64_t getDefaultImageBase() {
- if (Config->is64())
- return Config->DLL ? 0x180000000 : 0x140000000;
- return Config->DLL ? 0x10000000 : 0x400000;
+ if (config->is64())
+ return config->dll ? 0x180000000 : 0x140000000;
+ return config->dll ? 0x10000000 : 0x400000;
}
-static std::string createResponseFile(const opt::InputArgList &Args,
- ArrayRef<StringRef> FilePaths,
- ArrayRef<StringRef> SearchPaths) {
- SmallString<0> Data;
- raw_svector_ostream OS(Data);
+static std::string createResponseFile(const opt::InputArgList &args,
+ ArrayRef<StringRef> filePaths,
+ ArrayRef<StringRef> searchPaths) {
+ SmallString<0> data;
+ raw_svector_ostream os(data);
- for (auto *Arg : Args) {
- switch (Arg->getOption().getID()) {
+ for (auto *arg : args) {
+ switch (arg->getOption().getID()) {
case OPT_linkrepro:
case OPT_INPUT:
case OPT_defaultlib:
case OPT_implib:
case OPT_pdb:
case OPT_out:
- OS << Arg->getSpelling() << sys::path::filename(Arg->getValue()) << "\n";
+ os << arg->getSpelling() << sys::path::filename(arg->getValue()) << "\n";
break;
default:
- OS << toString(*Arg) << "\n";
+ os << toString(*arg) << "\n";
}
}
- for (StringRef Path : SearchPaths) {
- std::string RelPath = relativeToRoot(Path);
- OS << "/libpath:" << quote(RelPath) << "\n";
+ for (StringRef path : searchPaths) {
+ std::string relPath = relativeToRoot(path);
+ os << "/libpath:" << quote(relPath) << "\n";
}
- for (StringRef Path : FilePaths)
- OS << quote(relativeToRoot(Path)) << "\n";
+ for (StringRef path : filePaths)
+ os << quote(relativeToRoot(path)) << "\n";
- return Data.str();
+ return data.str();
}
enum class DebugKind { Unknown, None, Full, FastLink, GHash, Dwarf, Symtab };
-static DebugKind parseDebugKind(const opt::InputArgList &Args) {
- auto *A = Args.getLastArg(OPT_debug, OPT_debug_opt);
- if (!A)
+static DebugKind parseDebugKind(const opt::InputArgList &args) {
+ auto *a = args.getLastArg(OPT_debug, OPT_debug_opt);
+ if (!a)
return DebugKind::None;
- if (A->getNumValues() == 0)
+ if (a->getNumValues() == 0)
return DebugKind::Full;
- DebugKind Debug = StringSwitch<DebugKind>(A->getValue())
+ DebugKind debug = StringSwitch<DebugKind>(a->getValue())
.CaseLower("none", DebugKind::None)
.CaseLower("full", DebugKind::Full)
.CaseLower("fastlink", DebugKind::FastLink)
.CaseLower("symtab", DebugKind::Symtab)
.Default(DebugKind::Unknown);
- if (Debug == DebugKind::FastLink) {
+ if (debug == DebugKind::FastLink) {
warn("/debug:fastlink unsupported; using /debug:full");
return DebugKind::Full;
}
- if (Debug == DebugKind::Unknown) {
- error("/debug: unknown option: " + Twine(A->getValue()));
+ if (debug == DebugKind::Unknown) {
+ error("/debug: unknown option: " + Twine(a->getValue()));
return DebugKind::None;
}
- return Debug;
+ return debug;
}
-static unsigned parseDebugTypes(const opt::InputArgList &Args) {
- unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
+static unsigned parseDebugTypes(const opt::InputArgList &args) {
+ unsigned debugTypes = static_cast<unsigned>(DebugType::None);
- if (auto *A = Args.getLastArg(OPT_debugtype)) {
- SmallVector<StringRef, 3> Types;
- StringRef(A->getValue())
- .split(Types, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ if (auto *a = args.getLastArg(OPT_debugtype)) {
+ SmallVector<StringRef, 3> types;
+ StringRef(a->getValue())
+ .split(types, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- for (StringRef Type : Types) {
- unsigned V = StringSwitch<unsigned>(Type.lower())
+ for (StringRef type : types) {
+ unsigned v = StringSwitch<unsigned>(type.lower())
.Case("cv", static_cast<unsigned>(DebugType::CV))
.Case("pdata", static_cast<unsigned>(DebugType::PData))
.Case("fixup", static_cast<unsigned>(DebugType::Fixup))
.Default(0);
- if (V == 0) {
- warn("/debugtype: unknown option '" + Type + "'");
+ if (v == 0) {
+ warn("/debugtype: unknown option '" + type + "'");
continue;
}
- DebugTypes |= V;
+ debugTypes |= v;
}
- return DebugTypes;
+ return debugTypes;
}
// Default debug types
- DebugTypes = static_cast<unsigned>(DebugType::CV);
- if (Args.hasArg(OPT_driver))
- DebugTypes |= static_cast<unsigned>(DebugType::PData);
- if (Args.hasArg(OPT_profile))
- DebugTypes |= static_cast<unsigned>(DebugType::Fixup);
+ debugTypes = static_cast<unsigned>(DebugType::CV);
+ if (args.hasArg(OPT_driver))
+ debugTypes |= static_cast<unsigned>(DebugType::PData);
+ if (args.hasArg(OPT_profile))
+ debugTypes |= static_cast<unsigned>(DebugType::Fixup);
- return DebugTypes;
+ return debugTypes;
}
-static std::string getMapFile(const opt::InputArgList &Args) {
- auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file);
- if (!Arg)
+static std::string getMapFile(const opt::InputArgList &args) {
+ auto *arg = args.getLastArg(OPT_lldmap, OPT_lldmap_file);
+ if (!arg)
return "";
- if (Arg->getOption().getID() == OPT_lldmap_file)
- return Arg->getValue();
+ if (arg->getOption().getID() == OPT_lldmap_file)
+ return arg->getValue();
- assert(Arg->getOption().getID() == OPT_lldmap);
- StringRef OutFile = Config->OutputFile;
- return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str();
+ assert(arg->getOption().getID() == OPT_lldmap);
+ StringRef outFile = config->outputFile;
+ return (outFile.substr(0, outFile.rfind('.')) + ".map").str();
}
static std::string getImplibPath() {
- if (!Config->Implib.empty())
- return Config->Implib;
- SmallString<128> Out = StringRef(Config->OutputFile);
- sys::path::replace_extension(Out, ".lib");
- return Out.str();
+ if (!config->implib.empty())
+ return config->implib;
+ SmallString<128> out = StringRef(config->outputFile);
+ sys::path::replace_extension(out, ".lib");
+ return out.str();
}
//
// LINK | {value} | {value}.{.dll/.exe} | {output name}
// LIB | {value} | {value}.dll | {output name}.dll
//
-static std::string getImportName(bool AsLib) {
- SmallString<128> Out;
+static std::string getImportName(bool asLib) {
+ SmallString<128> out;
- if (Config->ImportName.empty()) {
- Out.assign(sys::path::filename(Config->OutputFile));
- if (AsLib)
- sys::path::replace_extension(Out, ".dll");
+ if (config->importName.empty()) {
+ out.assign(sys::path::filename(config->outputFile));
+ if (asLib)
+ sys::path::replace_extension(out, ".dll");
} else {
- Out.assign(Config->ImportName);
- if (!sys::path::has_extension(Out))
- sys::path::replace_extension(Out,
- (Config->DLL || AsLib) ? ".dll" : ".exe");
+ out.assign(config->importName);
+ if (!sys::path::has_extension(out))
+ sys::path::replace_extension(out,
+ (config->dll || asLib) ? ".dll" : ".exe");
}
- return Out.str();
+ return out.str();
}
-static void createImportLibrary(bool AsLib) {
- std::vector<COFFShortExport> Exports;
- for (Export &E1 : Config->Exports) {
- COFFShortExport E2;
- E2.Name = E1.Name;
- E2.SymbolName = E1.SymbolName;
- E2.ExtName = E1.ExtName;
- E2.Ordinal = E1.Ordinal;
- E2.Noname = E1.Noname;
- E2.Data = E1.Data;
- E2.Private = E1.Private;
- E2.Constant = E1.Constant;
- Exports.push_back(E2);
- }
-
- auto HandleError = [](Error &&E) {
- handleAllErrors(std::move(E),
- [](ErrorInfoBase &EIB) { error(EIB.message()); });
+static void createImportLibrary(bool asLib) {
+ std::vector<COFFShortExport> exports;
+ for (Export &e1 : config->exports) {
+ COFFShortExport e2;
+ e2.Name = e1.name;
+ e2.SymbolName = e1.symbolName;
+ e2.ExtName = e1.extName;
+ e2.Ordinal = e1.ordinal;
+ e2.Noname = e1.noname;
+ e2.Data = e1.data;
+ e2.Private = e1.isPrivate;
+ e2.Constant = e1.constant;
+ exports.push_back(e2);
+ }
+
+ auto handleError = [](Error &&e) {
+ handleAllErrors(std::move(e),
+ [](ErrorInfoBase &eib) { error(eib.message()); });
};
- std::string LibName = getImportName(AsLib);
- std::string Path = getImplibPath();
+ std::string libName = getImportName(asLib);
+ std::string path = getImplibPath();
- if (!Config->Incremental) {
- HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
- Config->MinGW));
+ if (!config->incremental) {
+ handleError(writeImportLibrary(libName, path, exports, config->machine,
+ config->mingw));
return;
}
// If the import library already exists, replace it only if the contents
// have changed.
- ErrorOr<std::unique_ptr<MemoryBuffer>> OldBuf = MemoryBuffer::getFile(
- Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false);
- if (!OldBuf) {
- HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine,
- Config->MinGW));
+ ErrorOr<std::unique_ptr<MemoryBuffer>> oldBuf = MemoryBuffer::getFile(
+ path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false);
+ if (!oldBuf) {
+ handleError(writeImportLibrary(libName, path, exports, config->machine,
+ config->mingw));
return;
}
- SmallString<128> TmpName;
- if (std::error_code EC =
- sys::fs::createUniqueFile(Path + ".tmp-%%%%%%%%.lib", TmpName))
- fatal("cannot create temporary file for import library " + Path + ": " +
- EC.message());
+ SmallString<128> tmpName;
+ if (std::error_code ec =
+ sys::fs::createUniqueFile(path + ".tmp-%%%%%%%%.lib", tmpName))
+ fatal("cannot create temporary file for import library " + path + ": " +
+ ec.message());
- if (Error E = writeImportLibrary(LibName, TmpName, Exports, Config->Machine,
- Config->MinGW)) {
- HandleError(std::move(E));
+ if (Error e = writeImportLibrary(libName, tmpName, exports, config->machine,
+ config->mingw)) {
+ handleError(std::move(e));
return;
}
- std::unique_ptr<MemoryBuffer> NewBuf = check(MemoryBuffer::getFile(
- TmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false));
- if ((*OldBuf)->getBuffer() != NewBuf->getBuffer()) {
- OldBuf->reset();
- HandleError(errorCodeToError(sys::fs::rename(TmpName, Path)));
+ std::unique_ptr<MemoryBuffer> newBuf = check(MemoryBuffer::getFile(
+ tmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false));
+ if ((*oldBuf)->getBuffer() != newBuf->getBuffer()) {
+ oldBuf->reset();
+ handleError(errorCodeToError(sys::fs::rename(tmpName, path)));
} else {
- sys::fs::remove(TmpName);
+ sys::fs::remove(tmpName);
}
}
-static void parseModuleDefs(StringRef Path) {
- std::unique_ptr<MemoryBuffer> MB = CHECK(
- MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
- COFFModuleDefinition M = check(parseCOFFModuleDefinition(
- MB->getMemBufferRef(), Config->Machine, Config->MinGW));
-
- if (Config->OutputFile.empty())
- Config->OutputFile = Saver.save(M.OutputFile);
- Config->ImportName = Saver.save(M.ImportName);
- if (M.ImageBase)
- Config->ImageBase = M.ImageBase;
- if (M.StackReserve)
- Config->StackReserve = M.StackReserve;
- if (M.StackCommit)
- Config->StackCommit = M.StackCommit;
- if (M.HeapReserve)
- Config->HeapReserve = M.HeapReserve;
- if (M.HeapCommit)
- Config->HeapCommit = M.HeapCommit;
- if (M.MajorImageVersion)
- Config->MajorImageVersion = M.MajorImageVersion;
- if (M.MinorImageVersion)
- Config->MinorImageVersion = M.MinorImageVersion;
- if (M.MajorOSVersion)
- Config->MajorOSVersion = M.MajorOSVersion;
- if (M.MinorOSVersion)
- Config->MinorOSVersion = M.MinorOSVersion;
-
- for (COFFShortExport E1 : M.Exports) {
- Export E2;
+static void parseModuleDefs(StringRef path) {
+ std::unique_ptr<MemoryBuffer> mb = CHECK(
+ MemoryBuffer::getFile(path, -1, false, true), "could not open " + path);
+ COFFModuleDefinition m = check(parseCOFFModuleDefinition(
+ mb->getMemBufferRef(), config->machine, config->mingw));
+
+ if (config->outputFile.empty())
+ config->outputFile = saver.save(m.OutputFile);
+ config->importName = saver.save(m.ImportName);
+ if (m.ImageBase)
+ config->imageBase = m.ImageBase;
+ if (m.StackReserve)
+ config->stackReserve = m.StackReserve;
+ if (m.StackCommit)
+ config->stackCommit = m.StackCommit;
+ if (m.HeapReserve)
+ config->heapReserve = m.HeapReserve;
+ if (m.HeapCommit)
+ config->heapCommit = m.HeapCommit;
+ if (m.MajorImageVersion)
+ config->majorImageVersion = m.MajorImageVersion;
+ if (m.MinorImageVersion)
+ config->minorImageVersion = m.MinorImageVersion;
+ if (m.MajorOSVersion)
+ config->majorOSVersion = m.MajorOSVersion;
+ if (m.MinorOSVersion)
+ config->minorOSVersion = m.MinorOSVersion;
+
+ for (COFFShortExport e1 : m.Exports) {
+ Export e2;
// In simple cases, only Name is set. Renamed exports are parsed
// and set as "ExtName = Name". If Name has the form "OtherDll.Func",
// it shouldn't be a normal exported function but a forward to another
// DLL instead. This is supported by both MS and GNU linkers.
- if (E1.ExtName != E1.Name && StringRef(E1.Name).contains('.')) {
- E2.Name = Saver.save(E1.ExtName);
- E2.ForwardTo = Saver.save(E1.Name);
- Config->Exports.push_back(E2);
+ if (e1.ExtName != e1.Name && StringRef(e1.Name).contains('.')) {
+ e2.name = saver.save(e1.ExtName);
+ e2.forwardTo = saver.save(e1.Name);
+ config->exports.push_back(e2);
continue;
}
- E2.Name = Saver.save(E1.Name);
- E2.ExtName = Saver.save(E1.ExtName);
- E2.Ordinal = E1.Ordinal;
- E2.Noname = E1.Noname;
- E2.Data = E1.Data;
- E2.Private = E1.Private;
- E2.Constant = E1.Constant;
- Config->Exports.push_back(E2);
+ e2.name = saver.save(e1.Name);
+ e2.extName = saver.save(e1.ExtName);
+ e2.ordinal = e1.Ordinal;
+ e2.noname = e1.Noname;
+ e2.data = e1.Data;
+ e2.isPrivate = e1.Private;
+ e2.constant = e1.Constant;
+ config->exports.push_back(e2);
}
}
-void LinkerDriver::enqueueTask(std::function<void()> Task) {
- TaskQueue.push_back(std::move(Task));
+void LinkerDriver::enqueueTask(std::function<void()> task) {
+ taskQueue.push_back(std::move(task));
}
bool LinkerDriver::run() {
- ScopedTimer T(InputFileTimer);
+ ScopedTimer t(inputFileTimer);
- bool DidWork = !TaskQueue.empty();
- while (!TaskQueue.empty()) {
- TaskQueue.front()();
- TaskQueue.pop_front();
+ bool didWork = !taskQueue.empty();
+ while (!taskQueue.empty()) {
+ taskQueue.front()();
+ taskQueue.pop_front();
}
- return DidWork;
+ return didWork;
}
// Parse an /order file. If an option is given, the linker places
// COMDAT sections in the same order as their names appear in the
// given file.
-static void parseOrderFile(StringRef Arg) {
+static void parseOrderFile(StringRef arg) {
// For some reason, the MSVC linker requires a filename to be
// preceded by "@".
- if (!Arg.startswith("@")) {
+ if (!arg.startswith("@")) {
error("malformed /order option: '@' missing");
return;
}
// Get a list of all comdat sections for error checking.
- DenseSet<StringRef> Set;
- for (Chunk *C : Symtab->getChunks())
- if (auto *Sec = dyn_cast<SectionChunk>(C))
- if (Sec->Sym)
- Set.insert(Sec->Sym->getName());
+ DenseSet<StringRef> set;
+ for (Chunk *c : symtab->getChunks())
+ if (auto *sec = dyn_cast<SectionChunk>(c))
+ if (sec->sym)
+ set.insert(sec->sym->getName());
// Open a file.
- StringRef Path = Arg.substr(1);
- std::unique_ptr<MemoryBuffer> MB = CHECK(
- MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
+ StringRef path = arg.substr(1);
+ std::unique_ptr<MemoryBuffer> mb = CHECK(
+ MemoryBuffer::getFile(path, -1, false, true), "could not open " + path);
// Parse a file. An order file contains one symbol per line.
// All symbols that were not present in a given order file are
// considered to have the lowest priority 0 and are placed at
// end of an output section.
- for (std::string S : args::getLines(MB->getMemBufferRef())) {
- if (Config->Machine == I386 && !isDecorated(S))
- S = "_" + S;
+ for (std::string s : args::getLines(mb->getMemBufferRef())) {
+ if (config->machine == I386 && !isDecorated(s))
+ s = "_" + s;
- if (Set.count(S) == 0) {
- if (Config->WarnMissingOrderSymbol)
- warn("/order:" + Arg + ": missing symbol: " + S + " [LNK4037]");
+ if (set.count(s) == 0) {
+ if (config->warnMissingOrderSymbol)
+ warn("/order:" + arg + ": missing symbol: " + s + " [LNK4037]");
}
else
- Config->Order[S] = INT_MIN + Config->Order.size();
+ config->order[s] = INT_MIN + config->order.size();
}
}
-static void markAddrsig(Symbol *S) {
- if (auto *D = dyn_cast_or_null<Defined>(S))
- if (SectionChunk *C = dyn_cast_or_null<SectionChunk>(D->getChunk()))
- C->KeepUnique = true;
+static void markAddrsig(Symbol *s) {
+ if (auto *d = dyn_cast_or_null<Defined>(s))
+ if (SectionChunk *c = dyn_cast_or_null<SectionChunk>(d->getChunk()))
+ c->keepUnique = true;
}
static void findKeepUniqueSections() {
// Exported symbols could be address-significant in other executables or DSOs,
// so we conservatively mark them as address-significant.
- for (Export &R : Config->Exports)
- markAddrsig(R.Sym);
+ for (Export &r : config->exports)
+ markAddrsig(r.sym);
// Visit the address-significance table in each object file and mark each
// referenced symbol as address-significant.
- for (ObjFile *Obj : ObjFile::Instances) {
- ArrayRef<Symbol *> Syms = Obj->getSymbols();
- if (Obj->AddrsigSec) {
- ArrayRef<uint8_t> Contents;
+ for (ObjFile *obj : ObjFile::instances) {
+ ArrayRef<Symbol *> syms = obj->getSymbols();
+ if (obj->addrsigSec) {
+ ArrayRef<uint8_t> contents;
cantFail(
- Obj->getCOFFObj()->getSectionContents(Obj->AddrsigSec, Contents));
- const uint8_t *Cur = Contents.begin();
- while (Cur != Contents.end()) {
- unsigned Size;
- const char *Err;
- uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err);
- if (Err)
- fatal(toString(Obj) + ": could not decode addrsig section: " + Err);
- if (SymIndex >= Syms.size())
- fatal(toString(Obj) + ": invalid symbol index in addrsig section");
- markAddrsig(Syms[SymIndex]);
- Cur += Size;
+ obj->getCOFFObj()->getSectionContents(obj->addrsigSec, contents));
+ const uint8_t *cur = contents.begin();
+ while (cur != contents.end()) {
+ unsigned size;
+ const char *err;
+ uint64_t symIndex = decodeULEB128(cur, &size, contents.end(), &err);
+ if (err)
+ fatal(toString(obj) + ": could not decode addrsig section: " + err);
+ if (symIndex >= syms.size())
+ fatal(toString(obj) + ": invalid symbol index in addrsig section");
+ markAddrsig(syms[symIndex]);
+ cur += size;
}
} else {
// If an object file does not have an address-significance table,
// conservatively mark all of its symbols as address-significant.
- for (Symbol *S : Syms)
- markAddrsig(S);
+ for (Symbol *s : syms)
+ markAddrsig(s);
}
}
}
// binary).
// lld only supports %_PDB% and %_EXT% and warns on references to all other env
// vars.
-static void parsePDBAltPath(StringRef AltPath) {
- SmallString<128> Buf;
- StringRef PDBBasename =
- sys::path::filename(Config->PDBPath, sys::path::Style::windows);
- StringRef BinaryExtension =
- sys::path::extension(Config->OutputFile, sys::path::Style::windows);
- if (!BinaryExtension.empty())
- BinaryExtension = BinaryExtension.substr(1); // %_EXT% does not include '.'.
+static void parsePDBAltPath(StringRef altPath) {
+ SmallString<128> buf;
+ StringRef pdbBasename =
+ sys::path::filename(config->pdbPath, sys::path::Style::windows);
+ StringRef binaryExtension =
+ sys::path::extension(config->outputFile, sys::path::Style::windows);
+ if (!binaryExtension.empty())
+ binaryExtension = binaryExtension.substr(1); // %_EXT% does not include '.'.
// Invariant:
// +--------- Cursor ('a...' might be the empty string).
// | | +- SecondMark
// v v v
// a...%...%...
- size_t Cursor = 0;
- while (Cursor < AltPath.size()) {
- size_t FirstMark, SecondMark;
- if ((FirstMark = AltPath.find('%', Cursor)) == StringRef::npos ||
- (SecondMark = AltPath.find('%', FirstMark + 1)) == StringRef::npos) {
+ size_t cursor = 0;
+ while (cursor < altPath.size()) {
+ size_t firstMark, secondMark;
+ if ((firstMark = altPath.find('%', cursor)) == StringRef::npos ||
+ (secondMark = altPath.find('%', firstMark + 1)) == StringRef::npos) {
// Didn't find another full fragment, treat rest of string as literal.
- Buf.append(AltPath.substr(Cursor));
+ buf.append(altPath.substr(cursor));
break;
}
// Found a full fragment. Append text in front of first %, and interpret
// text between first and second % as variable name.
- Buf.append(AltPath.substr(Cursor, FirstMark - Cursor));
- StringRef Var = AltPath.substr(FirstMark, SecondMark - FirstMark + 1);
- if (Var.equals_lower("%_pdb%"))
- Buf.append(PDBBasename);
- else if (Var.equals_lower("%_ext%"))
- Buf.append(BinaryExtension);
+ buf.append(altPath.substr(cursor, firstMark - cursor));
+ StringRef var = altPath.substr(firstMark, secondMark - firstMark + 1);
+ if (var.equals_lower("%_pdb%"))
+ buf.append(pdbBasename);
+ else if (var.equals_lower("%_ext%"))
+ buf.append(binaryExtension);
else {
warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " +
- Var + " as literal");
- Buf.append(Var);
+ var + " as literal");
+ buf.append(var);
}
- Cursor = SecondMark + 1;
+ cursor = secondMark + 1;
}
- Config->PDBAltPath = Buf;
+ config->pdbAltPath = buf;
}
/// Check that at most one resource obj file was used.
// LNK4078, mirror that. The normal use of resource files is to give the
// linker many .res files, which are then converted to a single resource obj
// file internally, so this is not a big restriction in practice.
- ObjFile *ResourceObjFile = nullptr;
- for (ObjFile *F : ObjFile::Instances) {
- if (!F->IsResourceObjFile)
+ ObjFile *resourceObjFile = nullptr;
+ for (ObjFile *f : ObjFile::instances) {
+ if (!f->isResourceObjFile)
continue;
- if (!ResourceObjFile) {
- ResourceObjFile = F;
+ if (!resourceObjFile) {
+ resourceObjFile = f;
continue;
}
- error(toString(F) +
+ error(toString(f) +
": more than one resource obj file not allowed, already got " +
- toString(ResourceObjFile));
+ toString(resourceObjFile));
}
}
// explicitly specified. The automatic behavior can be disabled using the
// -exclude-all-symbols option, so that lld-link behaves like link.exe rather
// than MinGW in the case that nothing is explicitly exported.
-void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &Args) {
- if (!Config->DLL)
+void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
+ if (!config->dll)
return;
- if (!Args.hasArg(OPT_export_all_symbols)) {
- if (!Config->Exports.empty())
+ if (!args.hasArg(OPT_export_all_symbols)) {
+ if (!config->exports.empty())
return;
- if (Args.hasArg(OPT_exclude_all_symbols))
+ if (args.hasArg(OPT_exclude_all_symbols))
return;
}
- AutoExporter Exporter;
+ AutoExporter exporter;
- for (auto *Arg : Args.filtered(OPT_wholearchive_file))
- if (Optional<StringRef> Path = doFindFile(Arg->getValue()))
- Exporter.addWholeArchive(*Path);
+ for (auto *arg : args.filtered(OPT_wholearchive_file))
+ if (Optional<StringRef> path = doFindFile(arg->getValue()))
+ exporter.addWholeArchive(*path);
- Symtab->forEachSymbol([&](Symbol *S) {
- auto *Def = dyn_cast<Defined>(S);
- if (!Exporter.shouldExport(Def))
+ symtab->forEachSymbol([&](Symbol *s) {
+ auto *def = dyn_cast<Defined>(s);
+ if (!exporter.shouldExport(def))
return;
- Export E;
- E.Name = Def->getName();
- E.Sym = Def;
- if (Chunk *C = Def->getChunk())
- if (!(C->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
- E.Data = true;
- Config->Exports.push_back(E);
+ Export e;
+ e.name = def->getName();
+ e.sym = def;
+ if (Chunk *c = def->getChunk())
+ if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
+ e.data = true;
+ config->exports.push_back(e);
});
}
-void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
+void LinkerDriver::link(ArrayRef<const char *> argsArr) {
// Needed for LTO.
InitializeAllTargetInfos();
InitializeAllTargets();
// If the first command line argument is "/lib", link.exe acts like lib.exe.
// We call our own implementation of lib.exe that understands bitcode files.
- if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) {
- if (llvm::libDriverMain(ArgsArr.slice(1)) != 0)
+ if (argsArr.size() > 1 && StringRef(argsArr[1]).equals_lower("/lib")) {
+ if (llvm::libDriverMain(argsArr.slice(1)) != 0)
fatal("lib failed");
return;
}
// Parse command line options.
- ArgParser Parser;
- opt::InputArgList Args = Parser.parseLINK(ArgsArr);
+ ArgParser parser;
+ opt::InputArgList args = parser.parseLINK(argsArr);
// Parse and evaluate -mllvm options.
- std::vector<const char *> V;
- V.push_back("lld-link (LLVM option parsing)");
- for (auto *Arg : Args.filtered(OPT_mllvm))
- V.push_back(Arg->getValue());
- cl::ParseCommandLineOptions(V.size(), V.data());
+ std::vector<const char *> v;
+ v.push_back("lld-link (LLVM option parsing)");
+ for (auto *arg : args.filtered(OPT_mllvm))
+ v.push_back(arg->getValue());
+ cl::ParseCommandLineOptions(v.size(), v.data());
// Handle /errorlimit early, because error() depends on it.
- if (auto *Arg = Args.getLastArg(OPT_errorlimit)) {
- int N = 20;
- StringRef S = Arg->getValue();
- if (S.getAsInteger(10, N))
- error(Arg->getSpelling() + " number expected, but got " + S);
- errorHandler().ErrorLimit = N;
+ if (auto *arg = args.getLastArg(OPT_errorlimit)) {
+ int n = 20;
+ StringRef s = arg->getValue();
+ if (s.getAsInteger(10, n))
+ error(arg->getSpelling() + " number expected, but got " + s);
+ errorHandler().errorLimit = n;
}
// Handle /help
- if (Args.hasArg(OPT_help)) {
- printHelp(ArgsArr[0]);
+ if (args.hasArg(OPT_help)) {
+ printHelp(argsArr[0]);
return;
}
- lld::ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_threads_no, true);
+ lld::threadsEnabled = args.hasFlag(OPT_threads, OPT_threads_no, true);
- if (Args.hasArg(OPT_show_timing))
- Config->ShowTiming = true;
+ if (args.hasArg(OPT_show_timing))
+ config->showTiming = true;
- Config->ShowSummary = Args.hasArg(OPT_summary);
+ config->showSummary = args.hasArg(OPT_summary);
- ScopedTimer T(Timer::root());
+ ScopedTimer t(Timer::root());
// Handle --version, which is an lld extension. This option is a bit odd
// because it doesn't start with "/", but we deliberately chose "--" to
// avoid conflict with /version and for compatibility with clang-cl.
- if (Args.hasArg(OPT_dash_dash_version)) {
+ if (args.hasArg(OPT_dash_dash_version)) {
outs() << getLLDVersion() << "\n";
return;
}
// Handle /lldmingw early, since it can potentially affect how other
// options are handled.
- Config->MinGW = Args.hasArg(OPT_lldmingw);
+ config->mingw = args.hasArg(OPT_lldmingw);
- if (auto *Arg = Args.getLastArg(OPT_linkrepro)) {
- SmallString<64> Path = StringRef(Arg->getValue());
- sys::path::append(Path, "repro.tar");
+ if (auto *arg = args.getLastArg(OPT_linkrepro)) {
+ SmallString<64> path = StringRef(arg->getValue());
+ sys::path::append(path, "repro.tar");
- Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
- TarWriter::create(Path, "repro");
+ Expected<std::unique_ptr<TarWriter>> errOrWriter =
+ TarWriter::create(path, "repro");
- if (ErrOrWriter) {
- Tar = std::move(*ErrOrWriter);
+ if (errOrWriter) {
+ tar = std::move(*errOrWriter);
} else {
- error("/linkrepro: failed to open " + Path + ": " +
- toString(ErrOrWriter.takeError()));
+ error("/linkrepro: failed to open " + path + ": " +
+ toString(errOrWriter.takeError()));
}
}
- if (!Args.hasArg(OPT_INPUT)) {
- if (Args.hasArg(OPT_deffile))
- Config->NoEntry = true;
+ if (!args.hasArg(OPT_INPUT)) {
+ if (args.hasArg(OPT_deffile))
+ config->noEntry = true;
else
fatal("no input files");
}
// Construct search path list.
- SearchPaths.push_back("");
- for (auto *Arg : Args.filtered(OPT_libpath))
- SearchPaths.push_back(Arg->getValue());
+ searchPaths.push_back("");
+ for (auto *arg : args.filtered(OPT_libpath))
+ searchPaths.push_back(arg->getValue());
addLibSearchPaths();
// Handle /ignore
- for (auto *Arg : Args.filtered(OPT_ignore)) {
- SmallVector<StringRef, 8> Vec;
- StringRef(Arg->getValue()).split(Vec, ',');
- for (StringRef S : Vec) {
- if (S == "4037")
- Config->WarnMissingOrderSymbol = false;
- else if (S == "4099")
- Config->WarnDebugInfoUnusable = false;
- else if (S == "4217")
- Config->WarnLocallyDefinedImported = false;
+ for (auto *arg : args.filtered(OPT_ignore)) {
+ SmallVector<StringRef, 8> vec;
+ StringRef(arg->getValue()).split(vec, ',');
+ for (StringRef s : vec) {
+ if (s == "4037")
+ config->warnMissingOrderSymbol = false;
+ else if (s == "4099")
+ config->warnDebugInfoUnusable = false;
+ else if (s == "4217")
+ config->warnLocallyDefinedImported = false;
// Other warning numbers are ignored.
}
}
// Handle /out
- if (auto *Arg = Args.getLastArg(OPT_out))
- Config->OutputFile = Arg->getValue();
+ if (auto *arg = args.getLastArg(OPT_out))
+ config->outputFile = arg->getValue();
// Handle /verbose
- if (Args.hasArg(OPT_verbose))
- Config->Verbose = true;
- errorHandler().Verbose = Config->Verbose;
+ if (args.hasArg(OPT_verbose))
+ config->verbose = true;
+ errorHandler().verbose = config->verbose;
// Handle /force or /force:unresolved
- if (Args.hasArg(OPT_force, OPT_force_unresolved))
- Config->ForceUnresolved = true;
+ if (args.hasArg(OPT_force, OPT_force_unresolved))
+ config->forceUnresolved = true;
// Handle /force or /force:multiple
- if (Args.hasArg(OPT_force, OPT_force_multiple))
- Config->ForceMultiple = true;
+ if (args.hasArg(OPT_force, OPT_force_multiple))
+ config->forceMultiple = true;
// Handle /force or /force:multipleres
- if (Args.hasArg(OPT_force, OPT_force_multipleres))
- Config->ForceMultipleRes = true;
+ if (args.hasArg(OPT_force, OPT_force_multipleres))
+ config->forceMultipleRes = true;
// Handle /debug
- DebugKind Debug = parseDebugKind(Args);
- if (Debug == DebugKind::Full || Debug == DebugKind::Dwarf ||
- Debug == DebugKind::GHash) {
- Config->Debug = true;
- Config->Incremental = true;
+ DebugKind debug = parseDebugKind(args);
+ if (debug == DebugKind::Full || debug == DebugKind::Dwarf ||
+ debug == DebugKind::GHash) {
+ config->debug = true;
+ config->incremental = true;
}
// Handle /demangle
- Config->Demangle = Args.hasFlag(OPT_demangle, OPT_demangle_no);
+ config->demangle = args.hasFlag(OPT_demangle, OPT_demangle_no);
// Handle /debugtype
- Config->DebugTypes = parseDebugTypes(Args);
+ config->debugTypes = parseDebugTypes(args);
// Handle /pdb
- bool ShouldCreatePDB =
- (Debug == DebugKind::Full || Debug == DebugKind::GHash);
- if (ShouldCreatePDB) {
- if (auto *Arg = Args.getLastArg(OPT_pdb))
- Config->PDBPath = Arg->getValue();
- if (auto *Arg = Args.getLastArg(OPT_pdbaltpath))
- Config->PDBAltPath = Arg->getValue();
- if (Args.hasArg(OPT_natvis))
- Config->NatvisFiles = Args.getAllArgValues(OPT_natvis);
+ bool shouldCreatePDB =
+ (debug == DebugKind::Full || debug == DebugKind::GHash);
+ if (shouldCreatePDB) {
+ if (auto *arg = args.getLastArg(OPT_pdb))
+ config->pdbPath = arg->getValue();
+ if (auto *arg = args.getLastArg(OPT_pdbaltpath))
+ config->pdbAltPath = arg->getValue();
+ if (args.hasArg(OPT_natvis))
+ config->natvisFiles = args.getAllArgValues(OPT_natvis);
- if (auto *Arg = Args.getLastArg(OPT_pdb_source_path))
- Config->PDBSourcePath = Arg->getValue();
+ if (auto *arg = args.getLastArg(OPT_pdb_source_path))
+ config->pdbSourcePath = arg->getValue();
}
// Handle /noentry
- if (Args.hasArg(OPT_noentry)) {
- if (Args.hasArg(OPT_dll))
- Config->NoEntry = true;
+ if (args.hasArg(OPT_noentry)) {
+ if (args.hasArg(OPT_dll))
+ config->noEntry = true;
else
error("/noentry must be specified with /dll");
}
// Handle /dll
- if (Args.hasArg(OPT_dll)) {
- Config->DLL = true;
- Config->ManifestID = 2;
+ if (args.hasArg(OPT_dll)) {
+ config->dll = true;
+ config->manifestID = 2;
}
// Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase
// because we need to explicitly check whether that option or its inverse was
// present in the argument list in order to handle /fixed.
- auto *DynamicBaseArg = Args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no);
- if (DynamicBaseArg &&
- DynamicBaseArg->getOption().getID() == OPT_dynamicbase_no)
- Config->DynamicBase = false;
+ auto *dynamicBaseArg = args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no);
+ if (dynamicBaseArg &&
+ dynamicBaseArg->getOption().getID() == OPT_dynamicbase_no)
+ config->dynamicBase = false;
// MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the
// default setting for any other project type.", but link.exe defaults to
// /FIXED:NO for exe outputs as well. Match behavior, not docs.
- bool Fixed = Args.hasFlag(OPT_fixed, OPT_fixed_no, false);
- if (Fixed) {
- if (DynamicBaseArg &&
- DynamicBaseArg->getOption().getID() == OPT_dynamicbase) {
+ bool fixed = args.hasFlag(OPT_fixed, OPT_fixed_no, false);
+ if (fixed) {
+ if (dynamicBaseArg &&
+ dynamicBaseArg->getOption().getID() == OPT_dynamicbase) {
error("/fixed must not be specified with /dynamicbase");
} else {
- Config->Relocatable = false;
- Config->DynamicBase = false;
+ config->relocatable = false;
+ config->dynamicBase = false;
}
}
// Handle /appcontainer
- Config->AppContainer =
- Args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false);
+ config->appContainer =
+ args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false);
// Handle /machine
- if (auto *Arg = Args.getLastArg(OPT_machine)) {
- Config->Machine = getMachineType(Arg->getValue());
- if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN)
- fatal(Twine("unknown /machine argument: ") + Arg->getValue());
+ if (auto *arg = args.getLastArg(OPT_machine)) {
+ config->machine = getMachineType(arg->getValue());
+ if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN)
+ fatal(Twine("unknown /machine argument: ") + arg->getValue());
}
// Handle /nodefaultlib:<filename>
- for (auto *Arg : Args.filtered(OPT_nodefaultlib))
- Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()).lower());
+ for (auto *arg : args.filtered(OPT_nodefaultlib))
+ config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower());
// Handle /nodefaultlib
- if (Args.hasArg(OPT_nodefaultlib_all))
- Config->NoDefaultLibAll = true;
+ if (args.hasArg(OPT_nodefaultlib_all))
+ config->noDefaultLibAll = true;
// Handle /base
- if (auto *Arg = Args.getLastArg(OPT_base))
- parseNumbers(Arg->getValue(), &Config->ImageBase);
+ if (auto *arg = args.getLastArg(OPT_base))
+ parseNumbers(arg->getValue(), &config->imageBase);
// Handle /filealign
- if (auto *Arg = Args.getLastArg(OPT_filealign)) {
- parseNumbers(Arg->getValue(), &Config->FileAlign);
- if (!isPowerOf2_64(Config->FileAlign))
- error("/filealign: not a power of two: " + Twine(Config->FileAlign));
+ if (auto *arg = args.getLastArg(OPT_filealign)) {
+ parseNumbers(arg->getValue(), &config->fileAlign);
+ if (!isPowerOf2_64(config->fileAlign))
+ error("/filealign: not a power of two: " + Twine(config->fileAlign));
}
// Handle /stack
- if (auto *Arg = Args.getLastArg(OPT_stack))
- parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);
+ if (auto *arg = args.getLastArg(OPT_stack))
+ parseNumbers(arg->getValue(), &config->stackReserve, &config->stackCommit);
// Handle /guard:cf
- if (auto *Arg = Args.getLastArg(OPT_guard))
- parseGuard(Arg->getValue());
+ if (auto *arg = args.getLastArg(OPT_guard))
+ parseGuard(arg->getValue());
// Handle /heap
- if (auto *Arg = Args.getLastArg(OPT_heap))
- parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit);
+ if (auto *arg = args.getLastArg(OPT_heap))
+ parseNumbers(arg->getValue(), &config->heapReserve, &config->heapCommit);
// Handle /version
- if (auto *Arg = Args.getLastArg(OPT_version))
- parseVersion(Arg->getValue(), &Config->MajorImageVersion,
- &Config->MinorImageVersion);
+ if (auto *arg = args.getLastArg(OPT_version))
+ parseVersion(arg->getValue(), &config->majorImageVersion,
+ &config->minorImageVersion);
// Handle /subsystem
- if (auto *Arg = Args.getLastArg(OPT_subsystem))
- parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion,
- &Config->MinorOSVersion);
+ if (auto *arg = args.getLastArg(OPT_subsystem))
+ parseSubsystem(arg->getValue(), &config->subsystem, &config->majorOSVersion,
+ &config->minorOSVersion);
// Handle /timestamp
- if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) {
- if (Arg->getOption().getID() == OPT_repro) {
- Config->Timestamp = 0;
- Config->Repro = true;
+ if (llvm::opt::Arg *arg = args.getLastArg(OPT_timestamp, OPT_repro)) {
+ if (arg->getOption().getID() == OPT_repro) {
+ config->timestamp = 0;
+ config->repro = true;
} else {
- Config->Repro = false;
- StringRef Value(Arg->getValue());
- if (Value.getAsInteger(0, Config->Timestamp))
- fatal(Twine("invalid timestamp: ") + Value +
+ config->repro = false;
+ StringRef value(arg->getValue());
+ if (value.getAsInteger(0, config->timestamp))
+ fatal(Twine("invalid timestamp: ") + value +
". Expected 32-bit integer");
}
} else {
- Config->Repro = false;
- Config->Timestamp = time(nullptr);
+ config->repro = false;
+ config->timestamp = time(nullptr);
}
// Handle /alternatename
- for (auto *Arg : Args.filtered(OPT_alternatename))
- parseAlternateName(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_alternatename))
+ parseAlternateName(arg->getValue());
// Handle /include
- for (auto *Arg : Args.filtered(OPT_incl))
- addUndefined(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_incl))
+ addUndefined(arg->getValue());
// Handle /implib
- if (auto *Arg = Args.getLastArg(OPT_implib))
- Config->Implib = Arg->getValue();
+ if (auto *arg = args.getLastArg(OPT_implib))
+ config->implib = arg->getValue();
// Handle /opt.
- bool DoGC = Debug == DebugKind::None || Args.hasArg(OPT_profile);
- unsigned ICFLevel =
- Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on
- unsigned TailMerge = 1;
- for (auto *Arg : Args.filtered(OPT_opt)) {
- std::string Str = StringRef(Arg->getValue()).lower();
- SmallVector<StringRef, 1> Vec;
- StringRef(Str).split(Vec, ',');
- for (StringRef S : Vec) {
- if (S == "ref") {
- DoGC = true;
- } else if (S == "noref") {
- DoGC = false;
- } else if (S == "icf" || S.startswith("icf=")) {
- ICFLevel = 2;
- } else if (S == "noicf") {
- ICFLevel = 0;
- } else if (S == "lldtailmerge") {
- TailMerge = 2;
- } else if (S == "nolldtailmerge") {
- TailMerge = 0;
- } else if (S.startswith("lldlto=")) {
- StringRef OptLevel = S.substr(7);
- if (OptLevel.getAsInteger(10, Config->LTOO) || Config->LTOO > 3)
- error("/opt:lldlto: invalid optimization level: " + OptLevel);
- } else if (S.startswith("lldltojobs=")) {
- StringRef Jobs = S.substr(11);
- if (Jobs.getAsInteger(10, Config->ThinLTOJobs) ||
- Config->ThinLTOJobs == 0)
- error("/opt:lldltojobs: invalid job count: " + Jobs);
- } else if (S.startswith("lldltopartitions=")) {
- StringRef N = S.substr(17);
- if (N.getAsInteger(10, Config->LTOPartitions) ||
- Config->LTOPartitions == 0)
- error("/opt:lldltopartitions: invalid partition count: " + N);
- } else if (S != "lbr" && S != "nolbr")
- error("/opt: unknown option: " + S);
+ bool doGC = debug == DebugKind::None || args.hasArg(OPT_profile);
+ unsigned icfLevel =
+ args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on
+ unsigned tailMerge = 1;
+ for (auto *arg : args.filtered(OPT_opt)) {
+ std::string str = StringRef(arg->getValue()).lower();
+ SmallVector<StringRef, 1> vec;
+ StringRef(str).split(vec, ',');
+ for (StringRef s : vec) {
+ if (s == "ref") {
+ doGC = true;
+ } else if (s == "noref") {
+ doGC = false;
+ } else if (s == "icf" || s.startswith("icf=")) {
+ icfLevel = 2;
+ } else if (s == "noicf") {
+ icfLevel = 0;
+ } else if (s == "lldtailmerge") {
+ tailMerge = 2;
+ } else if (s == "nolldtailmerge") {
+ tailMerge = 0;
+ } else if (s.startswith("lldlto=")) {
+ StringRef optLevel = s.substr(7);
+ if (optLevel.getAsInteger(10, config->ltoo) || config->ltoo > 3)
+ error("/opt:lldlto: invalid optimization level: " + optLevel);
+ } else if (s.startswith("lldltojobs=")) {
+ StringRef jobs = s.substr(11);
+ if (jobs.getAsInteger(10, config->thinLTOJobs) ||
+ config->thinLTOJobs == 0)
+ error("/opt:lldltojobs: invalid job count: " + jobs);
+ } else if (s.startswith("lldltopartitions=")) {
+ StringRef n = s.substr(17);
+ if (n.getAsInteger(10, config->ltoPartitions) ||
+ config->ltoPartitions == 0)
+ error("/opt:lldltopartitions: invalid partition count: " + n);
+ } else if (s != "lbr" && s != "nolbr")
+ error("/opt: unknown option: " + s);
}
}
// FIXME: LLD only implements "limited" ICF, i.e. it only merges identical
// code. If the user passes /OPT:ICF explicitly, LLD should merge identical
// comdat readonly data.
- if (ICFLevel == 1 && !DoGC)
- ICFLevel = 0;
- Config->DoGC = DoGC;
- Config->DoICF = ICFLevel > 0;
- Config->TailMerge = (TailMerge == 1 && Config->DoICF) || TailMerge == 2;
+ if (icfLevel == 1 && !doGC)
+ icfLevel = 0;
+ config->doGC = doGC;
+ config->doICF = icfLevel > 0;
+ config->tailMerge = (tailMerge == 1 && config->doICF) || tailMerge == 2;
// Handle /lldsavetemps
- if (Args.hasArg(OPT_lldsavetemps))
- Config->SaveTemps = true;
+ if (args.hasArg(OPT_lldsavetemps))
+ config->saveTemps = true;
// Handle /kill-at
- if (Args.hasArg(OPT_kill_at))
- Config->KillAt = true;
+ if (args.hasArg(OPT_kill_at))
+ config->killAt = true;
// Handle /lldltocache
- if (auto *Arg = Args.getLastArg(OPT_lldltocache))
- Config->LTOCache = Arg->getValue();
+ if (auto *arg = args.getLastArg(OPT_lldltocache))
+ config->ltoCache = arg->getValue();
// Handle /lldsavecachepolicy
- if (auto *Arg = Args.getLastArg(OPT_lldltocachepolicy))
- Config->LTOCachePolicy = CHECK(
- parseCachePruningPolicy(Arg->getValue()),
- Twine("/lldltocachepolicy: invalid cache policy: ") + Arg->getValue());
+ if (auto *arg = args.getLastArg(OPT_lldltocachepolicy))
+ config->ltoCachePolicy = CHECK(
+ parseCachePruningPolicy(arg->getValue()),
+ Twine("/lldltocachepolicy: invalid cache policy: ") + arg->getValue());
// Handle /failifmismatch
- for (auto *Arg : Args.filtered(OPT_failifmismatch))
- checkFailIfMismatch(Arg->getValue(), nullptr);
+ for (auto *arg : args.filtered(OPT_failifmismatch))
+ checkFailIfMismatch(arg->getValue(), nullptr);
// Handle /merge
- for (auto *Arg : Args.filtered(OPT_merge))
- parseMerge(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_merge))
+ parseMerge(arg->getValue());
// Add default section merging rules after user rules. User rules take
// precedence, but we will emit a warning if there is a conflict.
parseMerge(".xdata=.rdata");
parseMerge(".bss=.data");
- if (Config->MinGW) {
+ if (config->mingw) {
parseMerge(".ctors=.rdata");
parseMerge(".dtors=.rdata");
parseMerge(".CRT=.rdata");
}
// Handle /section
- for (auto *Arg : Args.filtered(OPT_section))
- parseSection(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_section))
+ parseSection(arg->getValue());
// Handle /aligncomm
- for (auto *Arg : Args.filtered(OPT_aligncomm))
- parseAligncomm(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_aligncomm))
+ parseAligncomm(arg->getValue());
// Handle /manifestdependency. This enables /manifest unless /manifest:no is
// also passed.
- if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) {
- Config->ManifestDependency = Arg->getValue();
- Config->Manifest = Configuration::SideBySide;
+ if (auto *arg = args.getLastArg(OPT_manifestdependency)) {
+ config->manifestDependency = arg->getValue();
+ config->manifest = Configuration::SideBySide;
}
// Handle /manifest and /manifest:
- if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) {
- if (Arg->getOption().getID() == OPT_manifest)
- Config->Manifest = Configuration::SideBySide;
+ if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) {
+ if (arg->getOption().getID() == OPT_manifest)
+ config->manifest = Configuration::SideBySide;
else
- parseManifest(Arg->getValue());
+ parseManifest(arg->getValue());
}
// Handle /manifestuac
- if (auto *Arg = Args.getLastArg(OPT_manifestuac))
- parseManifestUAC(Arg->getValue());
+ if (auto *arg = args.getLastArg(OPT_manifestuac))
+ parseManifestUAC(arg->getValue());
// Handle /manifestfile
- if (auto *Arg = Args.getLastArg(OPT_manifestfile))
- Config->ManifestFile = Arg->getValue();
+ if (auto *arg = args.getLastArg(OPT_manifestfile))
+ config->manifestFile = arg->getValue();
// Handle /manifestinput
- for (auto *Arg : Args.filtered(OPT_manifestinput))
- Config->ManifestInput.push_back(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_manifestinput))
+ config->manifestInput.push_back(arg->getValue());
- if (!Config->ManifestInput.empty() &&
- Config->Manifest != Configuration::Embed) {
+ if (!config->manifestInput.empty() &&
+ config->manifest != Configuration::Embed) {
fatal("/manifestinput: requires /manifest:embed");
}
// Handle miscellaneous boolean flags.
- Config->AllowBind = Args.hasFlag(OPT_allowbind, OPT_allowbind_no, true);
- Config->AllowIsolation =
- Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true);
- Config->Incremental =
- Args.hasFlag(OPT_incremental, OPT_incremental_no,
- !Config->DoGC && !Config->DoICF && !Args.hasArg(OPT_order) &&
- !Args.hasArg(OPT_profile));
- Config->IntegrityCheck =
- Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);
- Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
- for (auto *Arg : Args.filtered(OPT_swaprun))
- parseSwaprun(Arg->getValue());
- Config->TerminalServerAware =
- !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
- Config->DebugDwarf = Debug == DebugKind::Dwarf;
- Config->DebugGHashes = Debug == DebugKind::GHash;
- Config->DebugSymtab = Debug == DebugKind::Symtab;
-
- Config->MapFile = getMapFile(Args);
-
- if (Config->Incremental && Args.hasArg(OPT_profile)) {
+ config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true);
+ config->allowIsolation =
+ args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true);
+ config->incremental =
+ args.hasFlag(OPT_incremental, OPT_incremental_no,
+ !config->doGC && !config->doICF && !args.hasArg(OPT_order) &&
+ !args.hasArg(OPT_profile));
+ config->integrityCheck =
+ args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);
+ config->nxCompat = args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
+ for (auto *arg : args.filtered(OPT_swaprun))
+ parseSwaprun(arg->getValue());
+ config->terminalServerAware =
+ !config->dll && args.hasFlag(OPT_tsaware, OPT_tsaware_no, true);
+ config->debugDwarf = debug == DebugKind::Dwarf;
+ config->debugGHashes = debug == DebugKind::GHash;
+ config->debugSymtab = debug == DebugKind::Symtab;
+
+ config->mapFile = getMapFile(args);
+
+ if (config->incremental && args.hasArg(OPT_profile)) {
warn("ignoring '/incremental' due to '/profile' specification");
- Config->Incremental = false;
+ config->incremental = false;
}
- if (Config->Incremental && Args.hasArg(OPT_order)) {
+ if (config->incremental && args.hasArg(OPT_order)) {
warn("ignoring '/incremental' due to '/order' specification");
- Config->Incremental = false;
+ config->incremental = false;
}
- if (Config->Incremental && Config->DoGC) {
+ if (config->incremental && config->doGC) {
warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to "
"disable");
- Config->Incremental = false;
+ config->incremental = false;
}
- if (Config->Incremental && Config->DoICF) {
+ if (config->incremental && config->doICF) {
warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to "
"disable");
- Config->Incremental = false;
+ config->incremental = false;
}
if (errorCount())
return;
- std::set<sys::fs::UniqueID> WholeArchives;
- for (auto *Arg : Args.filtered(OPT_wholearchive_file))
- if (Optional<StringRef> Path = doFindFile(Arg->getValue()))
- if (Optional<sys::fs::UniqueID> ID = getUniqueID(*Path))
- WholeArchives.insert(*ID);
+ std::set<sys::fs::UniqueID> wholeArchives;
+ for (auto *arg : args.filtered(OPT_wholearchive_file))
+ if (Optional<StringRef> path = doFindFile(arg->getValue()))
+ if (Optional<sys::fs::UniqueID> id = getUniqueID(*path))
+ wholeArchives.insert(*id);
// A predicate returning true if a given path is an argument for
// /wholearchive:, or /wholearchive is enabled globally.
// This function is a bit tricky because "foo.obj /wholearchive:././foo.obj"
// needs to be handled as "/wholearchive:foo.obj foo.obj".
- auto IsWholeArchive = [&](StringRef Path) -> bool {
- if (Args.hasArg(OPT_wholearchive_flag))
+ auto isWholeArchive = [&](StringRef path) -> bool {
+ if (args.hasArg(OPT_wholearchive_flag))
return true;
- if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path))
- return WholeArchives.count(*ID);
+ if (Optional<sys::fs::UniqueID> id = getUniqueID(path))
+ return wholeArchives.count(*id);
return false;
};
// Create a list of input files. Files can be given as arguments
// for /defaultlib option.
- for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file))
- if (Optional<StringRef> Path = findFile(Arg->getValue()))
- enqueuePath(*Path, IsWholeArchive(*Path));
+ for (auto *arg : args.filtered(OPT_INPUT, OPT_wholearchive_file))
+ if (Optional<StringRef> path = findFile(arg->getValue()))
+ enqueuePath(*path, isWholeArchive(*path));
- for (auto *Arg : Args.filtered(OPT_defaultlib))
- if (Optional<StringRef> Path = findLib(Arg->getValue()))
- enqueuePath(*Path, false);
+ for (auto *arg : args.filtered(OPT_defaultlib))
+ if (Optional<StringRef> path = findLib(arg->getValue()))
+ enqueuePath(*path, false);
// Windows specific -- Create a resource file containing a manifest file.
- if (Config->Manifest == Configuration::Embed)
+ if (config->manifest == Configuration::Embed)
addBuffer(createManifestRes(), false);
// Read all input files given via the command line.
// We should have inferred a machine type by now from the input files, but if
// not we assume x64.
- if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+ if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) {
warn("/machine is not specified. x64 is assumed");
- Config->Machine = AMD64;
+ config->machine = AMD64;
}
- Config->Wordsize = Config->is64() ? 8 : 4;
+ config->wordsize = config->is64() ? 8 : 4;
// Handle /functionpadmin
- for (auto *Arg : Args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
- parseFunctionPadMin(Arg, Config->Machine);
+ for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
+ parseFunctionPadMin(arg, config->machine);
// Input files can be Windows resource files (.res files). We use
// WindowsResource to convert resource files to a regular COFF file,
// then link the resulting file normally.
- if (!Resources.empty())
- Symtab->addFile(make<ObjFile>(convertResToCOFF(Resources)));
+ if (!resources.empty())
+ symtab->addFile(make<ObjFile>(convertResToCOFF(resources)));
- if (Tar)
- Tar->append("response.txt",
- createResponseFile(Args, FilePaths,
- ArrayRef<StringRef>(SearchPaths).slice(1)));
+ if (tar)
+ tar->append("response.txt",
+ createResponseFile(args, filePaths,
+ ArrayRef<StringRef>(searchPaths).slice(1)));
// Handle /largeaddressaware
- Config->LargeAddressAware = Args.hasFlag(
- OPT_largeaddressaware, OPT_largeaddressaware_no, Config->is64());
+ config->largeAddressAware = args.hasFlag(
+ OPT_largeaddressaware, OPT_largeaddressaware_no, config->is64());
// Handle /highentropyva
- Config->HighEntropyVA =
- Config->is64() &&
- Args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true);
+ config->highEntropyVA =
+ config->is64() &&
+ args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true);
- if (!Config->DynamicBase &&
- (Config->Machine == ARMNT || Config->Machine == ARM64))
+ if (!config->dynamicBase &&
+ (config->machine == ARMNT || config->machine == ARM64))
error("/dynamicbase:no is not compatible with " +
- machineToStr(Config->Machine));
+ machineToStr(config->machine));
// Handle /export
- for (auto *Arg : Args.filtered(OPT_export)) {
- Export E = parseExport(Arg->getValue());
- if (Config->Machine == I386) {
- if (!isDecorated(E.Name))
- E.Name = Saver.save("_" + E.Name);
- if (!E.ExtName.empty() && !isDecorated(E.ExtName))
- E.ExtName = Saver.save("_" + E.ExtName);
+ for (auto *arg : args.filtered(OPT_export)) {
+ Export e = parseExport(arg->getValue());
+ if (config->machine == I386) {
+ if (!isDecorated(e.name))
+ e.name = saver.save("_" + e.name);
+ if (!e.extName.empty() && !isDecorated(e.extName))
+ e.extName = saver.save("_" + e.extName);
}
- Config->Exports.push_back(E);
+ config->exports.push_back(e);
}
// Handle /def
- if (auto *Arg = Args.getLastArg(OPT_deffile)) {
+ if (auto *arg = args.getLastArg(OPT_deffile)) {
// parseModuleDefs mutates Config object.
- parseModuleDefs(Arg->getValue());
+ parseModuleDefs(arg->getValue());
}
// Handle generation of import library from a def file.
- if (!Args.hasArg(OPT_INPUT)) {
+ if (!args.hasArg(OPT_INPUT)) {
fixupExports();
createImportLibrary(/*AsLib=*/true);
return;
// Windows specific -- if no /subsystem is given, we need to infer
// that from entry point name. Must happen before /entry handling,
// and after the early return when just writing an import library.
- if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
- Config->Subsystem = inferSubsystem();
- if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
+ if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
+ config->subsystem = inferSubsystem();
+ if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
fatal("subsystem must be defined");
}
// Handle /entry and /dll
- if (auto *Arg = Args.getLastArg(OPT_entry)) {
- Config->Entry = addUndefined(mangle(Arg->getValue()));
- } else if (!Config->Entry && !Config->NoEntry) {
- if (Args.hasArg(OPT_dll)) {
- StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12"
+ if (auto *arg = args.getLastArg(OPT_entry)) {
+ config->entry = addUndefined(mangle(arg->getValue()));
+ } else if (!config->entry && !config->noEntry) {
+ if (args.hasArg(OPT_dll)) {
+ StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12"
: "_DllMainCRTStartup";
- Config->Entry = addUndefined(S);
+ config->entry = addUndefined(s);
} else {
// Windows specific -- If entry point name is not given, we need to
// infer that from user-defined entry name.
- StringRef S = findDefaultEntry();
- if (S.empty())
+ StringRef s = findDefaultEntry();
+ if (s.empty())
fatal("entry point must be defined");
- Config->Entry = addUndefined(S);
- log("Entry name inferred: " + S);
+ config->entry = addUndefined(s);
+ log("Entry name inferred: " + s);
}
}
// Handle /delayload
- for (auto *Arg : Args.filtered(OPT_delayload)) {
- Config->DelayLoads.insert(StringRef(Arg->getValue()).lower());
- if (Config->Machine == I386) {
- Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8");
+ for (auto *arg : args.filtered(OPT_delayload)) {
+ config->delayLoads.insert(StringRef(arg->getValue()).lower());
+ if (config->machine == I386) {
+ config->delayLoadHelper = addUndefined("___delayLoadHelper2@8");
} else {
- Config->DelayLoadHelper = addUndefined("__delayLoadHelper2");
+ config->delayLoadHelper = addUndefined("__delayLoadHelper2");
}
}
// Set default image name if neither /out or /def set it.
- if (Config->OutputFile.empty()) {
- Config->OutputFile =
- getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue());
+ if (config->outputFile.empty()) {
+ config->outputFile =
+ getOutputPath((*args.filtered(OPT_INPUT).begin())->getValue());
}
// Fail early if an output file is not writable.
- if (auto E = tryCreateFile(Config->OutputFile)) {
- error("cannot open output file " + Config->OutputFile + ": " + E.message());
+ if (auto e = tryCreateFile(config->outputFile)) {
+ error("cannot open output file " + config->outputFile + ": " + e.message());
return;
}
- if (ShouldCreatePDB) {
+ if (shouldCreatePDB) {
// Put the PDB next to the image if no /pdb flag was passed.
- if (Config->PDBPath.empty()) {
- Config->PDBPath = Config->OutputFile;
- sys::path::replace_extension(Config->PDBPath, ".pdb");
+ if (config->pdbPath.empty()) {
+ config->pdbPath = config->outputFile;
+ sys::path::replace_extension(config->pdbPath, ".pdb");
}
// The embedded PDB path should be the absolute path to the PDB if no
// /pdbaltpath flag was passed.
- if (Config->PDBAltPath.empty()) {
- Config->PDBAltPath = Config->PDBPath;
+ if (config->pdbAltPath.empty()) {
+ config->pdbAltPath = config->pdbPath;
// It's important to make the path absolute and remove dots. This path
// will eventually be written into the PE header, and certain Microsoft
// tools won't work correctly if these assumptions are not held.
- sys::fs::make_absolute(Config->PDBAltPath);
- sys::path::remove_dots(Config->PDBAltPath);
+ sys::fs::make_absolute(config->pdbAltPath);
+ sys::path::remove_dots(config->pdbAltPath);
} else {
// Don't do this earlier, so that Config->OutputFile is ready.
- parsePDBAltPath(Config->PDBAltPath);
+ parsePDBAltPath(config->pdbAltPath);
}
}
// Set default image base if /base is not given.
- if (Config->ImageBase == uint64_t(-1))
- Config->ImageBase = getDefaultImageBase();
-
- Symtab->addSynthetic(mangle("__ImageBase"), nullptr);
- if (Config->Machine == I386) {
- Symtab->addAbsolute("___safe_se_handler_table", 0);
- Symtab->addAbsolute("___safe_se_handler_count", 0);
- }
-
- Symtab->addAbsolute(mangle("__guard_fids_count"), 0);
- Symtab->addAbsolute(mangle("__guard_fids_table"), 0);
- Symtab->addAbsolute(mangle("__guard_flags"), 0);
- Symtab->addAbsolute(mangle("__guard_iat_count"), 0);
- Symtab->addAbsolute(mangle("__guard_iat_table"), 0);
- Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0);
- Symtab->addAbsolute(mangle("__guard_longjmp_table"), 0);
+ if (config->imageBase == uint64_t(-1))
+ config->imageBase = getDefaultImageBase();
+
+ symtab->addSynthetic(mangle("__ImageBase"), nullptr);
+ if (config->machine == I386) {
+ symtab->addAbsolute("___safe_se_handler_table", 0);
+ symtab->addAbsolute("___safe_se_handler_count", 0);
+ }
+
+ symtab->addAbsolute(mangle("__guard_fids_count"), 0);
+ symtab->addAbsolute(mangle("__guard_fids_table"), 0);
+ symtab->addAbsolute(mangle("__guard_flags"), 0);
+ symtab->addAbsolute(mangle("__guard_iat_count"), 0);
+ symtab->addAbsolute(mangle("__guard_iat_table"), 0);
+ symtab->addAbsolute(mangle("__guard_longjmp_count"), 0);
+ symtab->addAbsolute(mangle("__guard_longjmp_table"), 0);
// Needed for MSVC 2017 15.5 CRT.
- Symtab->addAbsolute(mangle("__enclave_config"), 0);
+ symtab->addAbsolute(mangle("__enclave_config"), 0);
- if (Config->MinGW) {
- Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
- Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);
- Symtab->addAbsolute(mangle("__CTOR_LIST__"), 0);
- Symtab->addAbsolute(mangle("__DTOR_LIST__"), 0);
+ if (config->mingw) {
+ symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
+ symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);
+ symtab->addAbsolute(mangle("__CTOR_LIST__"), 0);
+ symtab->addAbsolute(mangle("__DTOR_LIST__"), 0);
}
// This code may add new undefined symbols to the link, which may enqueue more
do {
// Windows specific -- if entry point is not found,
// search for its mangled names.
- if (Config->Entry)
- mangleMaybe(Config->Entry);
+ if (config->entry)
+ mangleMaybe(config->entry);
// Windows specific -- Make sure we resolve all dllexported symbols.
- for (Export &E : Config->Exports) {
- if (!E.ForwardTo.empty())
+ for (Export &e : config->exports) {
+ if (!e.forwardTo.empty())
continue;
- E.Sym = addUndefined(E.Name);
- if (!E.Directives)
- E.SymbolName = mangleMaybe(E.Sym);
+ e.sym = addUndefined(e.name);
+ if (!e.directives)
+ e.symbolName = mangleMaybe(e.sym);
}
// Add weak aliases. Weak aliases is a mechanism to give remaining
// undefined symbols final chance to be resolved successfully.
- for (auto Pair : Config->AlternateNames) {
- StringRef From = Pair.first;
- StringRef To = Pair.second;
- Symbol *Sym = Symtab->find(From);
- if (!Sym)
+ for (auto pair : config->alternateNames) {
+ StringRef from = pair.first;
+ StringRef to = pair.second;
+ Symbol *sym = symtab->find(from);
+ if (!sym)
continue;
- if (auto *U = dyn_cast<Undefined>(Sym))
- if (!U->WeakAlias)
- U->WeakAlias = Symtab->addUndefined(To);
+ if (auto *u = dyn_cast<Undefined>(sym))
+ if (!u->weakAlias)
+ u->weakAlias = symtab->addUndefined(to);
}
// Windows specific -- if __load_config_used can be resolved, resolve it.
- if (Symtab->findUnderscore("_load_config_used"))
+ if (symtab->findUnderscore("_load_config_used"))
addUndefined(mangle("_load_config_used"));
} while (run());
// Do LTO by compiling bitcode input files to a set of native COFF files then
// link those files.
- Symtab->addCombinedLTOObjects();
+ symtab->addCombinedLTOObjects();
run();
- if (Args.hasArg(OPT_include_optional)) {
+ if (args.hasArg(OPT_include_optional)) {
// Handle /includeoptional
- for (auto *Arg : Args.filtered(OPT_include_optional))
- if (dyn_cast_or_null<Lazy>(Symtab->find(Arg->getValue())))
- addUndefined(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_include_optional))
+ if (dyn_cast_or_null<Lazy>(symtab->find(arg->getValue())))
+ addUndefined(arg->getValue());
while (run());
}
- if (Config->MinGW) {
+ if (config->mingw) {
// Load any further object files that might be needed for doing automatic
// imports.
//
// normal object file as well (although that won't be used for the
// actual autoimport later on). If this pass adds new undefined references,
// we won't iterate further to resolve them.
- Symtab->loadMinGWAutomaticImports();
+ symtab->loadMinGWAutomaticImports();
run();
}
// Make sure we have resolved all symbols.
- Symtab->reportRemainingUndefines();
+ symtab->reportRemainingUndefines();
if (errorCount())
return;
// Handle /safeseh.
- if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) {
- for (ObjFile *File : ObjFile::Instances)
- if (!File->hasSafeSEH())
- error("/safeseh: " + File->getName() + " is not compatible with SEH");
+ if (args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) {
+ for (ObjFile *file : ObjFile::instances)
+ if (!file->hasSafeSEH())
+ error("/safeseh: " + file->getName() + " is not compatible with SEH");
if (errorCount())
return;
}
- if (Config->MinGW) {
+ if (config->mingw) {
// In MinGW, all symbols are automatically exported if no symbols
// are chosen to be exported.
- maybeExportMinGWSymbols(Args);
+ maybeExportMinGWSymbols(args);
// Make sure the crtend.o object is the last object file. This object
// file can contain terminating section chunks that need to be placed
// order provided on the command line, while lld will pull in needed
// files from static libraries only after the last object file on the
// command line.
- for (auto I = ObjFile::Instances.begin(), E = ObjFile::Instances.end();
- I != E; I++) {
- ObjFile *File = *I;
- if (isCrtend(File->getName())) {
- ObjFile::Instances.erase(I);
- ObjFile::Instances.push_back(File);
+ for (auto i = ObjFile::instances.begin(), e = ObjFile::instances.end();
+ i != e; i++) {
+ ObjFile *file = *i;
+ if (isCrtend(file->getName())) {
+ ObjFile::instances.erase(i);
+ ObjFile::instances.push_back(file);
break;
}
}
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file.
- if (!Config->Exports.empty() || Config->DLL) {
+ if (!config->exports.empty() || config->dll) {
fixupExports();
createImportLibrary(/*AsLib=*/false);
assignExportOrdinals();
}
// Handle /output-def (MinGW specific).
- if (auto *Arg = Args.getLastArg(OPT_output_def))
- writeDefFile(Arg->getValue());
+ if (auto *arg = args.getLastArg(OPT_output_def))
+ writeDefFile(arg->getValue());
// Set extra alignment for .comm symbols
- for (auto Pair : Config->AlignComm) {
- StringRef Name = Pair.first;
- uint32_t Alignment = Pair.second;
+ for (auto pair : config->alignComm) {
+ StringRef name = pair.first;
+ uint32_t alignment = pair.second;
- Symbol *Sym = Symtab->find(Name);
- if (!Sym) {
- warn("/aligncomm symbol " + Name + " not found");
+ Symbol *sym = symtab->find(name);
+ if (!sym) {
+ warn("/aligncomm symbol " + name + " not found");
continue;
}
// If the symbol isn't common, it must have been replaced with a regular
// symbol, which will carry its own alignment.
- auto *DC = dyn_cast<DefinedCommon>(Sym);
- if (!DC)
+ auto *dc = dyn_cast<DefinedCommon>(sym);
+ if (!dc)
continue;
- CommonChunk *C = DC->getChunk();
- C->setAlignment(std::max(C->getAlignment(), Alignment));
+ CommonChunk *c = dc->getChunk();
+ c->setAlignment(std::max(c->getAlignment(), alignment));
}
// Windows specific -- Create a side-by-side manifest file.
- if (Config->Manifest == Configuration::SideBySide)
+ if (config->manifest == Configuration::SideBySide)
createSideBySideManifest();
// Handle /order. We want to do this at this moment because we
// need a complete list of comdat sections to warn on nonexistent
// functions.
- if (auto *Arg = Args.getLastArg(OPT_order))
- parseOrderFile(Arg->getValue());
+ if (auto *arg = args.getLastArg(OPT_order))
+ parseOrderFile(arg->getValue());
// Identify unreferenced COMDAT sections.
- if (Config->DoGC)
- markLive(Symtab->getChunks());
+ if (config->doGC)
+ markLive(symtab->getChunks());
// Needs to happen after the last call to addFile().
diagnoseMultipleResourceObjFiles();
// Identify identical COMDAT sections to merge them.
- if (Config->DoICF) {
+ if (config->doICF) {
findKeepUniqueSections();
- doICF(Symtab->getChunks());
+ doICF(symtab->getChunks());
}
// Write the result.
// Stop early so we can print the results.
Timer::root().stop();
- if (Config->ShowTiming)
+ if (config->showTiming)
Timer::root().print();
}
namespace coff {
class LinkerDriver;
-extern LinkerDriver *Driver;
+extern LinkerDriver *driver;
using llvm::COFF::MachineTypes;
using llvm::COFF::WindowsSubsystem;
class ArgParser {
public:
// Concatenate LINK environment variable and given arguments and parse them.
- llvm::opt::InputArgList parseLINK(std::vector<const char *> Args);
+ llvm::opt::InputArgList parseLINK(std::vector<const char *> args);
// Tokenizes a given string and then parses as command line options.
- llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
+ llvm::opt::InputArgList parse(StringRef s) { return parse(tokenize(s)); }
// Tokenizes a given string and then parses as command line options in
// .drectve section. /EXPORT options are returned in second element
// to be processed in fastpath.
std::pair<llvm::opt::InputArgList, std::vector<StringRef>>
- parseDirectives(StringRef S);
+ parseDirectives(StringRef s);
private:
// Parses command line options.
- llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args);
+ llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> args);
- std::vector<const char *> tokenize(StringRef S);
+ std::vector<const char *> tokenize(StringRef s);
- COFFOptTable Table;
+ COFFOptTable table;
};
class LinkerDriver {
public:
- void link(llvm::ArrayRef<const char *> Args);
+ void link(llvm::ArrayRef<const char *> args);
// Used by the resolver to parse .drectve section contents.
- void parseDirectives(InputFile *File);
+ void parseDirectives(InputFile *file);
// Used by ArchiveFile to enqueue members.
- void enqueueArchiveMember(const Archive::Child &C, StringRef SymName,
- StringRef ParentName);
+ void enqueueArchiveMember(const Archive::Child &c, StringRef symName,
+ StringRef parentName);
- MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB);
+ MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
- void enqueuePath(StringRef Path, bool WholeArchive);
+ void enqueuePath(StringRef path, bool wholeArchive);
private:
- std::unique_ptr<llvm::TarWriter> Tar; // for /linkrepro
+ std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro
// Opens a file. Path has to be resolved already.
- MemoryBufferRef openFile(StringRef Path);
+ MemoryBufferRef openFile(StringRef path);
// Searches a file from search paths.
- Optional<StringRef> findFile(StringRef Filename);
- Optional<StringRef> findLib(StringRef Filename);
- StringRef doFindFile(StringRef Filename);
- StringRef doFindLib(StringRef Filename);
- StringRef doFindLibMinGW(StringRef Filename);
+ Optional<StringRef> findFile(StringRef filename);
+ Optional<StringRef> findLib(StringRef filename);
+ StringRef doFindFile(StringRef filename);
+ StringRef doFindLib(StringRef filename);
+ StringRef doFindLibMinGW(StringRef filename);
// Parses LIB environment which contains a list of search paths.
void addLibSearchPaths();
// Library search path. The first element is always "" (current directory).
- std::vector<StringRef> SearchPaths;
+ std::vector<StringRef> searchPaths;
- void maybeExportMinGWSymbols(const llvm::opt::InputArgList &Args);
+ void maybeExportMinGWSymbols(const llvm::opt::InputArgList &args);
// We don't want to add the same file more than once.
// Files are uniquified by their filesystem and file number.
- std::set<llvm::sys::fs::UniqueID> VisitedFiles;
+ std::set<llvm::sys::fs::UniqueID> visitedFiles;
- std::set<std::string> VisitedLibs;
+ std::set<std::string> visitedLibs;
- Symbol *addUndefined(StringRef Sym);
+ Symbol *addUndefined(StringRef sym);
- StringRef mangleMaybe(Symbol *S);
+ StringRef mangleMaybe(Symbol *s);
// Windows specific -- "main" is not the only main function in Windows.
// You can choose one from these four -- {w,}{WinMain,main}.
StringRef findDefaultEntry();
WindowsSubsystem inferSubsystem();
- void addBuffer(std::unique_ptr<MemoryBuffer> MB, bool WholeArchive);
- void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
- StringRef ParentName, uint64_t OffsetInArchive);
+ void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive);
+ void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,
+ StringRef parentName, uint64_t offsetInArchive);
- void enqueueTask(std::function<void()> Task);
+ void enqueueTask(std::function<void()> task);
bool run();
- std::list<std::function<void()>> TaskQueue;
- std::vector<StringRef> FilePaths;
- std::vector<MemoryBufferRef> Resources;
+ std::list<std::function<void()>> taskQueue;
+ std::vector<StringRef> filePaths;
+ std::vector<MemoryBufferRef> resources;
- llvm::StringSet<> DirectivesExports;
+ llvm::StringSet<> directivesExports;
};
// Functions below this line are defined in DriverUtils.cpp.
-void printHelp(const char *Argv0);
+void printHelp(const char *argv0);
// Parses a string in the form of "<integer>[,<integer>]".
-void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
+void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size = nullptr);
-void parseGuard(StringRef Arg);
+void parseGuard(StringRef arg);
// Parses a string in the form of "<integer>[.<integer>]".
// Minor's default value is 0.
-void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
+void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor);
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
-void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
- uint32_t *Minor);
+void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major,
+ uint32_t *minor);
void parseAlternateName(StringRef);
void parseMerge(StringRef);
void parseAligncomm(StringRef);
// Parses a string in the form of "[:<integer>]"
-void parseFunctionPadMin(llvm::opt::Arg *A, llvm::COFF::MachineTypes Machine);
+void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine);
// Parses a string in the form of "EMBED[,=<integer>]|NO".
-void parseManifest(StringRef Arg);
+void parseManifest(StringRef arg);
// Parses a string in the form of "level=<string>|uiAccess=<string>"
-void parseManifestUAC(StringRef Arg);
+void parseManifestUAC(StringRef arg);
// Parses a string in the form of "cd|net[,(cd|net)]*"
-void parseSwaprun(StringRef Arg);
+void parseSwaprun(StringRef arg);
// Create a resource file containing a manifest XML.
std::unique_ptr<MemoryBuffer> createManifestRes();
void createSideBySideManifest();
// Used for dllexported symbols.
-Export parseExport(StringRef Arg);
+Export parseExport(StringRef arg);
void fixupExports();
void assignExportOrdinals();
// if value matches previous values for the key.
// This feature used in the directive section to reject
// incompatible objects.
-void checkFailIfMismatch(StringRef Arg, InputFile *Source);
+void checkFailIfMismatch(StringRef arg, InputFile *source);
// Convert Windows resource files (.res files) to a .obj file.
-MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs);
+MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs);
-void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects);
+void runMSVCLinker(std::string rsp, ArrayRef<StringRef> objects);
// Create enum with OPT_xxx values for each option in Options.td
enum {
class Executor {
public:
- explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
- void add(StringRef S) { Args.push_back(Saver.save(S)); }
- void add(std::string &S) { Args.push_back(Saver.save(S)); }
- void add(Twine S) { Args.push_back(Saver.save(S)); }
- void add(const char *S) { Args.push_back(Saver.save(S)); }
+ explicit Executor(StringRef s) : prog(saver.save(s)) {}
+ void add(StringRef s) { args.push_back(saver.save(s)); }
+ void add(std::string &s) { args.push_back(saver.save(s)); }
+ void add(Twine s) { args.push_back(saver.save(s)); }
+ void add(const char *s) { args.push_back(saver.save(s)); }
void run() {
- ErrorOr<std::string> ExeOrErr = sys::findProgramByName(Prog);
- if (auto EC = ExeOrErr.getError())
- fatal("unable to find " + Prog + " in PATH: " + EC.message());
- StringRef Exe = Saver.save(*ExeOrErr);
- Args.insert(Args.begin(), Exe);
+ ErrorOr<std::string> exeOrErr = sys::findProgramByName(prog);
+ if (auto ec = exeOrErr.getError())
+ fatal("unable to find " + prog + " in PATH: " + ec.message());
+ StringRef exe = saver.save(*exeOrErr);
+ args.insert(args.begin(), exe);
- if (sys::ExecuteAndWait(Args[0], Args) != 0)
+ if (sys::ExecuteAndWait(args[0], args) != 0)
fatal("ExecuteAndWait failed: " +
- llvm::join(Args.begin(), Args.end(), " "));
+ llvm::join(args.begin(), args.end(), " "));
}
private:
- StringRef Prog;
- std::vector<StringRef> Args;
+ StringRef prog;
+ std::vector<StringRef> args;
};
} // anonymous namespace
// Parses a string in the form of "<integer>[,<integer>]".
-void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) {
- StringRef S1, S2;
- std::tie(S1, S2) = Arg.split(',');
- if (S1.getAsInteger(0, *Addr))
- fatal("invalid number: " + S1);
- if (Size && !S2.empty() && S2.getAsInteger(0, *Size))
- fatal("invalid number: " + S2);
+void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) {
+ StringRef s1, s2;
+ std::tie(s1, s2) = arg.split(',');
+ if (s1.getAsInteger(0, *addr))
+ fatal("invalid number: " + s1);
+ if (size && !s2.empty() && s2.getAsInteger(0, *size))
+ fatal("invalid number: " + s2);
}
// Parses a string in the form of "<integer>[.<integer>]".
// If second number is not present, Minor is set to 0.
-void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
- StringRef S1, S2;
- std::tie(S1, S2) = Arg.split('.');
- if (S1.getAsInteger(0, *Major))
- fatal("invalid number: " + S1);
- *Minor = 0;
- if (!S2.empty() && S2.getAsInteger(0, *Minor))
- fatal("invalid number: " + S2);
-}
-
-void parseGuard(StringRef FullArg) {
- SmallVector<StringRef, 1> SplitArgs;
- FullArg.split(SplitArgs, ",");
- for (StringRef Arg : SplitArgs) {
- if (Arg.equals_lower("no"))
- Config->GuardCF = GuardCFLevel::Off;
- else if (Arg.equals_lower("nolongjmp"))
- Config->GuardCF = GuardCFLevel::NoLongJmp;
- else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp"))
- Config->GuardCF = GuardCFLevel::Full;
+void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor) {
+ StringRef s1, s2;
+ std::tie(s1, s2) = arg.split('.');
+ if (s1.getAsInteger(0, *major))
+ fatal("invalid number: " + s1);
+ *minor = 0;
+ if (!s2.empty() && s2.getAsInteger(0, *minor))
+ fatal("invalid number: " + s2);
+}
+
+void parseGuard(StringRef fullArg) {
+ SmallVector<StringRef, 1> splitArgs;
+ fullArg.split(splitArgs, ",");
+ for (StringRef arg : splitArgs) {
+ if (arg.equals_lower("no"))
+ config->guardCF = GuardCFLevel::Off;
+ else if (arg.equals_lower("nolongjmp"))
+ config->guardCF = GuardCFLevel::NoLongJmp;
+ else if (arg.equals_lower("cf") || arg.equals_lower("longjmp"))
+ config->guardCF = GuardCFLevel::Full;
else
- fatal("invalid argument to /guard: " + Arg);
+ fatal("invalid argument to /guard: " + arg);
}
}
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
-void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
- uint32_t *Minor) {
- StringRef SysStr, Ver;
- std::tie(SysStr, Ver) = Arg.split(',');
- std::string SysStrLower = SysStr.lower();
- *Sys = StringSwitch<WindowsSubsystem>(SysStrLower)
+void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major,
+ uint32_t *minor) {
+ StringRef sysStr, ver;
+ std::tie(sysStr, ver) = arg.split(',');
+ std::string sysStrLower = sysStr.lower();
+ *sys = StringSwitch<WindowsSubsystem>(sysStrLower)
.Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
.Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)
.Case("default", IMAGE_SUBSYSTEM_UNKNOWN)
.Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
.Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
.Default(IMAGE_SUBSYSTEM_UNKNOWN);
- if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN && SysStrLower != "default")
- fatal("unknown subsystem: " + SysStr);
- if (!Ver.empty())
- parseVersion(Ver, Major, Minor);
+ if (*sys == IMAGE_SUBSYSTEM_UNKNOWN && sysStrLower != "default")
+ fatal("unknown subsystem: " + sysStr);
+ if (!ver.empty())
+ parseVersion(ver, major, minor);
}
// Parse a string of the form of "<from>=<to>".
// Results are directly written to Config.
-void parseAlternateName(StringRef S) {
- StringRef From, To;
- std::tie(From, To) = S.split('=');
- if (From.empty() || To.empty())
- fatal("/alternatename: invalid argument: " + S);
- auto It = Config->AlternateNames.find(From);
- if (It != Config->AlternateNames.end() && It->second != To)
- fatal("/alternatename: conflicts: " + S);
- Config->AlternateNames.insert(It, std::make_pair(From, To));
+void parseAlternateName(StringRef s) {
+ StringRef from, to;
+ std::tie(from, to) = s.split('=');
+ if (from.empty() || to.empty())
+ fatal("/alternatename: invalid argument: " + s);
+ auto it = config->alternateNames.find(from);
+ if (it != config->alternateNames.end() && it->second != to)
+ fatal("/alternatename: conflicts: " + s);
+ config->alternateNames.insert(it, std::make_pair(from, to));
}
// Parse a string of the form of "<from>=<to>".
// Results are directly written to Config.
-void parseMerge(StringRef S) {
- StringRef From, To;
- std::tie(From, To) = S.split('=');
- if (From.empty() || To.empty())
- fatal("/merge: invalid argument: " + S);
- if (From == ".rsrc" || To == ".rsrc")
+void parseMerge(StringRef s) {
+ StringRef from, to;
+ std::tie(from, to) = s.split('=');
+ if (from.empty() || to.empty())
+ fatal("/merge: invalid argument: " + s);
+ if (from == ".rsrc" || to == ".rsrc")
fatal("/merge: cannot merge '.rsrc' with any section");
- if (From == ".reloc" || To == ".reloc")
+ if (from == ".reloc" || to == ".reloc")
fatal("/merge: cannot merge '.reloc' with any section");
- auto Pair = Config->Merge.insert(std::make_pair(From, To));
- bool Inserted = Pair.second;
- if (!Inserted) {
- StringRef Existing = Pair.first->second;
- if (Existing != To)
- warn(S + ": already merged into " + Existing);
+ auto pair = config->merge.insert(std::make_pair(from, to));
+ bool inserted = pair.second;
+ if (!inserted) {
+ StringRef existing = pair.first->second;
+ if (existing != to)
+ warn(s + ": already merged into " + existing);
}
}
-static uint32_t parseSectionAttributes(StringRef S) {
- uint32_t Ret = 0;
- for (char C : S.lower()) {
- switch (C) {
+static uint32_t parseSectionAttributes(StringRef s) {
+ uint32_t ret = 0;
+ for (char c : s.lower()) {
+ switch (c) {
case 'd':
- Ret |= IMAGE_SCN_MEM_DISCARDABLE;
+ ret |= IMAGE_SCN_MEM_DISCARDABLE;
break;
case 'e':
- Ret |= IMAGE_SCN_MEM_EXECUTE;
+ ret |= IMAGE_SCN_MEM_EXECUTE;
break;
case 'k':
- Ret |= IMAGE_SCN_MEM_NOT_CACHED;
+ ret |= IMAGE_SCN_MEM_NOT_CACHED;
break;
case 'p':
- Ret |= IMAGE_SCN_MEM_NOT_PAGED;
+ ret |= IMAGE_SCN_MEM_NOT_PAGED;
break;
case 'r':
- Ret |= IMAGE_SCN_MEM_READ;
+ ret |= IMAGE_SCN_MEM_READ;
break;
case 's':
- Ret |= IMAGE_SCN_MEM_SHARED;
+ ret |= IMAGE_SCN_MEM_SHARED;
break;
case 'w':
- Ret |= IMAGE_SCN_MEM_WRITE;
+ ret |= IMAGE_SCN_MEM_WRITE;
break;
default:
- fatal("/section: invalid argument: " + S);
+ fatal("/section: invalid argument: " + s);
}
}
- return Ret;
+ return ret;
}
// Parses /section option argument.
-void parseSection(StringRef S) {
- StringRef Name, Attrs;
- std::tie(Name, Attrs) = S.split(',');
- if (Name.empty() || Attrs.empty())
- fatal("/section: invalid argument: " + S);
- Config->Section[Name] = parseSectionAttributes(Attrs);
+void parseSection(StringRef s) {
+ StringRef name, attrs;
+ std::tie(name, attrs) = s.split(',');
+ if (name.empty() || attrs.empty())
+ fatal("/section: invalid argument: " + s);
+ config->section[name] = parseSectionAttributes(attrs);
}
// Parses /aligncomm option argument.
-void parseAligncomm(StringRef S) {
- StringRef Name, Align;
- std::tie(Name, Align) = S.split(',');
- if (Name.empty() || Align.empty()) {
- error("/aligncomm: invalid argument: " + S);
+void parseAligncomm(StringRef s) {
+ StringRef name, align;
+ std::tie(name, align) = s.split(',');
+ if (name.empty() || align.empty()) {
+ error("/aligncomm: invalid argument: " + s);
return;
}
- int V;
- if (Align.getAsInteger(0, V)) {
- error("/aligncomm: invalid argument: " + S);
+ int v;
+ if (align.getAsInteger(0, v)) {
+ error("/aligncomm: invalid argument: " + s);
return;
}
- Config->AlignComm[Name] = std::max(Config->AlignComm[Name], 1 << V);
+ config->alignComm[name] = std::max(config->alignComm[name], 1 << v);
}
// Parses /functionpadmin option argument.
-void parseFunctionPadMin(llvm::opt::Arg *A, llvm::COFF::MachineTypes Machine) {
- StringRef Arg = A->getNumValues() ? A->getValue() : "";
- if (!Arg.empty()) {
+void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine) {
+ StringRef arg = a->getNumValues() ? a->getValue() : "";
+ if (!arg.empty()) {
// Optional padding in bytes is given.
- if (Arg.getAsInteger(0, Config->FunctionPadMin))
- error("/functionpadmin: invalid argument: " + Arg);
+ if (arg.getAsInteger(0, config->functionPadMin))
+ error("/functionpadmin: invalid argument: " + arg);
return;
}
// No optional argument given.
// Set default padding based on machine, similar to link.exe.
// There is no default padding for ARM platforms.
- if (Machine == I386) {
- Config->FunctionPadMin = 5;
- } else if (Machine == AMD64) {
- Config->FunctionPadMin = 6;
+ if (machine == I386) {
+ config->functionPadMin = 5;
+ } else if (machine == AMD64) {
+ config->functionPadMin = 6;
} else {
- error("/functionpadmin: invalid argument for this machine: " + Arg);
+ error("/functionpadmin: invalid argument for this machine: " + arg);
}
}
// Parses a string in the form of "EMBED[,=<integer>]|NO".
// Results are directly written to Config.
-void parseManifest(StringRef Arg) {
- if (Arg.equals_lower("no")) {
- Config->Manifest = Configuration::No;
+void parseManifest(StringRef arg) {
+ if (arg.equals_lower("no")) {
+ config->manifest = Configuration::No;
return;
}
- if (!Arg.startswith_lower("embed"))
- fatal("invalid option " + Arg);
- Config->Manifest = Configuration::Embed;
- Arg = Arg.substr(strlen("embed"));
- if (Arg.empty())
+ if (!arg.startswith_lower("embed"))
+ fatal("invalid option " + arg);
+ config->manifest = Configuration::Embed;
+ arg = arg.substr(strlen("embed"));
+ if (arg.empty())
return;
- if (!Arg.startswith_lower(",id="))
- fatal("invalid option " + Arg);
- Arg = Arg.substr(strlen(",id="));
- if (Arg.getAsInteger(0, Config->ManifestID))
- fatal("invalid option " + Arg);
+ if (!arg.startswith_lower(",id="))
+ fatal("invalid option " + arg);
+ arg = arg.substr(strlen(",id="));
+ if (arg.getAsInteger(0, config->manifestID))
+ fatal("invalid option " + arg);
}
// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
// Results are directly written to Config.
-void parseManifestUAC(StringRef Arg) {
- if (Arg.equals_lower("no")) {
- Config->ManifestUAC = false;
+void parseManifestUAC(StringRef arg) {
+ if (arg.equals_lower("no")) {
+ config->manifestUAC = false;
return;
}
for (;;) {
- Arg = Arg.ltrim();
- if (Arg.empty())
+ arg = arg.ltrim();
+ if (arg.empty())
return;
- if (Arg.startswith_lower("level=")) {
- Arg = Arg.substr(strlen("level="));
- std::tie(Config->ManifestLevel, Arg) = Arg.split(" ");
+ if (arg.startswith_lower("level=")) {
+ arg = arg.substr(strlen("level="));
+ std::tie(config->manifestLevel, arg) = arg.split(" ");
continue;
}
- if (Arg.startswith_lower("uiaccess=")) {
- Arg = Arg.substr(strlen("uiaccess="));
- std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" ");
+ if (arg.startswith_lower("uiaccess=")) {
+ arg = arg.substr(strlen("uiaccess="));
+ std::tie(config->manifestUIAccess, arg) = arg.split(" ");
continue;
}
- fatal("invalid option " + Arg);
+ fatal("invalid option " + arg);
}
}
// Parses a string in the form of "cd|net[,(cd|net)]*"
// Results are directly written to Config.
-void parseSwaprun(StringRef Arg) {
+void parseSwaprun(StringRef arg) {
do {
- StringRef Swaprun, NewArg;
- std::tie(Swaprun, NewArg) = Arg.split(',');
- if (Swaprun.equals_lower("cd"))
- Config->SwaprunCD = true;
- else if (Swaprun.equals_lower("net"))
- Config->SwaprunNet = true;
- else if (Swaprun.empty())
+ StringRef swaprun, newArg;
+ std::tie(swaprun, newArg) = arg.split(',');
+ if (swaprun.equals_lower("cd"))
+ config->swaprunCD = true;
+ else if (swaprun.equals_lower("net"))
+ config->swaprunNet = true;
+ else if (swaprun.empty())
error("/swaprun: missing argument");
else
- error("/swaprun: invalid argument: " + Swaprun);
+ error("/swaprun: invalid argument: " + swaprun);
// To catch trailing commas, e.g. `/spawrun:cd,`
- if (NewArg.empty() && Arg.endswith(","))
+ if (newArg.empty() && arg.endswith(","))
error("/swaprun: missing argument");
- Arg = NewArg;
- } while (!Arg.empty());
+ arg = newArg;
+ } while (!arg.empty());
}
// An RAII temporary file class that automatically removes a temporary file.
namespace {
class TemporaryFile {
public:
- TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") {
- SmallString<128> S;
- if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S))
- fatal("cannot create a temporary file: " + EC.message());
- Path = S.str();
-
- if (!Contents.empty()) {
- std::error_code EC;
- raw_fd_ostream OS(Path, EC, sys::fs::F_None);
- if (EC)
- fatal("failed to open " + Path + ": " + EC.message());
- OS << Contents;
+ TemporaryFile(StringRef prefix, StringRef extn, StringRef contents = "") {
+ SmallString<128> s;
+ if (auto ec = sys::fs::createTemporaryFile("lld-" + prefix, extn, s))
+ fatal("cannot create a temporary file: " + ec.message());
+ path = s.str();
+
+ if (!contents.empty()) {
+ std::error_code ec;
+ raw_fd_ostream os(path, ec, sys::fs::F_None);
+ if (ec)
+ fatal("failed to open " + path + ": " + ec.message());
+ os << contents;
}
}
- TemporaryFile(TemporaryFile &&Obj) {
- std::swap(Path, Obj.Path);
+ TemporaryFile(TemporaryFile &&obj) {
+ std::swap(path, obj.path);
}
~TemporaryFile() {
- if (Path.empty())
+ if (path.empty())
return;
- if (sys::fs::remove(Path))
- fatal("failed to remove " + Path);
+ if (sys::fs::remove(path))
+ fatal("failed to remove " + path);
}
// Returns a memory buffer of this temporary file.
// is called (you cannot remove an opened file on Windows.)
std::unique_ptr<MemoryBuffer> getMemoryBuffer() {
// IsVolatileSize=true forces MemoryBuffer to not use mmap().
- return CHECK(MemoryBuffer::getFile(Path, /*FileSize=*/-1,
+ return CHECK(MemoryBuffer::getFile(path, /*FileSize=*/-1,
/*RequiresNullTerminator=*/false,
/*IsVolatileSize=*/true),
- "could not open " + Path);
+ "could not open " + path);
}
- std::string Path;
+ std::string path;
};
}
static std::string createDefaultXml() {
- std::string Ret;
- raw_string_ostream OS(Ret);
+ std::string ret;
+ raw_string_ostream os(ret);
// Emit the XML. Note that we do *not* verify that the XML attributes are
// syntactically correct. This is intentional for link.exe compatibility.
- OS << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
+ os << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
<< "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
<< " manifestVersion=\"1.0\">\n";
- if (Config->ManifestUAC) {
- OS << " <trustInfo>\n"
+ if (config->manifestUAC) {
+ os << " <trustInfo>\n"
<< " <security>\n"
<< " <requestedPrivileges>\n"
- << " <requestedExecutionLevel level=" << Config->ManifestLevel
- << " uiAccess=" << Config->ManifestUIAccess << "/>\n"
+ << " <requestedExecutionLevel level=" << config->manifestLevel
+ << " uiAccess=" << config->manifestUIAccess << "/>\n"
<< " </requestedPrivileges>\n"
<< " </security>\n"
<< " </trustInfo>\n";
}
- if (!Config->ManifestDependency.empty()) {
- OS << " <dependency>\n"
+ if (!config->manifestDependency.empty()) {
+ os << " <dependency>\n"
<< " <dependentAssembly>\n"
- << " <assemblyIdentity " << Config->ManifestDependency << " />\n"
+ << " <assemblyIdentity " << config->manifestDependency << " />\n"
<< " </dependentAssembly>\n"
<< " </dependency>\n";
}
- OS << "</assembly>\n";
- return OS.str();
+ os << "</assembly>\n";
+ return os.str();
}
-static std::string createManifestXmlWithInternalMt(StringRef DefaultXml) {
- std::unique_ptr<MemoryBuffer> DefaultXmlCopy =
- MemoryBuffer::getMemBufferCopy(DefaultXml);
+static std::string createManifestXmlWithInternalMt(StringRef defaultXml) {
+ std::unique_ptr<MemoryBuffer> defaultXmlCopy =
+ MemoryBuffer::getMemBufferCopy(defaultXml);
- windows_manifest::WindowsManifestMerger Merger;
- if (auto E = Merger.merge(*DefaultXmlCopy.get()))
+ windows_manifest::WindowsManifestMerger merger;
+ if (auto e = merger.merge(*defaultXmlCopy.get()))
fatal("internal manifest tool failed on default xml: " +
- toString(std::move(E)));
+ toString(std::move(e)));
- for (StringRef Filename : Config->ManifestInput) {
- std::unique_ptr<MemoryBuffer> Manifest =
- check(MemoryBuffer::getFile(Filename));
- if (auto E = Merger.merge(*Manifest.get()))
- fatal("internal manifest tool failed on file " + Filename + ": " +
- toString(std::move(E)));
+ for (StringRef filename : config->manifestInput) {
+ std::unique_ptr<MemoryBuffer> manifest =
+ check(MemoryBuffer::getFile(filename));
+ if (auto e = merger.merge(*manifest.get()))
+ fatal("internal manifest tool failed on file " + filename + ": " +
+ toString(std::move(e)));
}
- return Merger.getMergedManifest().get()->getBuffer();
+ return merger.getMergedManifest().get()->getBuffer();
}
-static std::string createManifestXmlWithExternalMt(StringRef DefaultXml) {
+static std::string createManifestXmlWithExternalMt(StringRef defaultXml) {
// Create the default manifest file as a temporary file.
TemporaryFile Default("defaultxml", "manifest");
- std::error_code EC;
- raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text);
- if (EC)
- fatal("failed to open " + Default.Path + ": " + EC.message());
- OS << DefaultXml;
- OS.close();
+ std::error_code ec;
+ raw_fd_ostream os(Default.path, ec, sys::fs::F_Text);
+ if (ec)
+ fatal("failed to open " + Default.path + ": " + ec.message());
+ os << defaultXml;
+ os.close();
// Merge user-supplied manifests if they are given. Since libxml2 is not
// enabled, we must shell out to Microsoft's mt.exe tool.
- TemporaryFile User("user", "manifest");
+ TemporaryFile user("user", "manifest");
- Executor E("mt.exe");
- E.add("/manifest");
- E.add(Default.Path);
- for (StringRef Filename : Config->ManifestInput) {
- E.add("/manifest");
- E.add(Filename);
+ Executor e("mt.exe");
+ e.add("/manifest");
+ e.add(Default.path);
+ for (StringRef filename : config->manifestInput) {
+ e.add("/manifest");
+ e.add(filename);
}
- E.add("/nologo");
- E.add("/out:" + StringRef(User.Path));
- E.run();
+ e.add("/nologo");
+ e.add("/out:" + StringRef(user.path));
+ e.run();
- return CHECK(MemoryBuffer::getFile(User.Path), "could not open " + User.Path)
+ return CHECK(MemoryBuffer::getFile(user.path), "could not open " + user.path)
.get()
->getBuffer();
}
static std::string createManifestXml() {
- std::string DefaultXml = createDefaultXml();
- if (Config->ManifestInput.empty())
- return DefaultXml;
+ std::string defaultXml = createDefaultXml();
+ if (config->manifestInput.empty())
+ return defaultXml;
if (windows_manifest::isAvailable())
- return createManifestXmlWithInternalMt(DefaultXml);
+ return createManifestXmlWithInternalMt(defaultXml);
- return createManifestXmlWithExternalMt(DefaultXml);
+ return createManifestXmlWithExternalMt(defaultXml);
}
static std::unique_ptr<WritableMemoryBuffer>
-createMemoryBufferForManifestRes(size_t ManifestSize) {
- size_t ResSize = alignTo(
+createMemoryBufferForManifestRes(size_t manifestSize) {
+ size_t resSize = alignTo(
object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE +
sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) +
- sizeof(object::WinResHeaderSuffix) + ManifestSize,
+ sizeof(object::WinResHeaderSuffix) + manifestSize,
object::WIN_RES_DATA_ALIGNMENT);
- return WritableMemoryBuffer::getNewMemBuffer(ResSize, Config->OutputFile +
+ return WritableMemoryBuffer::getNewMemBuffer(resSize, config->outputFile +
".manifest.res");
}
-static void writeResFileHeader(char *&Buf) {
- memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));
- Buf += sizeof(COFF::WinResMagic);
- memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);
- Buf += object::WIN_RES_NULL_ENTRY_SIZE;
+static void writeResFileHeader(char *&buf) {
+ memcpy(buf, COFF::WinResMagic, sizeof(COFF::WinResMagic));
+ buf += sizeof(COFF::WinResMagic);
+ memset(buf, 0, object::WIN_RES_NULL_ENTRY_SIZE);
+ buf += object::WIN_RES_NULL_ENTRY_SIZE;
}
-static void writeResEntryHeader(char *&Buf, size_t ManifestSize) {
+static void writeResEntryHeader(char *&buf, size_t manifestSize) {
// Write the prefix.
- auto *Prefix = reinterpret_cast<object::WinResHeaderPrefix *>(Buf);
- Prefix->DataSize = ManifestSize;
- Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
+ auto *prefix = reinterpret_cast<object::WinResHeaderPrefix *>(buf);
+ prefix->DataSize = manifestSize;
+ prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) +
sizeof(object::WinResIDs) +
sizeof(object::WinResHeaderSuffix);
- Buf += sizeof(object::WinResHeaderPrefix);
+ buf += sizeof(object::WinResHeaderPrefix);
// Write the Type/Name IDs.
- auto *IDs = reinterpret_cast<object::WinResIDs *>(Buf);
- IDs->setType(RT_MANIFEST);
- IDs->setName(Config->ManifestID);
- Buf += sizeof(object::WinResIDs);
+ auto *iDs = reinterpret_cast<object::WinResIDs *>(buf);
+ iDs->setType(RT_MANIFEST);
+ iDs->setName(config->manifestID);
+ buf += sizeof(object::WinResIDs);
// Write the suffix.
- auto *Suffix = reinterpret_cast<object::WinResHeaderSuffix *>(Buf);
- Suffix->DataVersion = 0;
- Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
- Suffix->Language = SUBLANG_ENGLISH_US;
- Suffix->Version = 0;
- Suffix->Characteristics = 0;
- Buf += sizeof(object::WinResHeaderSuffix);
+ auto *suffix = reinterpret_cast<object::WinResHeaderSuffix *>(buf);
+ suffix->DataVersion = 0;
+ suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE;
+ suffix->Language = SUBLANG_ENGLISH_US;
+ suffix->Version = 0;
+ suffix->Characteristics = 0;
+ buf += sizeof(object::WinResHeaderSuffix);
}
// Create a resource file containing a manifest XML.
std::unique_ptr<MemoryBuffer> createManifestRes() {
- std::string Manifest = createManifestXml();
+ std::string manifest = createManifestXml();
- std::unique_ptr<WritableMemoryBuffer> Res =
- createMemoryBufferForManifestRes(Manifest.size());
+ std::unique_ptr<WritableMemoryBuffer> res =
+ createMemoryBufferForManifestRes(manifest.size());
- char *Buf = Res->getBufferStart();
- writeResFileHeader(Buf);
- writeResEntryHeader(Buf, Manifest.size());
+ char *buf = res->getBufferStart();
+ writeResFileHeader(buf);
+ writeResEntryHeader(buf, manifest.size());
// Copy the manifest data into the .res file.
- std::copy(Manifest.begin(), Manifest.end(), Buf);
- return std::move(Res);
+ std::copy(manifest.begin(), manifest.end(), buf);
+ return std::move(res);
}
void createSideBySideManifest() {
- std::string Path = Config->ManifestFile;
- if (Path == "")
- Path = Config->OutputFile + ".manifest";
- std::error_code EC;
- raw_fd_ostream Out(Path, EC, sys::fs::F_Text);
- if (EC)
- fatal("failed to create manifest: " + EC.message());
- Out << createManifestXml();
+ std::string path = config->manifestFile;
+ if (path == "")
+ path = config->outputFile + ".manifest";
+ std::error_code ec;
+ raw_fd_ostream out(path, ec, sys::fs::F_Text);
+ if (ec)
+ fatal("failed to create manifest: " + ec.message());
+ out << createManifestXml();
}
// Parse a string in the form of
// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]"
// or "<name>=<dllname>.<name>".
// Used for parsing /export arguments.
-Export parseExport(StringRef Arg) {
- Export E;
- StringRef Rest;
- std::tie(E.Name, Rest) = Arg.split(",");
- if (E.Name.empty())
+Export parseExport(StringRef arg) {
+ Export e;
+ StringRef rest;
+ std::tie(e.name, rest) = arg.split(",");
+ if (e.name.empty())
goto err;
- if (E.Name.contains('=')) {
- StringRef X, Y;
- std::tie(X, Y) = E.Name.split("=");
+ if (e.name.contains('=')) {
+ StringRef x, y;
+ std::tie(x, y) = e.name.split("=");
// If "<name>=<dllname>.<name>".
- if (Y.contains(".")) {
- E.Name = X;
- E.ForwardTo = Y;
- return E;
+ if (y.contains(".")) {
+ e.name = x;
+ e.forwardTo = y;
+ return e;
}
- E.ExtName = X;
- E.Name = Y;
- if (E.Name.empty())
+ e.extName = x;
+ e.name = y;
+ if (e.name.empty())
goto err;
}
// If "<name>=<internalname>[,@ordinal[,NONAME]][,DATA][,PRIVATE]"
- while (!Rest.empty()) {
- StringRef Tok;
- std::tie(Tok, Rest) = Rest.split(",");
- if (Tok.equals_lower("noname")) {
- if (E.Ordinal == 0)
+ while (!rest.empty()) {
+ StringRef tok;
+ std::tie(tok, rest) = rest.split(",");
+ if (tok.equals_lower("noname")) {
+ if (e.ordinal == 0)
goto err;
- E.Noname = true;
+ e.noname = true;
continue;
}
- if (Tok.equals_lower("data")) {
- E.Data = true;
+ if (tok.equals_lower("data")) {
+ e.data = true;
continue;
}
- if (Tok.equals_lower("constant")) {
- E.Constant = true;
+ if (tok.equals_lower("constant")) {
+ e.constant = true;
continue;
}
- if (Tok.equals_lower("private")) {
- E.Private = true;
+ if (tok.equals_lower("private")) {
+ e.isPrivate = true;
continue;
}
- if (Tok.startswith("@")) {
- int32_t Ord;
- if (Tok.substr(1).getAsInteger(0, Ord))
+ if (tok.startswith("@")) {
+ int32_t ord;
+ if (tok.substr(1).getAsInteger(0, ord))
goto err;
- if (Ord <= 0 || 65535 < Ord)
+ if (ord <= 0 || 65535 < ord)
goto err;
- E.Ordinal = Ord;
+ e.ordinal = ord;
continue;
}
goto err;
}
- return E;
+ return e;
err:
- fatal("invalid /export: " + Arg);
+ fatal("invalid /export: " + arg);
}
-static StringRef undecorate(StringRef Sym) {
- if (Config->Machine != I386)
- return Sym;
+static StringRef undecorate(StringRef sym) {
+ if (config->machine != I386)
+ return sym;
// In MSVC mode, a fully decorated stdcall function is exported
// as-is with the leading underscore (with type IMPORT_NAME).
// In MinGW mode, a decorated stdcall function gets the underscore
// removed, just like normal cdecl functions.
- if (Sym.startswith("_") && Sym.contains('@') && !Config->MinGW)
- return Sym;
- return Sym.startswith("_") ? Sym.substr(1) : Sym;
+ if (sym.startswith("_") && sym.contains('@') && !config->mingw)
+ return sym;
+ return sym.startswith("_") ? sym.substr(1) : sym;
}
// Convert stdcall/fastcall style symbols into unsuffixed symbols,
// with or without a leading underscore. (MinGW specific.)
-static StringRef killAt(StringRef Sym, bool Prefix) {
- if (Sym.empty())
- return Sym;
+static StringRef killAt(StringRef sym, bool prefix) {
+ if (sym.empty())
+ return sym;
// Strip any trailing stdcall suffix
- Sym = Sym.substr(0, Sym.find('@', 1));
- if (!Sym.startswith("@")) {
- if (Prefix && !Sym.startswith("_"))
- return Saver.save("_" + Sym);
- return Sym;
+ sym = sym.substr(0, sym.find('@', 1));
+ if (!sym.startswith("@")) {
+ if (prefix && !sym.startswith("_"))
+ return saver.save("_" + sym);
+ return sym;
}
// For fastcall, remove the leading @ and replace it with an
// underscore, if prefixes are used.
- Sym = Sym.substr(1);
- if (Prefix)
- Sym = Saver.save("_" + Sym);
- return Sym;
+ sym = sym.substr(1);
+ if (prefix)
+ sym = saver.save("_" + sym);
+ return sym;
}
// Performs error checking on all /export arguments.
// It also sets ordinals.
void fixupExports() {
// Symbol ordinals must be unique.
- std::set<uint16_t> Ords;
- for (Export &E : Config->Exports) {
- if (E.Ordinal == 0)
+ std::set<uint16_t> ords;
+ for (Export &e : config->exports) {
+ if (e.ordinal == 0)
continue;
- if (!Ords.insert(E.Ordinal).second)
- fatal("duplicate export ordinal: " + E.Name);
+ if (!ords.insert(e.ordinal).second)
+ fatal("duplicate export ordinal: " + e.name);
}
- for (Export &E : Config->Exports) {
- if (!E.ForwardTo.empty()) {
- E.ExportName = undecorate(E.Name);
+ for (Export &e : config->exports) {
+ if (!e.forwardTo.empty()) {
+ e.exportName = undecorate(e.name);
} else {
- E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName);
+ e.exportName = undecorate(e.extName.empty() ? e.name : e.extName);
}
}
- if (Config->KillAt && Config->Machine == I386) {
- for (Export &E : Config->Exports) {
- E.Name = killAt(E.Name, true);
- E.ExportName = killAt(E.ExportName, false);
- E.ExtName = killAt(E.ExtName, true);
- E.SymbolName = killAt(E.SymbolName, true);
+ if (config->killAt && config->machine == I386) {
+ for (Export &e : config->exports) {
+ e.name = killAt(e.name, true);
+ e.exportName = killAt(e.exportName, false);
+ e.extName = killAt(e.extName, true);
+ e.symbolName = killAt(e.symbolName, true);
}
}
// Uniquefy by name.
- DenseMap<StringRef, Export *> Map(Config->Exports.size());
- std::vector<Export> V;
- for (Export &E : Config->Exports) {
- auto Pair = Map.insert(std::make_pair(E.ExportName, &E));
- bool Inserted = Pair.second;
- if (Inserted) {
- V.push_back(E);
+ DenseMap<StringRef, Export *> map(config->exports.size());
+ std::vector<Export> v;
+ for (Export &e : config->exports) {
+ auto pair = map.insert(std::make_pair(e.exportName, &e));
+ bool inserted = pair.second;
+ if (inserted) {
+ v.push_back(e);
continue;
}
- Export *Existing = Pair.first->second;
- if (E == *Existing || E.Name != Existing->Name)
+ Export *existing = pair.first->second;
+ if (e == *existing || e.name != existing->name)
continue;
- warn("duplicate /export option: " + E.Name);
+ warn("duplicate /export option: " + e.name);
}
- Config->Exports = std::move(V);
+ config->exports = std::move(v);
// Sort by name.
- std::sort(Config->Exports.begin(), Config->Exports.end(),
- [](const Export &A, const Export &B) {
- return A.ExportName < B.ExportName;
+ std::sort(config->exports.begin(), config->exports.end(),
+ [](const Export &a, const Export &b) {
+ return a.exportName < b.exportName;
});
}
void assignExportOrdinals() {
// Assign unique ordinals if default (= 0).
- uint16_t Max = 0;
- for (Export &E : Config->Exports)
- Max = std::max(Max, E.Ordinal);
- for (Export &E : Config->Exports)
- if (E.Ordinal == 0)
- E.Ordinal = ++Max;
+ uint16_t max = 0;
+ for (Export &e : config->exports)
+ max = std::max(max, e.ordinal);
+ for (Export &e : config->exports)
+ if (e.ordinal == 0)
+ e.ordinal = ++max;
}
// Parses a string in the form of "key=value" and check
// if value matches previous values for the same key.
-void checkFailIfMismatch(StringRef Arg, InputFile *Source) {
- StringRef K, V;
- std::tie(K, V) = Arg.split('=');
- if (K.empty() || V.empty())
- fatal("/failifmismatch: invalid argument: " + Arg);
- std::pair<StringRef, InputFile *> Existing = Config->MustMatch[K];
- if (!Existing.first.empty() && V != Existing.first) {
- std::string SourceStr = Source ? toString(Source) : "cmd-line";
- std::string ExistingStr =
- Existing.second ? toString(Existing.second) : "cmd-line";
- fatal("/failifmismatch: mismatch detected for '" + K + "':\n>>> " +
- ExistingStr + " has value " + Existing.first + "\n>>> " + SourceStr +
- " has value " + V);
- }
- Config->MustMatch[K] = {V, Source};
+void checkFailIfMismatch(StringRef arg, InputFile *source) {
+ StringRef k, v;
+ std::tie(k, v) = arg.split('=');
+ if (k.empty() || v.empty())
+ fatal("/failifmismatch: invalid argument: " + arg);
+ std::pair<StringRef, InputFile *> existing = config->mustMatch[k];
+ if (!existing.first.empty() && v != existing.first) {
+ std::string sourceStr = source ? toString(source) : "cmd-line";
+ std::string existingStr =
+ existing.second ? toString(existing.second) : "cmd-line";
+ fatal("/failifmismatch: mismatch detected for '" + k + "':\n>>> " +
+ existingStr + " has value " + existing.first + "\n>>> " + sourceStr +
+ " has value " + v);
+ }
+ config->mustMatch[k] = {v, source};
}
// Convert Windows resource files (.res files) to a .obj file.
// Does what cvtres.exe does, but in-process and cross-platform.
-MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs) {
- object::WindowsResourceParser Parser;
+MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs) {
+ object::WindowsResourceParser parser;
- for (MemoryBufferRef MB : MBs) {
- std::unique_ptr<object::Binary> Bin = check(object::createBinary(MB));
- object::WindowsResource *RF = dyn_cast<object::WindowsResource>(Bin.get());
- if (!RF)
+ for (MemoryBufferRef mb : mbs) {
+ std::unique_ptr<object::Binary> bin = check(object::createBinary(mb));
+ object::WindowsResource *rf = dyn_cast<object::WindowsResource>(bin.get());
+ if (!rf)
fatal("cannot compile non-resource file as resource");
- std::vector<std::string> Duplicates;
- if (auto EC = Parser.parse(RF, Duplicates))
- fatal(toString(std::move(EC)));
+ std::vector<std::string> duplicates;
+ if (auto ec = parser.parse(rf, duplicates))
+ fatal(toString(std::move(ec)));
- for (const auto &DupeDiag : Duplicates)
- if (Config->ForceMultipleRes)
- warn(DupeDiag);
+ for (const auto &dupeDiag : duplicates)
+ if (config->forceMultipleRes)
+ warn(dupeDiag);
else
- error(DupeDiag);
+ error(dupeDiag);
}
- Expected<std::unique_ptr<MemoryBuffer>> E =
- llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser,
- Config->Timestamp);
- if (!E)
- fatal("failed to write .res to COFF: " + toString(E.takeError()));
+ Expected<std::unique_ptr<MemoryBuffer>> e =
+ llvm::object::writeWindowsResourceCOFF(config->machine, parser,
+ config->timestamp);
+ if (!e)
+ fatal("failed to write .res to COFF: " + toString(e.takeError()));
- MemoryBufferRef MBRef = **E;
- make<std::unique_ptr<MemoryBuffer>>(std::move(*E)); // take ownership
- return MBRef;
+ MemoryBufferRef mbref = **e;
+ make<std::unique_ptr<MemoryBuffer>>(std::move(*e)); // take ownership
+ return mbref;
}
// Create OptTable
#undef PREFIX
// Create table mapping all options defined in Options.td
-static const llvm::opt::OptTable::Info InfoTable[] = {
+static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
{X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \
X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
#undef OPTION
};
-COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {}
+COFFOptTable::COFFOptTable() : OptTable(infoTable, true) {}
// Set color diagnostics according to --color-diagnostics={auto,always,never}
// or --no-color-diagnostics flags.
-static void handleColorDiagnostics(opt::InputArgList &Args) {
- auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+static void handleColorDiagnostics(opt::InputArgList &args) {
+ auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
OPT_no_color_diagnostics);
- if (!Arg)
+ if (!arg)
return;
- if (Arg->getOption().getID() == OPT_color_diagnostics) {
- errorHandler().ColorDiagnostics = true;
- } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
- errorHandler().ColorDiagnostics = false;
+ if (arg->getOption().getID() == OPT_color_diagnostics) {
+ errorHandler().colorDiagnostics = true;
+ } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
+ errorHandler().colorDiagnostics = false;
} else {
- StringRef S = Arg->getValue();
- if (S == "always")
- errorHandler().ColorDiagnostics = true;
- else if (S == "never")
- errorHandler().ColorDiagnostics = false;
- else if (S != "auto")
- error("unknown option: --color-diagnostics=" + S);
- }
-}
-
-static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
- StringRef S = Arg->getValue();
- if (S != "windows" && S != "posix")
- error("invalid response file quoting: " + S);
- if (S == "windows")
+ StringRef s = arg->getValue();
+ if (s == "always")
+ errorHandler().colorDiagnostics = true;
+ else if (s == "never")
+ errorHandler().colorDiagnostics = false;
+ else if (s != "auto")
+ error("unknown option: --color-diagnostics=" + s);
+ }
+}
+
+static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) {
+ if (auto *arg = args.getLastArg(OPT_rsp_quoting)) {
+ StringRef s = arg->getValue();
+ if (s != "windows" && s != "posix")
+ error("invalid response file quoting: " + s);
+ if (s == "windows")
return cl::TokenizeWindowsCommandLine;
return cl::TokenizeGNUCommandLine;
}
}
// Parses a given list of options.
-opt::InputArgList ArgParser::parse(ArrayRef<const char *> Argv) {
+opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
// Make InputArgList from string vectors.
- unsigned MissingIndex;
- unsigned MissingCount;
+ unsigned missingIndex;
+ unsigned missingCount;
// We need to get the quoting style for response files before parsing all
// options so we parse here before and ignore all the options but
// --rsp-quoting.
- opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount);
+ opt::InputArgList args = table.ParseArgs(argv, missingIndex, missingCount);
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
- SmallVector<const char *, 256> ExpandedArgv(Argv.data(),
- Argv.data() + Argv.size());
- cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv);
- Args = Table.ParseArgs(makeArrayRef(ExpandedArgv).drop_front(), MissingIndex,
- MissingCount);
+ SmallVector<const char *, 256> expandedArgv(argv.data(),
+ argv.data() + argv.size());
+ cl::ExpandResponseFiles(saver, getQuotingStyle(args), expandedArgv);
+ args = table.ParseArgs(makeArrayRef(expandedArgv).drop_front(), missingIndex,
+ missingCount);
// Print the real command line if response files are expanded.
- if (Args.hasArg(OPT_verbose) && Argv.size() != ExpandedArgv.size()) {
- std::string Msg = "Command line:";
- for (const char *S : ExpandedArgv)
- Msg += " " + std::string(S);
- message(Msg);
+ if (args.hasArg(OPT_verbose) && argv.size() != expandedArgv.size()) {
+ std::string msg = "Command line:";
+ for (const char *s : expandedArgv)
+ msg += " " + std::string(s);
+ message(msg);
}
// Save the command line after response file expansion so we can write it to
// the PDB if necessary.
- Config->Argv = {ExpandedArgv.begin(), ExpandedArgv.end()};
+ config->argv = {expandedArgv.begin(), expandedArgv.end()};
// Handle /WX early since it converts missing argument warnings to errors.
- errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false);
+ errorHandler().fatalWarnings = args.hasFlag(OPT_WX, OPT_WX_no, false);
- if (MissingCount)
- fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
+ if (missingCount)
+ fatal(Twine(args.getArgString(missingIndex)) + ": missing argument");
- handleColorDiagnostics(Args);
+ handleColorDiagnostics(args);
- for (auto *Arg : Args.filtered(OPT_UNKNOWN)) {
- std::string Nearest;
- if (Table.findNearest(Arg->getAsString(Args), Nearest) > 1)
- warn("ignoring unknown argument '" + Arg->getAsString(Args) + "'");
+ for (auto *arg : args.filtered(OPT_UNKNOWN)) {
+ std::string nearest;
+ if (table.findNearest(arg->getAsString(args), nearest) > 1)
+ warn("ignoring unknown argument '" + arg->getAsString(args) + "'");
else
- warn("ignoring unknown argument '" + Arg->getAsString(Args) +
- "', did you mean '" + Nearest + "'");
+ warn("ignoring unknown argument '" + arg->getAsString(args) +
+ "', did you mean '" + nearest + "'");
}
- if (Args.hasArg(OPT_lib))
+ if (args.hasArg(OPT_lib))
warn("ignoring /lib since it's not the first argument");
- return Args;
+ return args;
}
// Tokenizes and parses a given string as command line in .drective section.
// /EXPORT options are processed in fastpath.
std::pair<opt::InputArgList, std::vector<StringRef>>
-ArgParser::parseDirectives(StringRef S) {
- std::vector<StringRef> Exports;
- SmallVector<const char *, 16> Rest;
+ArgParser::parseDirectives(StringRef s) {
+ std::vector<StringRef> exports;
+ SmallVector<const char *, 16> rest;
- for (StringRef Tok : tokenize(S)) {
- if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:"))
- Exports.push_back(Tok.substr(strlen("/export:")));
+ for (StringRef tok : tokenize(s)) {
+ if (tok.startswith_lower("/export:") || tok.startswith_lower("-export:"))
+ exports.push_back(tok.substr(strlen("/export:")));
else
- Rest.push_back(Tok.data());
+ rest.push_back(tok.data());
}
// Make InputArgList from unparsed string vectors.
- unsigned MissingIndex;
- unsigned MissingCount;
+ unsigned missingIndex;
+ unsigned missingCount;
- opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount);
+ opt::InputArgList args = table.ParseArgs(rest, missingIndex, missingCount);
- if (MissingCount)
- fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
- for (auto *Arg : Args.filtered(OPT_UNKNOWN))
- warn("ignoring unknown argument: " + Arg->getAsString(Args));
- return {std::move(Args), std::move(Exports)};
+ if (missingCount)
+ fatal(Twine(args.getArgString(missingIndex)) + ": missing argument");
+ for (auto *arg : args.filtered(OPT_UNKNOWN))
+ warn("ignoring unknown argument: " + arg->getAsString(args));
+ return {std::move(args), std::move(exports)};
}
// link.exe has an interesting feature. If LINK or _LINK_ environment
// variables exist, their contents are handled as command line strings.
// So you can pass extra arguments using them.
-opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Argv) {
+opt::InputArgList ArgParser::parseLINK(std::vector<const char *> argv) {
// Concatenate LINK env and command line arguments, and then parse them.
- if (Optional<std::string> S = Process::GetEnv("LINK")) {
- std::vector<const char *> V = tokenize(*S);
- Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
+ if (Optional<std::string> s = Process::GetEnv("LINK")) {
+ std::vector<const char *> v = tokenize(*s);
+ argv.insert(std::next(argv.begin()), v.begin(), v.end());
}
- if (Optional<std::string> S = Process::GetEnv("_LINK_")) {
- std::vector<const char *> V = tokenize(*S);
- Argv.insert(std::next(Argv.begin()), V.begin(), V.end());
+ if (Optional<std::string> s = Process::GetEnv("_LINK_")) {
+ std::vector<const char *> v = tokenize(*s);
+ argv.insert(std::next(argv.begin()), v.begin(), v.end());
}
- return parse(Argv);
+ return parse(argv);
}
-std::vector<const char *> ArgParser::tokenize(StringRef S) {
- SmallVector<const char *, 16> Tokens;
- cl::TokenizeWindowsCommandLine(S, Saver, Tokens);
- return std::vector<const char *>(Tokens.begin(), Tokens.end());
+std::vector<const char *> ArgParser::tokenize(StringRef s) {
+ SmallVector<const char *, 16> tokens;
+ cl::TokenizeWindowsCommandLine(s, saver, tokens);
+ return std::vector<const char *>(tokens.begin(), tokens.end());
}
-void printHelp(const char *Argv0) {
+void printHelp(const char *argv0) {
COFFOptTable().PrintHelp(outs(),
- (std::string(Argv0) + " [options] file...").c_str(),
+ (std::string(argv0) + " [options] file...").c_str(),
"LLVM Linker", false);
}
namespace lld {
namespace coff {
-static Timer ICFTimer("ICF", Timer::root());
+static Timer icfTimer("ICF", Timer::root());
class ICF {
public:
- void run(ArrayRef<Chunk *> V);
+ void run(ArrayRef<Chunk *> v);
private:
- void segregate(size_t Begin, size_t End, bool Constant);
+ void segregate(size_t begin, size_t end, bool constant);
- bool assocEquals(const SectionChunk *A, const SectionChunk *B);
+ bool assocEquals(const SectionChunk *a, const SectionChunk *b);
- bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
- bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
+ bool equalsConstant(const SectionChunk *a, const SectionChunk *b);
+ bool equalsVariable(const SectionChunk *a, const SectionChunk *b);
- bool isEligible(SectionChunk *C);
+ bool isEligible(SectionChunk *c);
- size_t findBoundary(size_t Begin, size_t End);
+ size_t findBoundary(size_t begin, size_t end);
- void forEachClassRange(size_t Begin, size_t End,
- std::function<void(size_t, size_t)> Fn);
+ void forEachClassRange(size_t begin, size_t end,
+ std::function<void(size_t, size_t)> fn);
- void forEachClass(std::function<void(size_t, size_t)> Fn);
+ void forEachClass(std::function<void(size_t, size_t)> fn);
- std::vector<SectionChunk *> Chunks;
- int Cnt = 0;
- std::atomic<bool> Repeat = {false};
+ std::vector<SectionChunk *> chunks;
+ int cnt = 0;
+ std::atomic<bool> repeat = {false};
};
// Returns true if section S is subject of ICF.
// merge read-only sections in a couple of cases where the address of the
// section is insignificant to the user program and the behaviour matches that
// of the Visual C++ linker.
-bool ICF::isEligible(SectionChunk *C) {
+bool ICF::isEligible(SectionChunk *c) {
// Non-comdat chunks, dead chunks, and writable chunks are not elegible.
- bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
- if (!C->isCOMDAT() || !C->Live || Writable)
+ bool writable = c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
+ if (!c->isCOMDAT() || !c->live || writable)
return false;
// Code sections are eligible.
- if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
+ if (c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
return true;
// .pdata and .xdata unwind info sections are eligible.
- StringRef OutSecName = C->getSectionName().split('$').first;
- if (OutSecName == ".pdata" || OutSecName == ".xdata")
+ StringRef outSecName = c->getSectionName().split('$').first;
+ if (outSecName == ".pdata" || outSecName == ".xdata")
return true;
// So are vtables.
- if (C->Sym && C->Sym->getName().startswith("??_7"))
+ if (c->sym && c->sym->getName().startswith("??_7"))
return true;
// Anything else not in an address-significance table is eligible.
- return !C->KeepUnique;
+ return !c->keepUnique;
}
// Split an equivalence class into smaller classes.
-void ICF::segregate(size_t Begin, size_t End, bool Constant) {
- while (Begin < End) {
+void ICF::segregate(size_t begin, size_t end, bool constant) {
+ while (begin < end) {
// Divide [Begin, End) into two. Let Mid be the start index of the
// second group.
- auto Bound = std::stable_partition(
- Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) {
- if (Constant)
- return equalsConstant(Chunks[Begin], S);
- return equalsVariable(Chunks[Begin], S);
+ auto bound = std::stable_partition(
+ chunks.begin() + begin + 1, chunks.begin() + end, [&](SectionChunk *s) {
+ if (constant)
+ return equalsConstant(chunks[begin], s);
+ return equalsVariable(chunks[begin], s);
});
- size_t Mid = Bound - Chunks.begin();
+ size_t mid = bound - chunks.begin();
// Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an
// equivalence class ID because every group ends with a unique index.
- for (size_t I = Begin; I < Mid; ++I)
- Chunks[I]->Class[(Cnt + 1) % 2] = Mid;
+ for (size_t i = begin; i < mid; ++i)
+ chunks[i]->eqClass[(cnt + 1) % 2] = mid;
// If we created a group, we need to iterate the main loop again.
- if (Mid != End)
- Repeat = true;
+ if (mid != end)
+ repeat = true;
- Begin = Mid;
+ begin = mid;
}
}
// Returns true if two sections' associative children are equal.
-bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) {
- auto ChildClasses = [&](const SectionChunk *SC) {
- std::vector<uint32_t> Classes;
- for (const SectionChunk &C : SC->children())
- if (!C.getSectionName().startswith(".debug") &&
- C.getSectionName() != ".gfids$y" && C.getSectionName() != ".gljmp$y")
- Classes.push_back(C.Class[Cnt % 2]);
- return Classes;
+bool ICF::assocEquals(const SectionChunk *a, const SectionChunk *b) {
+ auto childClasses = [&](const SectionChunk *sc) {
+ std::vector<uint32_t> classes;
+ for (const SectionChunk &c : sc->children())
+ if (!c.getSectionName().startswith(".debug") &&
+ c.getSectionName() != ".gfids$y" && c.getSectionName() != ".gljmp$y")
+ classes.push_back(c.eqClass[cnt % 2]);
+ return classes;
};
- return ChildClasses(A) == ChildClasses(B);
+ return childClasses(a) == childClasses(b);
}
// Compare "non-moving" part of two sections, namely everything
// except relocation targets.
-bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
- if (A->RelocsSize != B->RelocsSize)
+bool ICF::equalsConstant(const SectionChunk *a, const SectionChunk *b) {
+ if (a->relocsSize != b->relocsSize)
return false;
// Compare relocations.
- auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
- if (R1.Type != R2.Type ||
- R1.VirtualAddress != R2.VirtualAddress) {
+ auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) {
+ if (r1.Type != r2.Type ||
+ r1.VirtualAddress != r2.VirtualAddress) {
return false;
}
- Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex);
- Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex);
- if (B1 == B2)
+ Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex);
+ Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex);
+ if (b1 == b2)
return true;
- if (auto *D1 = dyn_cast<DefinedRegular>(B1))
- if (auto *D2 = dyn_cast<DefinedRegular>(B2))
- return D1->getValue() == D2->getValue() &&
- D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
+ if (auto *d1 = dyn_cast<DefinedRegular>(b1))
+ if (auto *d2 = dyn_cast<DefinedRegular>(b2))
+ return d1->getValue() == d2->getValue() &&
+ d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2];
return false;
};
- if (!std::equal(A->getRelocs().begin(), A->getRelocs().end(),
- B->getRelocs().begin(), Eq))
+ if (!std::equal(a->getRelocs().begin(), a->getRelocs().end(),
+ b->getRelocs().begin(), eq))
return false;
// Compare section attributes and contents.
- return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
- A->getSectionName() == B->getSectionName() &&
- A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
- A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
- assocEquals(A, B);
+ return a->getOutputCharacteristics() == b->getOutputCharacteristics() &&
+ a->getSectionName() == b->getSectionName() &&
+ a->header->SizeOfRawData == b->header->SizeOfRawData &&
+ a->checksum == b->checksum && a->getContents() == b->getContents() &&
+ assocEquals(a, b);
}
// Compare "moving" part of two sections, namely relocation targets.
-bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
+bool ICF::equalsVariable(const SectionChunk *a, const SectionChunk *b) {
// Compare relocations.
- auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
- Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex);
- Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex);
- if (B1 == B2)
+ auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) {
+ Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex);
+ Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex);
+ if (b1 == b2)
return true;
- if (auto *D1 = dyn_cast<DefinedRegular>(B1))
- if (auto *D2 = dyn_cast<DefinedRegular>(B2))
- return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
+ if (auto *d1 = dyn_cast<DefinedRegular>(b1))
+ if (auto *d2 = dyn_cast<DefinedRegular>(b2))
+ return d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2];
return false;
};
- return std::equal(A->getRelocs().begin(), A->getRelocs().end(),
- B->getRelocs().begin(), Eq) &&
- assocEquals(A, B);
+ return std::equal(a->getRelocs().begin(), a->getRelocs().end(),
+ b->getRelocs().begin(), eq) &&
+ assocEquals(a, b);
}
// Find the first Chunk after Begin that has a different class from Begin.
-size_t ICF::findBoundary(size_t Begin, size_t End) {
- for (size_t I = Begin + 1; I < End; ++I)
- if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2])
- return I;
- return End;
+size_t ICF::findBoundary(size_t begin, size_t end) {
+ for (size_t i = begin + 1; i < end; ++i)
+ if (chunks[begin]->eqClass[cnt % 2] != chunks[i]->eqClass[cnt % 2])
+ return i;
+ return end;
}
-void ICF::forEachClassRange(size_t Begin, size_t End,
- std::function<void(size_t, size_t)> Fn) {
- while (Begin < End) {
- size_t Mid = findBoundary(Begin, End);
- Fn(Begin, Mid);
- Begin = Mid;
+void ICF::forEachClassRange(size_t begin, size_t end,
+ std::function<void(size_t, size_t)> fn) {
+ while (begin < end) {
+ size_t mid = findBoundary(begin, end);
+ fn(begin, mid);
+ begin = mid;
}
}
// Call Fn on each class group.
-void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {
+void ICF::forEachClass(std::function<void(size_t, size_t)> fn) {
// If the number of sections are too small to use threading,
// call Fn sequentially.
- if (Chunks.size() < 1024) {
- forEachClassRange(0, Chunks.size(), Fn);
- ++Cnt;
+ if (chunks.size() < 1024) {
+ forEachClassRange(0, chunks.size(), fn);
+ ++cnt;
return;
}
// The sharding must be completed before any calls to Fn are made
// so that Fn can modify the Chunks in its shard without causing data
// races.
- const size_t NumShards = 256;
- size_t Step = Chunks.size() / NumShards;
- size_t Boundaries[NumShards + 1];
- Boundaries[0] = 0;
- Boundaries[NumShards] = Chunks.size();
- parallelForEachN(1, NumShards, [&](size_t I) {
- Boundaries[I] = findBoundary((I - 1) * Step, Chunks.size());
+ const size_t numShards = 256;
+ size_t step = chunks.size() / numShards;
+ size_t boundaries[numShards + 1];
+ boundaries[0] = 0;
+ boundaries[numShards] = chunks.size();
+ parallelForEachN(1, numShards, [&](size_t i) {
+ boundaries[i] = findBoundary((i - 1) * step, chunks.size());
});
- parallelForEachN(1, NumShards + 1, [&](size_t I) {
- if (Boundaries[I - 1] < Boundaries[I]) {
- forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
+ parallelForEachN(1, numShards + 1, [&](size_t i) {
+ if (boundaries[i - 1] < boundaries[i]) {
+ forEachClassRange(boundaries[i - 1], boundaries[i], fn);
}
});
- ++Cnt;
+ ++cnt;
}
// Merge identical COMDAT sections.
// Two sections are considered the same if their section headers,
// contents and relocations are all the same.
-void ICF::run(ArrayRef<Chunk *> Vec) {
- ScopedTimer T(ICFTimer);
+void ICF::run(ArrayRef<Chunk *> vec) {
+ ScopedTimer t(icfTimer);
// Collect only mergeable sections and group by hash value.
- uint32_t NextId = 1;
- for (Chunk *C : Vec) {
- if (auto *SC = dyn_cast<SectionChunk>(C)) {
- if (isEligible(SC))
- Chunks.push_back(SC);
+ uint32_t nextId = 1;
+ for (Chunk *c : vec) {
+ if (auto *sc = dyn_cast<SectionChunk>(c)) {
+ if (isEligible(sc))
+ chunks.push_back(sc);
else
- SC->Class[0] = NextId++;
+ sc->eqClass[0] = nextId++;
}
}
// Make sure that ICF doesn't merge sections that are being handled by string
// tail merging.
- for (MergeChunk *MC : MergeChunk::Instances)
- if (MC)
- for (SectionChunk *SC : MC->Sections)
- SC->Class[0] = NextId++;
+ for (MergeChunk *mc : MergeChunk::instances)
+ if (mc)
+ for (SectionChunk *sc : mc->sections)
+ sc->eqClass[0] = nextId++;
// Initially, we use hash values to partition sections.
- parallelForEach(Chunks, [&](SectionChunk *SC) {
- SC->Class[0] = xxHash64(SC->getContents());
+ parallelForEach(chunks, [&](SectionChunk *sc) {
+ sc->eqClass[0] = xxHash64(sc->getContents());
});
// Combine the hashes of the sections referenced by each section into its
// hash.
- for (unsigned Cnt = 0; Cnt != 2; ++Cnt) {
- parallelForEach(Chunks, [&](SectionChunk *SC) {
- uint32_t Hash = SC->Class[Cnt % 2];
- for (Symbol *B : SC->symbols())
- if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
- Hash += Sym->getChunk()->Class[Cnt % 2];
+ for (unsigned cnt = 0; cnt != 2; ++cnt) {
+ parallelForEach(chunks, [&](SectionChunk *sc) {
+ uint32_t hash = sc->eqClass[cnt % 2];
+ for (Symbol *b : sc->symbols())
+ if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
+ hash += sym->getChunk()->eqClass[cnt % 2];
// Set MSB to 1 to avoid collisions with non-hash classs.
- SC->Class[(Cnt + 1) % 2] = Hash | (1U << 31);
+ sc->eqClass[(cnt + 1) % 2] = hash | (1U << 31);
});
}
// From now on, sections in Chunks are ordered so that sections in
// the same group are consecutive in the vector.
- llvm::stable_sort(Chunks, [](const SectionChunk *A, const SectionChunk *B) {
- return A->Class[0] < B->Class[0];
+ llvm::stable_sort(chunks, [](const SectionChunk *a, const SectionChunk *b) {
+ return a->eqClass[0] < b->eqClass[0];
});
// Compare static contents and assign unique IDs for each static content.
- forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); });
+ forEachClass([&](size_t begin, size_t end) { segregate(begin, end, true); });
// Split groups by comparing relocations until convergence is obtained.
do {
- Repeat = false;
+ repeat = false;
forEachClass(
- [&](size_t Begin, size_t End) { segregate(Begin, End, false); });
- } while (Repeat);
+ [&](size_t begin, size_t end) { segregate(begin, end, false); });
+ } while (repeat);
- log("ICF needed " + Twine(Cnt) + " iterations");
+ log("ICF needed " + Twine(cnt) + " iterations");
// Merge sections in the same classs.
- forEachClass([&](size_t Begin, size_t End) {
- if (End - Begin == 1)
+ forEachClass([&](size_t begin, size_t end) {
+ if (end - begin == 1)
return;
- log("Selected " + Chunks[Begin]->getDebugName());
- for (size_t I = Begin + 1; I < End; ++I) {
- log(" Removed " + Chunks[I]->getDebugName());
- Chunks[Begin]->replace(Chunks[I]);
+ log("Selected " + chunks[begin]->getDebugName());
+ for (size_t i = begin + 1; i < end; ++i) {
+ log(" Removed " + chunks[i]->getDebugName());
+ chunks[begin]->replace(chunks[i]);
}
});
}
// Entry point to ICF.
-void doICF(ArrayRef<Chunk *> Chunks) { ICF().run(Chunks); }
+void doICF(ArrayRef<Chunk *> chunks) { ICF().run(chunks); }
} // namespace coff
} // namespace lld
class Chunk;
-void doICF(ArrayRef<Chunk *> Chunks);
+void doICF(ArrayRef<Chunk *> chunks);
} // namespace coff
} // namespace lld
namespace lld {
namespace coff {
-std::vector<ObjFile *> ObjFile::Instances;
-std::vector<ImportFile *> ImportFile::Instances;
-std::vector<BitcodeFile *> BitcodeFile::Instances;
+std::vector<ObjFile *> ObjFile::instances;
+std::vector<ImportFile *> ImportFile::instances;
+std::vector<BitcodeFile *> BitcodeFile::instances;
/// Checks that Source is compatible with being a weak alias to Target.
/// If Source is Undefined and has no weak alias set, makes it a weak
/// alias to Target.
-static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,
- Symbol *Source, Symbol *Target) {
- if (auto *U = dyn_cast<Undefined>(Source)) {
- if (U->WeakAlias && U->WeakAlias != Target) {
+static void checkAndSetWeakAlias(SymbolTable *symtab, InputFile *f,
+ Symbol *source, Symbol *target) {
+ if (auto *u = dyn_cast<Undefined>(source)) {
+ if (u->weakAlias && u->weakAlias != target) {
// Weak aliases as produced by GCC are named in the form
// .weak.<weaksymbol>.<othersymbol>, where <othersymbol> is the name
// of another symbol emitted near the weak symbol.
// Just use the definition from the first object file that defined
// this weak symbol.
- if (Config->MinGW)
+ if (config->mingw)
return;
- Symtab->reportDuplicate(Source, F);
+ symtab->reportDuplicate(source, f);
}
- U->WeakAlias = Target;
+ u->weakAlias = target;
}
}
-ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
+ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
void ArchiveFile::parse() {
// Parse a MemoryBufferRef as an archive file.
- File = CHECK(Archive::create(MB), this);
+ file = CHECK(Archive::create(mb), this);
// Read the symbol table to construct Lazy objects.
- for (const Archive::Symbol &Sym : File->symbols())
- Symtab->addLazy(this, Sym);
+ for (const Archive::Symbol &sym : file->symbols())
+ symtab->addLazy(this, sym);
}
// Returns a buffer pointing to a member file containing a given symbol.
-void ArchiveFile::addMember(const Archive::Symbol *Sym) {
- const Archive::Child &C =
- CHECK(Sym->getMember(),
- "could not get the member for symbol " + Sym->getName());
+void ArchiveFile::addMember(const Archive::Symbol *sym) {
+ const Archive::Child &c =
+ CHECK(sym->getMember(),
+ "could not get the member for symbol " + sym->getName());
// Return an empty buffer if we have already returned the same buffer.
- if (!Seen.insert(C.getChildOffset()).second)
+ if (!seen.insert(c.getChildOffset()).second)
return;
- Driver->enqueueArchiveMember(C, Sym->getName(), getName());
+ driver->enqueueArchiveMember(c, sym->getName(), getName());
}
-std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) {
- std::vector<MemoryBufferRef> V;
- Error Err = Error::success();
- for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
- Archive::Child C =
- CHECK(COrErr,
- File->getFileName() + ": could not get the child of the archive");
- MemoryBufferRef MBRef =
- CHECK(C.getMemoryBufferRef(),
- File->getFileName() +
+std::vector<MemoryBufferRef> getArchiveMembers(Archive *file) {
+ std::vector<MemoryBufferRef> v;
+ Error err = Error::success();
+ for (const ErrorOr<Archive::Child> &cOrErr : file->children(err)) {
+ Archive::Child c =
+ CHECK(cOrErr,
+ file->getFileName() + ": could not get the child of the archive");
+ MemoryBufferRef mbref =
+ CHECK(c.getMemoryBufferRef(),
+ file->getFileName() +
": could not get the buffer for a child of the archive");
- V.push_back(MBRef);
+ v.push_back(mbref);
}
- if (Err)
- fatal(File->getFileName() +
- ": Archive::children failed: " + toString(std::move(Err)));
- return V;
+ if (err)
+ fatal(file->getFileName() +
+ ": Archive::children failed: " + toString(std::move(err)));
+ return v;
}
void ObjFile::parse() {
// Parse a memory buffer as a COFF file.
- std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), this);
+ std::unique_ptr<Binary> bin = CHECK(createBinary(mb), this);
- if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) {
- Bin.release();
- COFFObj.reset(Obj);
+ if (auto *obj = dyn_cast<COFFObjectFile>(bin.get())) {
+ bin.release();
+ coffObj.reset(obj);
} else {
fatal(toString(this) + " is not a COFF file");
}
initializeDependencies();
}
-const coff_section* ObjFile::getSection(uint32_t I) {
- const coff_section *Sec;
- if (auto EC = COFFObj->getSection(I, Sec))
- fatal("getSection failed: #" + Twine(I) + ": " + EC.message());
- return Sec;
+const coff_section* ObjFile::getSection(uint32_t i) {
+ const coff_section *sec;
+ if (auto ec = coffObj->getSection(i, sec))
+ fatal("getSection failed: #" + Twine(i) + ": " + ec.message());
+ return sec;
}
// We set SectionChunk pointers in the SparseChunks vector to this value
// an associative section definition together with the parent comdat's leader,
// we set the pointer to either nullptr (to mark the section as discarded) or a
// valid SectionChunk for that section.
-static SectionChunk *const PendingComdat = reinterpret_cast<SectionChunk *>(1);
+static SectionChunk *const pendingComdat = reinterpret_cast<SectionChunk *>(1);
void ObjFile::initializeChunks() {
- uint32_t NumSections = COFFObj->getNumberOfSections();
- Chunks.reserve(NumSections);
- SparseChunks.resize(NumSections + 1);
- for (uint32_t I = 1; I < NumSections + 1; ++I) {
- const coff_section *Sec = getSection(I);
- if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT)
- SparseChunks[I] = PendingComdat;
+ uint32_t numSections = coffObj->getNumberOfSections();
+ chunks.reserve(numSections);
+ sparseChunks.resize(numSections + 1);
+ for (uint32_t i = 1; i < numSections + 1; ++i) {
+ const coff_section *sec = getSection(i);
+ if (sec->Characteristics & IMAGE_SCN_LNK_COMDAT)
+ sparseChunks[i] = pendingComdat;
else
- SparseChunks[I] = readSection(I, nullptr, "");
+ sparseChunks[i] = readSection(i, nullptr, "");
}
}
-SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
- const coff_aux_section_definition *Def,
- StringRef LeaderName) {
- const coff_section *Sec = getSection(SectionNumber);
+SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
+ const coff_aux_section_definition *def,
+ StringRef leaderName) {
+ const coff_section *sec = getSection(sectionNumber);
- StringRef Name;
- if (Expected<StringRef> E = COFFObj->getSectionName(Sec))
- Name = *E;
+ StringRef name;
+ if (Expected<StringRef> e = coffObj->getSectionName(sec))
+ name = *e;
else
- fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " +
- toString(E.takeError()));
+ fatal("getSectionName failed: #" + Twine(sectionNumber) + ": " +
+ toString(e.takeError()));
- if (Name == ".drectve") {
- ArrayRef<uint8_t> Data;
- cantFail(COFFObj->getSectionContents(Sec, Data));
- Directives = StringRef((const char *)Data.data(), Data.size());
+ if (name == ".drectve") {
+ ArrayRef<uint8_t> data;
+ cantFail(coffObj->getSectionContents(sec, data));
+ directives = StringRef((const char *)data.data(), data.size());
return nullptr;
}
- if (Name == ".llvm_addrsig") {
- AddrsigSec = Sec;
+ if (name == ".llvm_addrsig") {
+ addrsigSec = sec;
return nullptr;
}
// and then write it to a separate .pdb file.
// Ignore DWARF debug info unless /debug is given.
- if (!Config->Debug && Name.startswith(".debug_"))
+ if (!config->debug && name.startswith(".debug_"))
return nullptr;
- if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
+ if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
return nullptr;
- auto *C = make<SectionChunk>(this, Sec);
- if (Def)
- C->Checksum = Def->CheckSum;
+ auto *c = make<SectionChunk>(this, sec);
+ if (def)
+ c->checksum = def->CheckSum;
// link.exe uses the presence of .rsrc$01 for LNK4078, so match that.
- if (Name == ".rsrc$01")
- IsResourceObjFile = true;
+ if (name == ".rsrc$01")
+ isResourceObjFile = true;
// CodeView sections are stored to a different vector because they are not
// linked in the regular manner.
- if (C->isCodeView())
- DebugChunks.push_back(C);
- else if (Name == ".gfids$y")
- GuardFidChunks.push_back(C);
- else if (Name == ".gljmp$y")
- GuardLJmpChunks.push_back(C);
- else if (Name == ".sxdata")
- SXDataChunks.push_back(C);
- else if (Config->TailMerge && Sec->NumberOfRelocations == 0 &&
- Name == ".rdata" && LeaderName.startswith("??_C@"))
+ if (c->isCodeView())
+ debugChunks.push_back(c);
+ else if (name == ".gfids$y")
+ guardFidChunks.push_back(c);
+ else if (name == ".gljmp$y")
+ guardLJmpChunks.push_back(c);
+ else if (name == ".sxdata")
+ sXDataChunks.push_back(c);
+ else if (config->tailMerge && sec->NumberOfRelocations == 0 &&
+ name == ".rdata" && leaderName.startswith("??_C@"))
// COFF sections that look like string literal sections (i.e. no
// relocations, in .rdata, leader symbol name matches the MSVC name mangling
// for string literals) are subject to string tail merging.
- MergeChunk::addSection(C);
+ MergeChunk::addSection(c);
else
- Chunks.push_back(C);
+ chunks.push_back(c);
- return C;
+ return c;
}
void ObjFile::readAssociativeDefinition(
- COFFSymbolRef Sym, const coff_aux_section_definition *Def) {
- readAssociativeDefinition(Sym, Def, Def->getNumber(Sym.isBigObj()));
+ COFFSymbolRef sym, const coff_aux_section_definition *def) {
+ readAssociativeDefinition(sym, def, def->getNumber(sym.isBigObj()));
}
-void ObjFile::readAssociativeDefinition(COFFSymbolRef Sym,
- const coff_aux_section_definition *Def,
- uint32_t ParentIndex) {
- SectionChunk *Parent = SparseChunks[ParentIndex];
- int32_t SectionNumber = Sym.getSectionNumber();
-
- auto Diag = [&]() {
- StringRef Name, ParentName;
- COFFObj->getSymbolName(Sym, Name);
-
- const coff_section *ParentSec = getSection(ParentIndex);
- if (Expected<StringRef> E = COFFObj->getSectionName(ParentSec))
- ParentName = *E;
- error(toString(this) + ": associative comdat " + Name + " (sec " +
- Twine(SectionNumber) + ") has invalid reference to section " +
- ParentName + " (sec " + Twine(ParentIndex) + ")");
+void ObjFile::readAssociativeDefinition(COFFSymbolRef sym,
+ const coff_aux_section_definition *def,
+ uint32_t parentIndex) {
+ SectionChunk *parent = sparseChunks[parentIndex];
+ int32_t sectionNumber = sym.getSectionNumber();
+
+ auto diag = [&]() {
+ StringRef name, parentName;
+ coffObj->getSymbolName(sym, name);
+
+ const coff_section *parentSec = getSection(parentIndex);
+ if (Expected<StringRef> e = coffObj->getSectionName(parentSec))
+ parentName = *e;
+ error(toString(this) + ": associative comdat " + name + " (sec " +
+ Twine(sectionNumber) + ") has invalid reference to section " +
+ parentName + " (sec " + Twine(parentIndex) + ")");
};
- if (Parent == PendingComdat) {
+ if (parent == pendingComdat) {
// This can happen if an associative comdat refers to another associative
// comdat that appears after it (invalid per COFF spec) or to a section
// without any symbols.
- Diag();
+ diag();
return;
}
// Check whether the parent is prevailing. If it is, so are we, and we read
// the section; otherwise mark it as discarded.
- if (Parent) {
- SectionChunk *C = readSection(SectionNumber, Def, "");
- SparseChunks[SectionNumber] = C;
- if (C) {
- C->Selection = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
- Parent->addAssociative(C);
+ if (parent) {
+ SectionChunk *c = readSection(sectionNumber, def, "");
+ sparseChunks[sectionNumber] = c;
+ if (c) {
+ c->selection = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
+ parent->addAssociative(c);
}
} else {
- SparseChunks[SectionNumber] = nullptr;
+ sparseChunks[sectionNumber] = nullptr;
}
}
void ObjFile::recordPrevailingSymbolForMingw(
- COFFSymbolRef Sym, DenseMap<StringRef, uint32_t> &PrevailingSectionMap) {
+ COFFSymbolRef sym, DenseMap<StringRef, uint32_t> &prevailingSectionMap) {
// For comdat symbols in executable sections, where this is the copy
// of the section chunk we actually include instead of discarding it,
// add the symbol to a map to allow using it for implicitly
// associating .[px]data$<func> sections to it.
- int32_t SectionNumber = Sym.getSectionNumber();
- SectionChunk *SC = SparseChunks[SectionNumber];
- if (SC && SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) {
- StringRef Name;
- COFFObj->getSymbolName(Sym, Name);
+ int32_t sectionNumber = sym.getSectionNumber();
+ SectionChunk *sc = sparseChunks[sectionNumber];
+ if (sc && sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) {
+ StringRef name;
+ coffObj->getSymbolName(sym, name);
if (getMachineType() == I386)
- Name.consume_front("_");
- PrevailingSectionMap[Name] = SectionNumber;
+ name.consume_front("_");
+ prevailingSectionMap[name] = sectionNumber;
}
}
void ObjFile::maybeAssociateSEHForMingw(
- COFFSymbolRef Sym, const coff_aux_section_definition *Def,
- const DenseMap<StringRef, uint32_t> &PrevailingSectionMap) {
- StringRef Name;
- COFFObj->getSymbolName(Sym, Name);
- if (Name.consume_front(".pdata$") || Name.consume_front(".xdata$") ||
- Name.consume_front(".eh_frame$")) {
+ COFFSymbolRef sym, const coff_aux_section_definition *def,
+ const DenseMap<StringRef, uint32_t> &prevailingSectionMap) {
+ StringRef name;
+ coffObj->getSymbolName(sym, name);
+ if (name.consume_front(".pdata$") || name.consume_front(".xdata$") ||
+ name.consume_front(".eh_frame$")) {
// For MinGW, treat .[px]data$<func> and .eh_frame$<func> as implicitly
// associative to the symbol <func>.
- auto ParentSym = PrevailingSectionMap.find(Name);
- if (ParentSym != PrevailingSectionMap.end())
- readAssociativeDefinition(Sym, Def, ParentSym->second);
+ auto parentSym = prevailingSectionMap.find(name);
+ if (parentSym != prevailingSectionMap.end())
+ readAssociativeDefinition(sym, def, parentSym->second);
}
}
-Symbol *ObjFile::createRegular(COFFSymbolRef Sym) {
- SectionChunk *SC = SparseChunks[Sym.getSectionNumber()];
- if (Sym.isExternal()) {
- StringRef Name;
- COFFObj->getSymbolName(Sym, Name);
- if (SC)
- return Symtab->addRegular(this, Name, Sym.getGeneric(), SC);
+Symbol *ObjFile::createRegular(COFFSymbolRef sym) {
+ SectionChunk *sc = sparseChunks[sym.getSectionNumber()];
+ if (sym.isExternal()) {
+ StringRef name;
+ coffObj->getSymbolName(sym, name);
+ if (sc)
+ return symtab->addRegular(this, name, sym.getGeneric(), sc);
// For MinGW symbols named .weak.* that point to a discarded section,
// don't create an Undefined symbol. If nothing ever refers to the symbol,
// everything should be fine. If something actually refers to the symbol
// (e.g. the undefined weak alias), linking will fail due to undefined
// references at the end.
- if (Config->MinGW && Name.startswith(".weak."))
+ if (config->mingw && name.startswith(".weak."))
return nullptr;
- return Symtab->addUndefined(Name, this, false);
+ return symtab->addUndefined(name, this, false);
}
- if (SC)
+ if (sc)
return make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
- /*IsExternal*/ false, Sym.getGeneric(), SC);
+ /*IsExternal*/ false, sym.getGeneric(), sc);
return nullptr;
}
void ObjFile::initializeSymbols() {
- uint32_t NumSymbols = COFFObj->getNumberOfSymbols();
- Symbols.resize(NumSymbols);
-
- SmallVector<std::pair<Symbol *, uint32_t>, 8> WeakAliases;
- std::vector<uint32_t> PendingIndexes;
- PendingIndexes.reserve(NumSymbols);
-
- DenseMap<StringRef, uint32_t> PrevailingSectionMap;
- std::vector<const coff_aux_section_definition *> ComdatDefs(
- COFFObj->getNumberOfSections() + 1);
-
- for (uint32_t I = 0; I < NumSymbols; ++I) {
- COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I));
- bool PrevailingComdat;
- if (COFFSym.isUndefined()) {
- Symbols[I] = createUndefined(COFFSym);
- } else if (COFFSym.isWeakExternal()) {
- Symbols[I] = createUndefined(COFFSym);
- uint32_t TagIndex = COFFSym.getAux<coff_aux_weak_external>()->TagIndex;
- WeakAliases.emplace_back(Symbols[I], TagIndex);
- } else if (Optional<Symbol *> OptSym =
- createDefined(COFFSym, ComdatDefs, PrevailingComdat)) {
- Symbols[I] = *OptSym;
- if (Config->MinGW && PrevailingComdat)
- recordPrevailingSymbolForMingw(COFFSym, PrevailingSectionMap);
+ uint32_t numSymbols = coffObj->getNumberOfSymbols();
+ symbols.resize(numSymbols);
+
+ SmallVector<std::pair<Symbol *, uint32_t>, 8> weakAliases;
+ std::vector<uint32_t> pendingIndexes;
+ pendingIndexes.reserve(numSymbols);
+
+ DenseMap<StringRef, uint32_t> prevailingSectionMap;
+ std::vector<const coff_aux_section_definition *> comdatDefs(
+ coffObj->getNumberOfSections() + 1);
+
+ for (uint32_t i = 0; i < numSymbols; ++i) {
+ COFFSymbolRef coffSym = check(coffObj->getSymbol(i));
+ bool prevailingComdat;
+ if (coffSym.isUndefined()) {
+ symbols[i] = createUndefined(coffSym);
+ } else if (coffSym.isWeakExternal()) {
+ symbols[i] = createUndefined(coffSym);
+ uint32_t tagIndex = coffSym.getAux<coff_aux_weak_external>()->TagIndex;
+ weakAliases.emplace_back(symbols[i], tagIndex);
+ } else if (Optional<Symbol *> optSym =
+ createDefined(coffSym, comdatDefs, prevailingComdat)) {
+ symbols[i] = *optSym;
+ if (config->mingw && prevailingComdat)
+ recordPrevailingSymbolForMingw(coffSym, prevailingSectionMap);
} else {
// createDefined() returns None if a symbol belongs to a section that
// was pending at the point when the symbol was read. This can happen in
// In both of these cases, we can expect the section to be resolved by
// the time we finish visiting the remaining symbols in the symbol
// table. So we postpone the handling of this symbol until that time.
- PendingIndexes.push_back(I);
+ pendingIndexes.push_back(i);
}
- I += COFFSym.getNumberOfAuxSymbols();
+ i += coffSym.getNumberOfAuxSymbols();
}
- for (uint32_t I : PendingIndexes) {
- COFFSymbolRef Sym = check(COFFObj->getSymbol(I));
- if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) {
- if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
- readAssociativeDefinition(Sym, Def);
- else if (Config->MinGW)
- maybeAssociateSEHForMingw(Sym, Def, PrevailingSectionMap);
+ for (uint32_t i : pendingIndexes) {
+ COFFSymbolRef sym = check(coffObj->getSymbol(i));
+ if (const coff_aux_section_definition *def = sym.getSectionDefinition()) {
+ if (def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+ readAssociativeDefinition(sym, def);
+ else if (config->mingw)
+ maybeAssociateSEHForMingw(sym, def, prevailingSectionMap);
}
- if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) {
- StringRef Name;
- COFFObj->getSymbolName(Sym, Name);
- log("comdat section " + Name +
+ if (sparseChunks[sym.getSectionNumber()] == pendingComdat) {
+ StringRef name;
+ coffObj->getSymbolName(sym, name);
+ log("comdat section " + name +
" without leader and unassociated, discarding");
continue;
}
- Symbols[I] = createRegular(Sym);
+ symbols[i] = createRegular(sym);
}
- for (auto &KV : WeakAliases) {
- Symbol *Sym = KV.first;
- uint32_t Idx = KV.second;
- checkAndSetWeakAlias(Symtab, this, Sym, Symbols[Idx]);
+ for (auto &kv : weakAliases) {
+ Symbol *sym = kv.first;
+ uint32_t idx = kv.second;
+ checkAndSetWeakAlias(symtab, this, sym, symbols[idx]);
}
}
-Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) {
- StringRef Name;
- COFFObj->getSymbolName(Sym, Name);
- return Symtab->addUndefined(Name, this, Sym.isWeakExternal());
+Symbol *ObjFile::createUndefined(COFFSymbolRef sym) {
+ StringRef name;
+ coffObj->getSymbolName(sym, name);
+ return symtab->addUndefined(name, this, sym.isWeakExternal());
}
-void ObjFile::handleComdatSelection(COFFSymbolRef Sym, COMDATType &Selection,
- bool &Prevailing, DefinedRegular *Leader) {
- if (Prevailing)
+void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection,
+ bool &prevailing, DefinedRegular *leader) {
+ if (prevailing)
return;
// There's already an existing comdat for this symbol: `Leader`.
// Use the comdats's selection field to determine if the new
// symbol in `Sym` should be discarded, produce a duplicate symbol
// error, etc.
- SectionChunk *LeaderChunk = nullptr;
- COMDATType LeaderSelection = IMAGE_COMDAT_SELECT_ANY;
+ SectionChunk *leaderChunk = nullptr;
+ COMDATType leaderSelection = IMAGE_COMDAT_SELECT_ANY;
- if (Leader->Data) {
- LeaderChunk = Leader->getChunk();
- LeaderSelection = LeaderChunk->Selection;
+ if (leader->data) {
+ leaderChunk = leader->getChunk();
+ leaderSelection = leaderChunk->selection;
} else {
// FIXME: comdats from LTO files don't know their selection; treat them
// as "any".
- Selection = LeaderSelection;
+ selection = leaderSelection;
}
- if ((Selection == IMAGE_COMDAT_SELECT_ANY &&
- LeaderSelection == IMAGE_COMDAT_SELECT_LARGEST) ||
- (Selection == IMAGE_COMDAT_SELECT_LARGEST &&
- LeaderSelection == IMAGE_COMDAT_SELECT_ANY)) {
+ if ((selection == IMAGE_COMDAT_SELECT_ANY &&
+ leaderSelection == IMAGE_COMDAT_SELECT_LARGEST) ||
+ (selection == IMAGE_COMDAT_SELECT_LARGEST &&
+ leaderSelection == IMAGE_COMDAT_SELECT_ANY)) {
// cl.exe picks "any" for vftables when building with /GR- and
// "largest" when building with /GR. To be able to link object files
// compiled with each flag, "any" and "largest" are merged as "largest".
- LeaderSelection = Selection = IMAGE_COMDAT_SELECT_LARGEST;
+ leaderSelection = selection = IMAGE_COMDAT_SELECT_LARGEST;
}
// Other than that, comdat selections must match. This is a bit more
// Making this symmetric independent of which selection is seen first
// seems better though.
// (This behavior matches ModuleLinker::getComdatResult().)
- if (Selection != LeaderSelection) {
- log(("conflicting comdat type for " + toString(*Leader) + ": " +
- Twine((int)LeaderSelection) + " in " + toString(Leader->getFile()) +
- " and " + Twine((int)Selection) + " in " + toString(this))
+ if (selection != leaderSelection) {
+ log(("conflicting comdat type for " + toString(*leader) + ": " +
+ Twine((int)leaderSelection) + " in " + toString(leader->getFile()) +
+ " and " + Twine((int)selection) + " in " + toString(this))
.str());
- Symtab->reportDuplicate(Leader, this);
+ symtab->reportDuplicate(leader, this);
return;
}
- switch (Selection) {
+ switch (selection) {
case IMAGE_COMDAT_SELECT_NODUPLICATES:
- Symtab->reportDuplicate(Leader, this);
+ symtab->reportDuplicate(leader, this);
break;
case IMAGE_COMDAT_SELECT_ANY:
break;
case IMAGE_COMDAT_SELECT_SAME_SIZE:
- if (LeaderChunk->getSize() != getSection(Sym)->SizeOfRawData)
- Symtab->reportDuplicate(Leader, this);
+ if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData)
+ symtab->reportDuplicate(leader, this);
break;
case IMAGE_COMDAT_SELECT_EXACT_MATCH: {
- SectionChunk NewChunk(this, getSection(Sym));
+ SectionChunk newChunk(this, getSection(sym));
// link.exe only compares section contents here and doesn't complain
// if the two comdat sections have e.g. different alignment.
// Match that.
- if (LeaderChunk->getContents() != NewChunk.getContents())
- Symtab->reportDuplicate(Leader, this);
+ if (leaderChunk->getContents() != newChunk.getContents())
+ symtab->reportDuplicate(leader, this);
break;
}
llvm_unreachable("createDefined not called for associative comdats");
case IMAGE_COMDAT_SELECT_LARGEST:
- if (LeaderChunk->getSize() < getSection(Sym)->SizeOfRawData) {
+ if (leaderChunk->getSize() < getSection(sym)->SizeOfRawData) {
// Replace the existing comdat symbol with the new one.
- StringRef Name;
- COFFObj->getSymbolName(Sym, Name);
+ StringRef name;
+ coffObj->getSymbolName(sym, name);
// FIXME: This is incorrect: With /opt:noref, the previous sections
// make it into the final executable as well. Correct handling would
// be to undo reading of the whole old section that's being replaced,
// or doing one pass that determines what the final largest comdat
// is for all IMAGE_COMDAT_SELECT_LARGEST comdats and then reading
// only the largest one.
- replaceSymbol<DefinedRegular>(Leader, this, Name, /*IsCOMDAT*/ true,
- /*IsExternal*/ true, Sym.getGeneric(),
+ replaceSymbol<DefinedRegular>(leader, this, name, /*IsCOMDAT*/ true,
+ /*IsExternal*/ true, sym.getGeneric(),
nullptr);
- Prevailing = true;
+ prevailing = true;
}
break;
}
Optional<Symbol *> ObjFile::createDefined(
- COFFSymbolRef Sym,
- std::vector<const coff_aux_section_definition *> &ComdatDefs,
- bool &Prevailing) {
- Prevailing = false;
- auto GetName = [&]() {
- StringRef S;
- COFFObj->getSymbolName(Sym, S);
- return S;
+ COFFSymbolRef sym,
+ std::vector<const coff_aux_section_definition *> &comdatDefs,
+ bool &prevailing) {
+ prevailing = false;
+ auto getName = [&]() {
+ StringRef s;
+ coffObj->getSymbolName(sym, s);
+ return s;
};
- if (Sym.isCommon()) {
- auto *C = make<CommonChunk>(Sym);
- Chunks.push_back(C);
- return Symtab->addCommon(this, GetName(), Sym.getValue(), Sym.getGeneric(),
- C);
+ if (sym.isCommon()) {
+ auto *c = make<CommonChunk>(sym);
+ chunks.push_back(c);
+ return symtab->addCommon(this, getName(), sym.getValue(), sym.getGeneric(),
+ c);
}
- if (Sym.isAbsolute()) {
- StringRef Name = GetName();
+ if (sym.isAbsolute()) {
+ StringRef name = getName();
// Skip special symbols.
- if (Name == "@comp.id")
+ if (name == "@comp.id")
return nullptr;
- if (Name == "@feat.00") {
- Feat00Flags = Sym.getValue();
+ if (name == "@feat.00") {
+ feat00Flags = sym.getValue();
return nullptr;
}
- if (Sym.isExternal())
- return Symtab->addAbsolute(Name, Sym);
- return make<DefinedAbsolute>(Name, Sym);
+ if (sym.isExternal())
+ return symtab->addAbsolute(name, sym);
+ return make<DefinedAbsolute>(name, sym);
}
- int32_t SectionNumber = Sym.getSectionNumber();
- if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
+ int32_t sectionNumber = sym.getSectionNumber();
+ if (sectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
return nullptr;
- if (llvm::COFF::isReservedSectionNumber(SectionNumber))
- fatal(toString(this) + ": " + GetName() +
- " should not refer to special section " + Twine(SectionNumber));
+ if (llvm::COFF::isReservedSectionNumber(sectionNumber))
+ fatal(toString(this) + ": " + getName() +
+ " should not refer to special section " + Twine(sectionNumber));
- if ((uint32_t)SectionNumber >= SparseChunks.size())
- fatal(toString(this) + ": " + GetName() +
- " should not refer to non-existent section " + Twine(SectionNumber));
+ if ((uint32_t)sectionNumber >= sparseChunks.size())
+ fatal(toString(this) + ": " + getName() +
+ " should not refer to non-existent section " + Twine(sectionNumber));
// Comdat handling.
// A comdat symbol consists of two symbol table entries.
// symbol entry it reads ComdatDefs and then sets it back to nullptr.
// Handle comdat leader.
- if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) {
- ComdatDefs[SectionNumber] = nullptr;
- DefinedRegular *Leader;
+ if (const coff_aux_section_definition *def = comdatDefs[sectionNumber]) {
+ comdatDefs[sectionNumber] = nullptr;
+ DefinedRegular *leader;
- if (Sym.isExternal()) {
- std::tie(Leader, Prevailing) =
- Symtab->addComdat(this, GetName(), Sym.getGeneric());
+ if (sym.isExternal()) {
+ std::tie(leader, prevailing) =
+ symtab->addComdat(this, getName(), sym.getGeneric());
} else {
- Leader = make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
- /*IsExternal*/ false, Sym.getGeneric());
- Prevailing = true;
+ leader = make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
+ /*IsExternal*/ false, sym.getGeneric());
+ prevailing = true;
}
- if (Def->Selection < (int)IMAGE_COMDAT_SELECT_NODUPLICATES ||
+ if (def->Selection < (int)IMAGE_COMDAT_SELECT_NODUPLICATES ||
// Intentionally ends at IMAGE_COMDAT_SELECT_LARGEST: link.exe
// doesn't understand IMAGE_COMDAT_SELECT_NEWEST either.
- Def->Selection > (int)IMAGE_COMDAT_SELECT_LARGEST) {
- fatal("unknown comdat type " + std::to_string((int)Def->Selection) +
- " for " + GetName() + " in " + toString(this));
+ def->Selection > (int)IMAGE_COMDAT_SELECT_LARGEST) {
+ fatal("unknown comdat type " + std::to_string((int)def->Selection) +
+ " for " + getName() + " in " + toString(this));
}
- COMDATType Selection = (COMDATType)Def->Selection;
+ COMDATType selection = (COMDATType)def->Selection;
- if (Leader->IsCOMDAT)
- handleComdatSelection(Sym, Selection, Prevailing, Leader);
+ if (leader->isCOMDAT)
+ handleComdatSelection(sym, selection, prevailing, leader);
- if (Prevailing) {
- SectionChunk *C = readSection(SectionNumber, Def, GetName());
- SparseChunks[SectionNumber] = C;
- C->Sym = cast<DefinedRegular>(Leader);
- C->Selection = Selection;
- cast<DefinedRegular>(Leader)->Data = &C->Repl;
+ if (prevailing) {
+ SectionChunk *c = readSection(sectionNumber, def, getName());
+ sparseChunks[sectionNumber] = c;
+ c->sym = cast<DefinedRegular>(leader);
+ c->selection = selection;
+ cast<DefinedRegular>(leader)->data = &c->repl;
} else {
- SparseChunks[SectionNumber] = nullptr;
+ sparseChunks[sectionNumber] = nullptr;
}
- return Leader;
+ return leader;
}
// Prepare to handle the comdat leader symbol by setting the section's
// ComdatDefs pointer if we encounter a non-associative comdat.
- if (SparseChunks[SectionNumber] == PendingComdat) {
- if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) {
- if (Def->Selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE)
- ComdatDefs[SectionNumber] = Def;
+ if (sparseChunks[sectionNumber] == pendingComdat) {
+ if (const coff_aux_section_definition *def = sym.getSectionDefinition()) {
+ if (def->Selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+ comdatDefs[sectionNumber] = def;
}
return None;
}
- return createRegular(Sym);
+ return createRegular(sym);
}
MachineTypes ObjFile::getMachineType() {
- if (COFFObj)
- return static_cast<MachineTypes>(COFFObj->getMachine());
+ if (coffObj)
+ return static_cast<MachineTypes>(coffObj->getMachine());
return IMAGE_FILE_MACHINE_UNKNOWN;
}
-ArrayRef<uint8_t> ObjFile::getDebugSection(StringRef SecName) {
- if (SectionChunk *Sec = SectionChunk::findByName(DebugChunks, SecName))
- return Sec->consumeDebugMagic();
+ArrayRef<uint8_t> ObjFile::getDebugSection(StringRef secName) {
+ if (SectionChunk *sec = SectionChunk::findByName(debugChunks, secName))
+ return sec->consumeDebugMagic();
return {};
}
// PCHSignature member. S_COMPILE3 stores compile-time cmd-line flags. This is
// currently used to initialize the HotPatchable member.
void ObjFile::initializeFlags() {
- ArrayRef<uint8_t> Data = getDebugSection(".debug$S");
- if (Data.empty())
+ ArrayRef<uint8_t> data = getDebugSection(".debug$S");
+ if (data.empty())
return;
- DebugSubsectionArray Subsections;
+ DebugSubsectionArray subsections;
- BinaryStreamReader Reader(Data, support::little);
- ExitOnError ExitOnErr;
- ExitOnErr(Reader.readArray(Subsections, Data.size()));
+ BinaryStreamReader reader(data, support::little);
+ ExitOnError exitOnErr;
+ exitOnErr(reader.readArray(subsections, data.size()));
- for (const DebugSubsectionRecord &SS : Subsections) {
- if (SS.kind() != DebugSubsectionKind::Symbols)
+ for (const DebugSubsectionRecord &ss : subsections) {
+ if (ss.kind() != DebugSubsectionKind::Symbols)
continue;
- unsigned Offset = 0;
+ unsigned offset = 0;
// Only parse the first two records. We are only looking for S_OBJNAME
// and S_COMPILE3, and they usually appear at the beginning of the
// stream.
- for (unsigned I = 0; I < 2; ++I) {
- Expected<CVSymbol> Sym = readSymbolFromStream(SS.getRecordData(), Offset);
- if (!Sym) {
- consumeError(Sym.takeError());
+ for (unsigned i = 0; i < 2; ++i) {
+ Expected<CVSymbol> sym = readSymbolFromStream(ss.getRecordData(), offset);
+ if (!sym) {
+ consumeError(sym.takeError());
return;
}
- if (Sym->kind() == SymbolKind::S_COMPILE3) {
- auto CS =
- cantFail(SymbolDeserializer::deserializeAs<Compile3Sym>(Sym.get()));
- HotPatchable =
- (CS.Flags & CompileSym3Flags::HotPatch) != CompileSym3Flags::None;
+ if (sym->kind() == SymbolKind::S_COMPILE3) {
+ auto cs =
+ cantFail(SymbolDeserializer::deserializeAs<Compile3Sym>(sym.get()));
+ hotPatchable =
+ (cs.Flags & CompileSym3Flags::HotPatch) != CompileSym3Flags::None;
}
- if (Sym->kind() == SymbolKind::S_OBJNAME) {
- auto ObjName = cantFail(SymbolDeserializer::deserializeAs<ObjNameSym>(
- Sym.get()));
- PCHSignature = ObjName.Signature;
+ if (sym->kind() == SymbolKind::S_OBJNAME) {
+ auto objName = cantFail(SymbolDeserializer::deserializeAs<ObjNameSym>(
+ sym.get()));
+ pchSignature = objName.Signature;
}
- Offset += Sym->length();
+ offset += sym->length();
}
}
}
// DebugTypes.h). Both cases only happen with cl.exe: clang-cl produces regular
// output even with /Yc and /Yu and with /Zi.
void ObjFile::initializeDependencies() {
- if (!Config->Debug)
+ if (!config->debug)
return;
- bool IsPCH = false;
+ bool isPCH = false;
- ArrayRef<uint8_t> Data = getDebugSection(".debug$P");
- if (!Data.empty())
- IsPCH = true;
+ ArrayRef<uint8_t> data = getDebugSection(".debug$P");
+ if (!data.empty())
+ isPCH = true;
else
- Data = getDebugSection(".debug$T");
+ data = getDebugSection(".debug$T");
- if (Data.empty())
+ if (data.empty())
return;
- CVTypeArray Types;
- BinaryStreamReader Reader(Data, support::little);
- cantFail(Reader.readArray(Types, Reader.getLength()));
+ CVTypeArray types;
+ BinaryStreamReader reader(data, support::little);
+ cantFail(reader.readArray(types, reader.getLength()));
- CVTypeArray::Iterator FirstType = Types.begin();
- if (FirstType == Types.end())
+ CVTypeArray::Iterator firstType = types.begin();
+ if (firstType == types.end())
return;
- DebugTypes.emplace(Types);
+ debugTypes.emplace(types);
- if (IsPCH) {
- DebugTypesObj = makePrecompSource(this);
+ if (isPCH) {
+ debugTypesObj = makePrecompSource(this);
return;
}
- if (FirstType->kind() == LF_TYPESERVER2) {
- TypeServer2Record TS = cantFail(
- TypeDeserializer::deserializeAs<TypeServer2Record>(FirstType->data()));
- DebugTypesObj = makeUseTypeServerSource(this, &TS);
+ if (firstType->kind() == LF_TYPESERVER2) {
+ TypeServer2Record ts = cantFail(
+ TypeDeserializer::deserializeAs<TypeServer2Record>(firstType->data()));
+ debugTypesObj = makeUseTypeServerSource(this, &ts);
return;
}
- if (FirstType->kind() == LF_PRECOMP) {
- PrecompRecord Precomp = cantFail(
- TypeDeserializer::deserializeAs<PrecompRecord>(FirstType->data()));
- DebugTypesObj = makeUsePrecompSource(this, &Precomp);
+ if (firstType->kind() == LF_PRECOMP) {
+ PrecompRecord precomp = cantFail(
+ TypeDeserializer::deserializeAs<PrecompRecord>(firstType->data()));
+ debugTypesObj = makeUsePrecompSource(this, &precomp);
return;
}
- DebugTypesObj = makeTpiSource(this);
+ debugTypesObj = makeTpiSource(this);
}
-StringRef ltrim1(StringRef S, const char *Chars) {
- if (!S.empty() && strchr(Chars, S[0]))
- return S.substr(1);
- return S;
+StringRef ltrim1(StringRef s, const char *chars) {
+ if (!s.empty() && strchr(chars, s[0]))
+ return s.substr(1);
+ return s;
}
void ImportFile::parse() {
- const char *Buf = MB.getBufferStart();
- const auto *Hdr = reinterpret_cast<const coff_import_header *>(Buf);
+ const char *buf = mb.getBufferStart();
+ const auto *hdr = reinterpret_cast<const coff_import_header *>(buf);
// Check if the total size is valid.
- if (MB.getBufferSize() != sizeof(*Hdr) + Hdr->SizeOfData)
+ if (mb.getBufferSize() != sizeof(*hdr) + hdr->SizeOfData)
fatal("broken import library");
// Read names and create an __imp_ symbol.
- StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr)));
- StringRef ImpName = Saver.save("__imp_" + Name);
- const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
- DLLName = StringRef(NameStart);
- StringRef ExtName;
- switch (Hdr->getNameType()) {
+ StringRef name = saver.save(StringRef(buf + sizeof(*hdr)));
+ StringRef impName = saver.save("__imp_" + name);
+ const char *nameStart = buf + sizeof(coff_import_header) + name.size() + 1;
+ dllName = StringRef(nameStart);
+ StringRef extName;
+ switch (hdr->getNameType()) {
case IMPORT_ORDINAL:
- ExtName = "";
+ extName = "";
break;
case IMPORT_NAME:
- ExtName = Name;
+ extName = name;
break;
case IMPORT_NAME_NOPREFIX:
- ExtName = ltrim1(Name, "?@_");
+ extName = ltrim1(name, "?@_");
break;
case IMPORT_NAME_UNDECORATE:
- ExtName = ltrim1(Name, "?@_");
- ExtName = ExtName.substr(0, ExtName.find('@'));
+ extName = ltrim1(name, "?@_");
+ extName = extName.substr(0, extName.find('@'));
break;
}
- this->Hdr = Hdr;
- ExternalName = ExtName;
+ this->hdr = hdr;
+ externalName = extName;
- ImpSym = Symtab->addImportData(ImpName, this);
+ impSym = symtab->addImportData(impName, this);
// If this was a duplicate, we logged an error but may continue;
// in this case, ImpSym is nullptr.
- if (!ImpSym)
+ if (!impSym)
return;
- if (Hdr->getType() == llvm::COFF::IMPORT_CONST)
- static_cast<void>(Symtab->addImportData(Name, this));
+ if (hdr->getType() == llvm::COFF::IMPORT_CONST)
+ static_cast<void>(symtab->addImportData(name, this));
// If type is function, we need to create a thunk which jump to an
// address pointed by the __imp_ symbol. (This allows you to call
// DLL functions just like regular non-DLL functions.)
- if (Hdr->getType() == llvm::COFF::IMPORT_CODE)
- ThunkSym = Symtab->addImportThunk(
- Name, cast_or_null<DefinedImportData>(ImpSym), Hdr->Machine);
+ if (hdr->getType() == llvm::COFF::IMPORT_CODE)
+ thunkSym = symtab->addImportThunk(
+ name, cast_or_null<DefinedImportData>(impSym), hdr->Machine);
}
-BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
- uint64_t OffsetInArchive)
- : InputFile(BitcodeKind, MB) {
- std::string Path = MB.getBufferIdentifier().str();
+BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
+ uint64_t offsetInArchive)
+ : InputFile(BitcodeKind, mb) {
+ std::string path = mb.getBufferIdentifier().str();
// ThinLTO assumes that all MemoryBufferRefs given to it have a unique
// name. If two archives define two members with the same name, this
// into consideration at LTO time (which very likely causes undefined
// symbols later in the link stage). So we append file offset to make
// filename unique.
- MemoryBufferRef MBRef(
- MB.getBuffer(),
- Saver.save(ArchiveName + Path +
- (ArchiveName.empty() ? "" : utostr(OffsetInArchive))));
+ MemoryBufferRef mbref(
+ mb.getBuffer(),
+ saver.save(archiveName + path +
+ (archiveName.empty() ? "" : utostr(offsetInArchive))));
- Obj = check(lto::InputFile::create(MBRef));
+ obj = check(lto::InputFile::create(mbref));
}
void BitcodeFile::parse() {
- std::vector<std::pair<Symbol *, bool>> Comdat(Obj->getComdatTable().size());
- for (size_t I = 0; I != Obj->getComdatTable().size(); ++I)
+ std::vector<std::pair<Symbol *, bool>> comdat(obj->getComdatTable().size());
+ for (size_t i = 0; i != obj->getComdatTable().size(); ++i)
// FIXME: lto::InputFile doesn't keep enough data to do correct comdat
// selection handling.
- Comdat[I] = Symtab->addComdat(this, Saver.save(Obj->getComdatTable()[I]));
- for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) {
- StringRef SymName = Saver.save(ObjSym.getName());
- int ComdatIndex = ObjSym.getComdatIndex();
- Symbol *Sym;
- if (ObjSym.isUndefined()) {
- Sym = Symtab->addUndefined(SymName, this, false);
- } else if (ObjSym.isCommon()) {
- Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize());
- } else if (ObjSym.isWeak() && ObjSym.isIndirect()) {
+ comdat[i] = symtab->addComdat(this, saver.save(obj->getComdatTable()[i]));
+ for (const lto::InputFile::Symbol &objSym : obj->symbols()) {
+ StringRef symName = saver.save(objSym.getName());
+ int comdatIndex = objSym.getComdatIndex();
+ Symbol *sym;
+ if (objSym.isUndefined()) {
+ sym = symtab->addUndefined(symName, this, false);
+ } else if (objSym.isCommon()) {
+ sym = symtab->addCommon(this, symName, objSym.getCommonSize());
+ } else if (objSym.isWeak() && objSym.isIndirect()) {
// Weak external.
- Sym = Symtab->addUndefined(SymName, this, true);
- std::string Fallback = ObjSym.getCOFFWeakExternalFallback();
- Symbol *Alias = Symtab->addUndefined(Saver.save(Fallback));
- checkAndSetWeakAlias(Symtab, this, Sym, Alias);
- } else if (ComdatIndex != -1) {
- if (SymName == Obj->getComdatTable()[ComdatIndex])
- Sym = Comdat[ComdatIndex].first;
- else if (Comdat[ComdatIndex].second)
- Sym = Symtab->addRegular(this, SymName);
+ sym = symtab->addUndefined(symName, this, true);
+ std::string fallback = objSym.getCOFFWeakExternalFallback();
+ Symbol *alias = symtab->addUndefined(saver.save(fallback));
+ checkAndSetWeakAlias(symtab, this, sym, alias);
+ } else if (comdatIndex != -1) {
+ if (symName == obj->getComdatTable()[comdatIndex])
+ sym = comdat[comdatIndex].first;
+ else if (comdat[comdatIndex].second)
+ sym = symtab->addRegular(this, symName);
else
- Sym = Symtab->addUndefined(SymName, this, false);
+ sym = symtab->addUndefined(symName, this, false);
} else {
- Sym = Symtab->addRegular(this, SymName);
+ sym = symtab->addRegular(this, symName);
}
- Symbols.push_back(Sym);
- if (ObjSym.isUsed())
- Config->GCRoot.push_back(Sym);
+ symbols.push_back(sym);
+ if (objSym.isUsed())
+ config->gCRoot.push_back(sym);
}
- Directives = Obj->getCOFFLinkerOpts();
+ directives = obj->getCOFFLinkerOpts();
}
MachineTypes BitcodeFile::getMachineType() {
- switch (Triple(Obj->getTargetTriple()).getArch()) {
+ switch (Triple(obj->getTargetTriple()).getArch()) {
case Triple::x86_64:
return AMD64;
case Triple::x86:
} // namespace lld
// Returns the last element of a path, which is supposed to be a filename.
-static StringRef getBasename(StringRef Path) {
- return sys::path::filename(Path, sys::path::Style::windows);
+static StringRef getBasename(StringRef path) {
+ return sys::path::filename(path, sys::path::Style::windows);
}
// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)".
-std::string lld::toString(const coff::InputFile *File) {
- if (!File)
+std::string lld::toString(const coff::InputFile *file) {
+ if (!file)
return "<internal>";
- if (File->ParentName.empty() || File->kind() == coff::InputFile::ImportKind)
- return File->getName();
+ if (file->parentName.empty() || file->kind() == coff::InputFile::ImportKind)
+ return file->getName();
- return (getBasename(File->ParentName) + "(" + getBasename(File->getName()) +
+ return (getBasename(file->parentName) + "(" + getBasename(file->getName()) +
")")
.str();
}
namespace lld {
namespace coff {
-std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *File);
+std::vector<MemoryBufferRef> getArchiveMembers(llvm::object::Archive *file);
using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
using llvm::COFF::MachineTypes;
class InputFile {
public:
enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
- Kind kind() const { return FileKind; }
+ Kind kind() const { return fileKind; }
virtual ~InputFile() {}
// Returns the filename.
- StringRef getName() const { return MB.getBufferIdentifier(); }
+ StringRef getName() const { return mb.getBufferIdentifier(); }
// Reads a file (the constructor doesn't do that).
virtual void parse() = 0;
// Returns the CPU type this file was compiled to.
virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; }
- MemoryBufferRef MB;
+ MemoryBufferRef mb;
// An archive file name if this file is created from an archive.
- StringRef ParentName;
+ StringRef parentName;
// Returns .drectve section contents if exist.
- StringRef getDirectives() { return Directives; }
+ StringRef getDirectives() { return directives; }
protected:
- InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+ InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {}
- StringRef Directives;
+ StringRef directives;
private:
- const Kind FileKind;
+ const Kind fileKind;
};
// .lib or .a file.
class ArchiveFile : public InputFile {
public:
- explicit ArchiveFile(MemoryBufferRef M);
- static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+ explicit ArchiveFile(MemoryBufferRef m);
+ static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
void parse() override;
// Enqueues an archive member load for the given symbol. If we've already
// enqueued a load for the same archive member, this function does nothing,
// which ensures that we don't load the same member more than once.
- void addMember(const Archive::Symbol *Sym);
+ void addMember(const Archive::Symbol *sym);
private:
- std::unique_ptr<Archive> File;
- llvm::DenseSet<uint64_t> Seen;
+ std::unique_ptr<Archive> file;
+ llvm::DenseSet<uint64_t> seen;
};
// .obj or .o file. This may be a member of an archive file.
class ObjFile : public InputFile {
public:
- explicit ObjFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {}
- static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
+ explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}
+ static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
void parse() override;
MachineTypes getMachineType() override;
- ArrayRef<Chunk *> getChunks() { return Chunks; }
- ArrayRef<SectionChunk *> getDebugChunks() { return DebugChunks; }
- ArrayRef<SectionChunk *> getSXDataChunks() { return SXDataChunks; }
- ArrayRef<SectionChunk *> getGuardFidChunks() { return GuardFidChunks; }
- ArrayRef<SectionChunk *> getGuardLJmpChunks() { return GuardLJmpChunks; }
- ArrayRef<Symbol *> getSymbols() { return Symbols; }
+ ArrayRef<Chunk *> getChunks() { return chunks; }
+ ArrayRef<SectionChunk *> getDebugChunks() { return debugChunks; }
+ ArrayRef<SectionChunk *> getSXDataChunks() { return sXDataChunks; }
+ ArrayRef<SectionChunk *> getGuardFidChunks() { return guardFidChunks; }
+ ArrayRef<SectionChunk *> getGuardLJmpChunks() { return guardLJmpChunks; }
+ ArrayRef<Symbol *> getSymbols() { return symbols; }
- ArrayRef<uint8_t> getDebugSection(StringRef SecName);
+ ArrayRef<uint8_t> getDebugSection(StringRef secName);
// Returns a Symbol object for the SymbolIndex'th symbol in the
// underlying object file.
- Symbol *getSymbol(uint32_t SymbolIndex) {
- return Symbols[SymbolIndex];
+ Symbol *getSymbol(uint32_t symbolIndex) {
+ return symbols[symbolIndex];
}
// Returns the underlying COFF file.
- COFFObjectFile *getCOFFObj() { return COFFObj.get(); }
+ COFFObjectFile *getCOFFObj() { return coffObj.get(); }
// Add a symbol for a range extension thunk. Return the new symbol table
// index. This index can be used to modify a relocation.
- uint32_t addRangeThunkSymbol(Symbol *Thunk) {
- Symbols.push_back(Thunk);
- return Symbols.size() - 1;
+ uint32_t addRangeThunkSymbol(Symbol *thunk) {
+ symbols.push_back(thunk);
+ return symbols.size() - 1;
}
- static std::vector<ObjFile *> Instances;
+ static std::vector<ObjFile *> instances;
// Flags in the absolute @feat.00 symbol if it is present. These usually
// indicate if an object was compiled with certain security features enabled
// like stack guard, safeseh, /guard:cf, or other things.
- uint32_t Feat00Flags = 0;
+ uint32_t feat00Flags = 0;
// True if this object file is compatible with SEH. COFF-specific and
// x86-only. COFF spec 5.10.1. The .sxdata section.
- bool hasSafeSEH() { return Feat00Flags & 0x1; }
+ bool hasSafeSEH() { return feat00Flags & 0x1; }
// True if this file was compiled with /guard:cf.
- bool hasGuardCF() { return Feat00Flags & 0x800; }
+ bool hasGuardCF() { return feat00Flags & 0x800; }
// Pointer to the PDB module descriptor builder. Various debug info records
// will reference object files by "module index", which is here. Things like
// source files and section contributions are also recorded here. Will be null
// if we are not producing a PDB.
- llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr;
+ llvm::pdb::DbiModuleDescriptorBuilder *moduleDBI = nullptr;
- const coff_section *AddrsigSec = nullptr;
+ const coff_section *addrsigSec = nullptr;
// When using Microsoft precompiled headers, this is the PCH's key.
// The same key is used by both the precompiled object, and objects using the
// precompiled object. Any difference indicates out-of-date objects.
- llvm::Optional<uint32_t> PCHSignature;
+ llvm::Optional<uint32_t> pchSignature;
// Whether this is an object file created from .res files.
- bool IsResourceObjFile = false;
+ bool isResourceObjFile = false;
// Whether this file was compiled with /hotpatch.
- bool HotPatchable = false;
+ bool hotPatchable = false;
// Whether the object was already merged into the final PDB.
- bool MergedIntoPDB = false;
+ bool mergedIntoPDB = false;
// If the OBJ has a .debug$T stream, this tells how it will be handled.
- TpiSource *DebugTypesObj = nullptr;
+ TpiSource *debugTypesObj = nullptr;
// The .debug$T stream if there's one.
- llvm::Optional<llvm::codeview::CVTypeArray> DebugTypes;
+ llvm::Optional<llvm::codeview::CVTypeArray> debugTypes;
private:
- const coff_section* getSection(uint32_t I);
- const coff_section *getSection(COFFSymbolRef Sym) {
- return getSection(Sym.getSectionNumber());
+ const coff_section* getSection(uint32_t i);
+ const coff_section *getSection(COFFSymbolRef sym) {
+ return getSection(sym.getSectionNumber());
}
void initializeChunks();
void initializeDependencies();
SectionChunk *
- readSection(uint32_t SectionNumber,
- const llvm::object::coff_aux_section_definition *Def,
- StringRef LeaderName);
+ readSection(uint32_t sectionNumber,
+ const llvm::object::coff_aux_section_definition *def,
+ StringRef leaderName);
void readAssociativeDefinition(
- COFFSymbolRef COFFSym,
- const llvm::object::coff_aux_section_definition *Def);
+ COFFSymbolRef coffSym,
+ const llvm::object::coff_aux_section_definition *def);
void readAssociativeDefinition(
- COFFSymbolRef COFFSym,
- const llvm::object::coff_aux_section_definition *Def,
- uint32_t ParentSection);
+ COFFSymbolRef coffSym,
+ const llvm::object::coff_aux_section_definition *def,
+ uint32_t parentSection);
void recordPrevailingSymbolForMingw(
- COFFSymbolRef COFFSym,
- llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap);
+ COFFSymbolRef coffSym,
+ llvm::DenseMap<StringRef, uint32_t> &prevailingSectionMap);
void maybeAssociateSEHForMingw(
- COFFSymbolRef Sym, const llvm::object::coff_aux_section_definition *Def,
- const llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap);
+ COFFSymbolRef sym, const llvm::object::coff_aux_section_definition *def,
+ const llvm::DenseMap<StringRef, uint32_t> &prevailingSectionMap);
// Given a new symbol Sym with comdat selection Selection, if the new
// symbol is not (yet) Prevailing and the existing comdat leader set to
// match the existing symbol and its selection. If either old or new
// symbol have selection IMAGE_COMDAT_SELECT_LARGEST, Sym might replace
// the existing leader. In that case, Prevailing is set to true.
- void handleComdatSelection(COFFSymbolRef Sym,
- llvm::COFF::COMDATType &Selection,
- bool &Prevailing, DefinedRegular *Leader);
+ void handleComdatSelection(COFFSymbolRef sym,
+ llvm::COFF::COMDATType &selection,
+ bool &prevailing, DefinedRegular *leader);
llvm::Optional<Symbol *>
- createDefined(COFFSymbolRef Sym,
+ createDefined(COFFSymbolRef sym,
std::vector<const llvm::object::coff_aux_section_definition *>
- &ComdatDefs,
- bool &PrevailingComdat);
- Symbol *createRegular(COFFSymbolRef Sym);
- Symbol *createUndefined(COFFSymbolRef Sym);
+ &comdatDefs,
+ bool &prevailingComdat);
+ Symbol *createRegular(COFFSymbolRef sym);
+ Symbol *createUndefined(COFFSymbolRef sym);
- std::unique_ptr<COFFObjectFile> COFFObj;
+ std::unique_ptr<COFFObjectFile> coffObj;
// List of all chunks defined by this file. This includes both section
// chunks and non-section chunks for common symbols.
- std::vector<Chunk *> Chunks;
+ std::vector<Chunk *> chunks;
// CodeView debug info sections.
- std::vector<SectionChunk *> DebugChunks;
+ std::vector<SectionChunk *> debugChunks;
// Chunks containing symbol table indices of exception handlers. Only used for
// 32-bit x86.
- std::vector<SectionChunk *> SXDataChunks;
+ std::vector<SectionChunk *> sXDataChunks;
// Chunks containing symbol table indices of address taken symbols and longjmp
// targets. These are not linked into the final binary when /guard:cf is set.
- std::vector<SectionChunk *> GuardFidChunks;
- std::vector<SectionChunk *> GuardLJmpChunks;
+ std::vector<SectionChunk *> guardFidChunks;
+ std::vector<SectionChunk *> guardLJmpChunks;
// This vector contains the same chunks as Chunks, but they are
// indexed such that you can get a SectionChunk by section index.
// Nonexistent section indices are filled with null pointers.
// (Because section number is 1-based, the first slot is always a
// null pointer.)
- std::vector<SectionChunk *> SparseChunks;
+ std::vector<SectionChunk *> sparseChunks;
// This vector contains a list of all symbols defined or referenced by this
// file. They are indexed such that you can get a Symbol by symbol
// index. Nonexistent indices (which are occupied by auxiliary
// symbols in the real symbol table) are filled with null pointers.
- std::vector<Symbol *> Symbols;
+ std::vector<Symbol *> symbols;
};
// This type represents import library members that contain DLL names
// for details about the format.
class ImportFile : public InputFile {
public:
- explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {}
+ explicit ImportFile(MemoryBufferRef m) : InputFile(ImportKind, m) {}
- static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
+ static bool classof(const InputFile *f) { return f->kind() == ImportKind; }
- static std::vector<ImportFile *> Instances;
+ static std::vector<ImportFile *> instances;
- Symbol *ImpSym = nullptr;
- Symbol *ThunkSym = nullptr;
- std::string DLLName;
+ Symbol *impSym = nullptr;
+ Symbol *thunkSym = nullptr;
+ std::string dllName;
private:
void parse() override;
public:
- StringRef ExternalName;
- const coff_import_header *Hdr;
- Chunk *Location = nullptr;
+ StringRef externalName;
+ const coff_import_header *hdr;
+ Chunk *location = nullptr;
// We want to eliminate dllimported symbols if no one actually refers them.
// These "Live" bits are used to keep track of which import library members
// symbols provided by this import library member. We also track whether the
// imported symbol is used separately from whether the thunk is used in order
// to avoid creating unnecessary thunks.
- bool Live = !Config->DoGC;
- bool ThunkLive = !Config->DoGC;
+ bool live = !config->doGC;
+ bool thunkLive = !config->doGC;
};
// Used for LTO.
class BitcodeFile : public InputFile {
public:
- BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
- uint64_t OffsetInArchive);
- static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
- ArrayRef<Symbol *> getSymbols() { return Symbols; }
+ BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
+ uint64_t offsetInArchive);
+ static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
+ ArrayRef<Symbol *> getSymbols() { return symbols; }
MachineTypes getMachineType() override;
- static std::vector<BitcodeFile *> Instances;
- std::unique_ptr<llvm::lto::InputFile> Obj;
+ static std::vector<BitcodeFile *> instances;
+ std::unique_ptr<llvm::lto::InputFile> obj;
private:
void parse() override;
- std::vector<Symbol *> Symbols;
+ std::vector<Symbol *> symbols;
};
} // namespace coff
-std::string toString(const coff::InputFile *File);
+std::string toString(const coff::InputFile *file);
} // namespace lld
#endif
using namespace lld::coff;
static std::unique_ptr<lto::LTO> createLTO() {
- lto::Config C;
- C.Options = initTargetOptionsFromCodeGenFlags();
+ lto::Config c;
+ c.Options = initTargetOptionsFromCodeGenFlags();
// Always emit a section per function/datum with LTO. LLVM LTO should get most
// of the benefit of linker GC, but there are still opportunities for ICF.
- C.Options.FunctionSections = true;
- C.Options.DataSections = true;
+ c.Options.FunctionSections = true;
+ c.Options.DataSections = true;
// Use static reloc model on 32-bit x86 because it usually results in more
// compact code, and because there are also known code generation bugs when
// using the PIC model (see PR34306).
- if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386)
- C.RelocModel = Reloc::Static;
+ if (config->machine == COFF::IMAGE_FILE_MACHINE_I386)
+ c.RelocModel = Reloc::Static;
else
- C.RelocModel = Reloc::PIC_;
- C.DisableVerify = true;
- C.DiagHandler = diagnosticHandler;
- C.OptLevel = Config->LTOO;
- C.CPU = getCPUStr();
- C.MAttrs = getMAttrs();
- C.CGOptLevel = args::getCGOptLevel(Config->LTOO);
-
- if (Config->SaveTemps)
- checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".",
+ c.RelocModel = Reloc::PIC_;
+ c.DisableVerify = true;
+ c.DiagHandler = diagnosticHandler;
+ c.OptLevel = config->ltoo;
+ c.CPU = getCPUStr();
+ c.MAttrs = getMAttrs();
+ c.CGOptLevel = args::getCGOptLevel(config->ltoo);
+
+ if (config->saveTemps)
+ checkError(c.addSaveTemps(std::string(config->outputFile) + ".",
/*UseInputModulePath*/ true));
- lto::ThinBackend Backend;
- if (Config->ThinLTOJobs != 0)
- Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
- return llvm::make_unique<lto::LTO>(std::move(C), Backend,
- Config->LTOPartitions);
+ lto::ThinBackend backend;
+ if (config->thinLTOJobs != 0)
+ backend = lto::createInProcessThinBackend(config->thinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(c), backend,
+ config->ltoPartitions);
}
-BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+BitcodeCompiler::BitcodeCompiler() : ltoObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
-static void undefine(Symbol *S) { replaceSymbol<Undefined>(S, S->getName()); }
+static void undefine(Symbol *s) { replaceSymbol<Undefined>(s, s->getName()); }
-void BitcodeCompiler::add(BitcodeFile &F) {
- lto::InputFile &Obj = *F.Obj;
- unsigned SymNum = 0;
- std::vector<Symbol *> SymBodies = F.getSymbols();
- std::vector<lto::SymbolResolution> Resols(SymBodies.size());
+void BitcodeCompiler::add(BitcodeFile &f) {
+ lto::InputFile &obj = *f.obj;
+ unsigned symNum = 0;
+ std::vector<Symbol *> symBodies = f.getSymbols();
+ std::vector<lto::SymbolResolution> resols(symBodies.size());
// Provide a resolution to the LTO API for each symbol.
- for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
- Symbol *Sym = SymBodies[SymNum];
- lto::SymbolResolution &R = Resols[SymNum];
- ++SymNum;
+ for (const lto::InputFile::Symbol &objSym : obj.symbols()) {
+ Symbol *sym = symBodies[symNum];
+ lto::SymbolResolution &r = resols[symNum];
+ ++symNum;
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
// reports two symbols for module ASM defined. Without this check, lld
// flags an undefined in IR with a definition in ASM as prevailing.
// Once IRObjectFile is fixed to report only one symbol this hack can
// be removed.
- R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F;
- R.VisibleToRegularObj = Sym->IsUsedInRegularObj;
- if (R.Prevailing)
- undefine(Sym);
+ r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
+ r.VisibleToRegularObj = sym->isUsedInRegularObj;
+ if (r.Prevailing)
+ undefine(sym);
}
- checkError(LTOObj->add(std::move(F.Obj), Resols));
+ checkError(ltoObj->add(std::move(f.obj), resols));
}
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() {
- unsigned MaxTasks = LTOObj->getMaxTasks();
- Buf.resize(MaxTasks);
- Files.resize(MaxTasks);
+ unsigned maxTasks = ltoObj->getMaxTasks();
+ buf.resize(maxTasks);
+ files.resize(maxTasks);
// The /lldltocache option specifies the path to a directory in which to cache
// native object files for ThinLTO incremental builds. If a path was
// specified, configure LTO to use it as the cache directory.
- lto::NativeObjectCache Cache;
- if (!Config->LTOCache.empty())
- Cache = check(lto::localCache(
- Config->LTOCache, [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
- Files[Task] = std::move(MB);
+ lto::NativeObjectCache cache;
+ if (!config->ltoCache.empty())
+ cache = check(lto::localCache(
+ config->ltoCache, [&](size_t task, std::unique_ptr<MemoryBuffer> mb) {
+ files[task] = std::move(mb);
}));
- checkError(LTOObj->run(
- [&](size_t Task) {
+ checkError(ltoObj->run(
+ [&](size_t task) {
return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buf[Task]));
+ llvm::make_unique<raw_svector_ostream>(buf[task]));
},
- Cache));
+ cache));
- if (!Config->LTOCache.empty())
- pruneCache(Config->LTOCache, Config->LTOCachePolicy);
+ if (!config->ltoCache.empty())
+ pruneCache(config->ltoCache, config->ltoCachePolicy);
- std::vector<StringRef> Ret;
- for (unsigned I = 0; I != MaxTasks; ++I) {
- if (Buf[I].empty())
+ std::vector<StringRef> ret;
+ for (unsigned i = 0; i != maxTasks; ++i) {
+ if (buf[i].empty())
continue;
- if (Config->SaveTemps) {
- if (I == 0)
- saveBuffer(Buf[I], Config->OutputFile + ".lto.obj");
+ if (config->saveTemps) {
+ if (i == 0)
+ saveBuffer(buf[i], config->outputFile + ".lto.obj");
else
- saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj");
+ saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.obj");
}
- Ret.emplace_back(Buf[I].data(), Buf[I].size());
+ ret.emplace_back(buf[i].data(), buf[i].size());
}
- for (std::unique_ptr<MemoryBuffer> &File : Files)
- if (File)
- Ret.push_back(File->getBuffer());
+ for (std::unique_ptr<MemoryBuffer> &file : files)
+ if (file)
+ ret.push_back(file->getBuffer());
- return Ret;
+ return ret;
}
BitcodeCompiler();
~BitcodeCompiler();
- void add(BitcodeFile &F);
+ void add(BitcodeFile &f);
std::vector<StringRef> compile();
private:
- std::unique_ptr<llvm::lto::LTO> LTOObj;
- std::vector<SmallString<0>> Buf;
- std::vector<std::unique_ptr<MemoryBuffer>> Files;
+ std::unique_ptr<llvm::lto::LTO> ltoObj;
+ std::vector<SmallString<0>> buf;
+ std::vector<std::unique_ptr<MemoryBuffer>> files;
};
}
}
using SymbolMapTy =
DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>;
-static const std::string Indent8 = " "; // 8 spaces
-static const std::string Indent16 = " "; // 16 spaces
+static const std::string indent8 = " "; // 8 spaces
+static const std::string indent16 = " "; // 16 spaces
// Print out the first three columns of a line.
-static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size,
- uint64_t Align) {
- OS << format("%08llx %08llx %5lld ", Addr, Size, Align);
+static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size,
+ uint64_t align) {
+ os << format("%08llx %08llx %5lld ", addr, size, align);
}
// Returns a list of all symbols that we want to print out.
static std::vector<DefinedRegular *> getSymbols() {
- std::vector<DefinedRegular *> V;
- for (ObjFile *File : ObjFile::Instances)
- for (Symbol *B : File->getSymbols())
- if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
- if (Sym && !Sym->getCOFFSymbol().isSectionDefinition())
- V.push_back(Sym);
- return V;
+ std::vector<DefinedRegular *> v;
+ for (ObjFile *file : ObjFile::instances)
+ for (Symbol *b : file->getSymbols())
+ if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
+ if (sym && !sym->getCOFFSymbol().isSectionDefinition())
+ v.push_back(sym);
+ return v;
}
// Returns a map from sections to their symbols.
-static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) {
- SymbolMapTy Ret;
- for (DefinedRegular *S : Syms)
- Ret[S->getChunk()].push_back(S);
+static SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> syms) {
+ SymbolMapTy ret;
+ for (DefinedRegular *s : syms)
+ ret[s->getChunk()].push_back(s);
// Sort symbols by address.
- for (auto &It : Ret) {
- SmallVectorImpl<DefinedRegular *> &V = It.second;
- std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) {
- return A->getRVA() < B->getRVA();
+ for (auto &it : ret) {
+ SmallVectorImpl<DefinedRegular *> &v = it.second;
+ std::sort(v.begin(), v.end(), [](DefinedRegular *a, DefinedRegular *b) {
+ return a->getRVA() < b->getRVA();
});
}
- return Ret;
+ return ret;
}
// Construct a map from symbols to their stringified representations.
static DenseMap<DefinedRegular *, std::string>
-getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
- std::vector<std::string> Str(Syms.size());
- parallelForEachN((size_t)0, Syms.size(), [&](size_t I) {
- raw_string_ostream OS(Str[I]);
- writeHeader(OS, Syms[I]->getRVA(), 0, 0);
- OS << Indent16 << toString(*Syms[I]);
+getSymbolStrings(ArrayRef<DefinedRegular *> syms) {
+ std::vector<std::string> str(syms.size());
+ parallelForEachN((size_t)0, syms.size(), [&](size_t i) {
+ raw_string_ostream os(str[i]);
+ writeHeader(os, syms[i]->getRVA(), 0, 0);
+ os << indent16 << toString(*syms[i]);
});
- DenseMap<DefinedRegular *, std::string> Ret;
- for (size_t I = 0, E = Syms.size(); I < E; ++I)
- Ret[Syms[I]] = std::move(Str[I]);
- return Ret;
+ DenseMap<DefinedRegular *, std::string> ret;
+ for (size_t i = 0, e = syms.size(); i < e; ++i)
+ ret[syms[i]] = std::move(str[i]);
+ return ret;
}
-void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
- if (Config->MapFile.empty())
+void coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
+ if (config->mapFile.empty())
return;
- std::error_code EC;
- raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
- if (EC)
- fatal("cannot open " + Config->MapFile + ": " + EC.message());
+ std::error_code ec;
+ raw_fd_ostream os(config->mapFile, ec, sys::fs::F_None);
+ if (ec)
+ fatal("cannot open " + config->mapFile + ": " + ec.message());
// Collect symbol info that we want to print out.
- std::vector<DefinedRegular *> Syms = getSymbols();
- SymbolMapTy SectionSyms = getSectionSyms(Syms);
- DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings(Syms);
+ std::vector<DefinedRegular *> syms = getSymbols();
+ SymbolMapTy sectionSyms = getSectionSyms(syms);
+ DenseMap<DefinedRegular *, std::string> symStr = getSymbolStrings(syms);
// Print out the header line.
- OS << "Address Size Align Out In Symbol\n";
+ os << "Address Size Align Out In Symbol\n";
// Print out file contents.
- for (OutputSection *Sec : OutputSections) {
- writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize);
- OS << Sec->Name << '\n';
+ for (OutputSection *sec : outputSections) {
+ writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*Align=*/pageSize);
+ os << sec->name << '\n';
- for (Chunk *C : Sec->Chunks) {
- auto *SC = dyn_cast<SectionChunk>(C);
- if (!SC)
+ for (Chunk *c : sec->chunks) {
+ auto *sc = dyn_cast<SectionChunk>(c);
+ if (!sc)
continue;
- writeHeader(OS, SC->getRVA(), SC->getSize(), SC->getAlignment());
- OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName()
+ writeHeader(os, sc->getRVA(), sc->getSize(), sc->getAlignment());
+ os << indent8 << sc->file->getName() << ":(" << sc->getSectionName()
<< ")\n";
- for (DefinedRegular *Sym : SectionSyms[SC])
- OS << SymStr[Sym] << '\n';
+ for (DefinedRegular *sym : sectionSyms[sc])
+ os << symStr[sym] << '\n';
}
}
}
namespace lld {
namespace coff {
class OutputSection;
-void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
+void writeMapFile(llvm::ArrayRef<OutputSection *> outputSections);
}
}
namespace lld {
namespace coff {
-static Timer GCTimer("GC", Timer::root());
+static Timer gCTimer("GC", Timer::root());
// Set live bit on for each reachable chunk. Unmarked (unreachable)
// COMDAT chunks will be ignored by Writer, so they will be excluded
// from the final output.
-void markLive(ArrayRef<Chunk *> Chunks) {
- ScopedTimer T(GCTimer);
+void markLive(ArrayRef<Chunk *> chunks) {
+ ScopedTimer t(gCTimer);
// We build up a worklist of sections which have been marked as live. We only
// push into the worklist when we discover an unmarked section, and we mark
// as we push, so sections never appear twice in the list.
- SmallVector<SectionChunk *, 256> Worklist;
+ SmallVector<SectionChunk *, 256> worklist;
// COMDAT section chunks are dead by default. Add non-COMDAT chunks.
- for (Chunk *C : Chunks)
- if (auto *SC = dyn_cast<SectionChunk>(C))
- if (SC->Live)
- Worklist.push_back(SC);
+ for (Chunk *c : chunks)
+ if (auto *sc = dyn_cast<SectionChunk>(c))
+ if (sc->live)
+ worklist.push_back(sc);
- auto Enqueue = [&](SectionChunk *C) {
- if (C->Live)
+ auto enqueue = [&](SectionChunk *c) {
+ if (c->live)
return;
- C->Live = true;
- Worklist.push_back(C);
+ c->live = true;
+ worklist.push_back(c);
};
- auto AddSym = [&](Symbol *B) {
- if (auto *Sym = dyn_cast<DefinedRegular>(B))
- Enqueue(Sym->getChunk());
- else if (auto *Sym = dyn_cast<DefinedImportData>(B))
- Sym->File->Live = true;
- else if (auto *Sym = dyn_cast<DefinedImportThunk>(B))
- Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true;
+ auto addSym = [&](Symbol *b) {
+ if (auto *sym = dyn_cast<DefinedRegular>(b))
+ enqueue(sym->getChunk());
+ else if (auto *sym = dyn_cast<DefinedImportData>(b))
+ sym->file->live = true;
+ else if (auto *sym = dyn_cast<DefinedImportThunk>(b))
+ sym->wrappedSym->file->live = sym->wrappedSym->file->thunkLive = true;
};
// Add GC root chunks.
- for (Symbol *B : Config->GCRoot)
- AddSym(B);
+ for (Symbol *b : config->gCRoot)
+ addSym(b);
- while (!Worklist.empty()) {
- SectionChunk *SC = Worklist.pop_back_val();
- assert(SC->Live && "We mark as live when pushing onto the worklist!");
+ while (!worklist.empty()) {
+ SectionChunk *sc = worklist.pop_back_val();
+ assert(sc->live && "We mark as live when pushing onto the worklist!");
// Mark all symbols listed in the relocation table for this section.
- for (Symbol *B : SC->symbols())
- if (B)
- AddSym(B);
+ for (Symbol *b : sc->symbols())
+ if (b)
+ addSym(b);
// Mark associative sections if any.
- for (SectionChunk &C : SC->children())
- Enqueue(&C);
+ for (SectionChunk &c : sc->children())
+ enqueue(&c);
}
}
class Chunk;
-void markLive(ArrayRef<Chunk *> Chunks);
+void markLive(ArrayRef<Chunk *> chunks);
} // namespace coff
} // namespace lld
using namespace llvm::COFF;
AutoExporter::AutoExporter() {
- ExcludeLibs = {
+ excludeLibs = {
"libgcc",
"libgcc_s",
"libstdc++",
"libucrtbase",
};
- ExcludeObjects = {
+ excludeObjects = {
"crt0.o", "crt1.o", "crt1u.o", "crt2.o", "crt2u.o", "dllcrt1.o",
"dllcrt2.o", "gcrt0.o", "gcrt1.o", "gcrt2.o", "crtbegin.o", "crtend.o",
};
- ExcludeSymbolPrefixes = {
+ excludeSymbolPrefixes = {
// Import symbols
"__imp_",
"__IMPORT_DESCRIPTOR_",
".",
};
- ExcludeSymbolSuffixes = {
+ excludeSymbolSuffixes = {
"_iname",
"_NULL_THUNK_DATA",
};
- if (Config->Machine == I386) {
- ExcludeSymbols = {
+ if (config->machine == I386) {
+ excludeSymbols = {
"__NULL_IMPORT_DESCRIPTOR",
"__pei386_runtime_relocator",
"_do_pseudo_reloc",
"_DllEntryPoint@12",
"_DllMainCRTStartup@12",
};
- ExcludeSymbolPrefixes.insert("__head_");
+ excludeSymbolPrefixes.insert("__head_");
} else {
- ExcludeSymbols = {
+ excludeSymbols = {
"__NULL_IMPORT_DESCRIPTOR",
"_pei386_runtime_relocator",
"do_pseudo_reloc",
"DllEntryPoint",
"DllMainCRTStartup",
};
- ExcludeSymbolPrefixes.insert("_head_");
+ excludeSymbolPrefixes.insert("_head_");
}
}
-void AutoExporter::addWholeArchive(StringRef Path) {
- StringRef LibName = sys::path::filename(Path);
+void AutoExporter::addWholeArchive(StringRef path) {
+ StringRef libName = sys::path::filename(path);
// Drop the file extension, to match the processing below.
- LibName = LibName.substr(0, LibName.rfind('.'));
- ExcludeLibs.erase(LibName);
+ libName = libName.substr(0, libName.rfind('.'));
+ excludeLibs.erase(libName);
}
-bool AutoExporter::shouldExport(Defined *Sym) const {
- if (!Sym || !Sym->isLive() || !Sym->getChunk())
+bool AutoExporter::shouldExport(Defined *sym) const {
+ if (!sym || !sym->isLive() || !sym->getChunk())
return false;
// Only allow the symbol kinds that make sense to export; in particular,
// disallow import symbols.
- if (!isa<DefinedRegular>(Sym) && !isa<DefinedCommon>(Sym))
+ if (!isa<DefinedRegular>(sym) && !isa<DefinedCommon>(sym))
return false;
- if (ExcludeSymbols.count(Sym->getName()))
+ if (excludeSymbols.count(sym->getName()))
return false;
- for (StringRef Prefix : ExcludeSymbolPrefixes.keys())
- if (Sym->getName().startswith(Prefix))
+ for (StringRef prefix : excludeSymbolPrefixes.keys())
+ if (sym->getName().startswith(prefix))
return false;
- for (StringRef Suffix : ExcludeSymbolSuffixes.keys())
- if (Sym->getName().endswith(Suffix))
+ for (StringRef suffix : excludeSymbolSuffixes.keys())
+ if (sym->getName().endswith(suffix))
return false;
// If a corresponding __imp_ symbol exists and is defined, don't export it.
- if (Symtab->find(("__imp_" + Sym->getName()).str()))
+ if (symtab->find(("__imp_" + sym->getName()).str()))
return false;
// Check that file is non-null before dereferencing it, symbols not
// originating in regular object files probably shouldn't be exported.
- if (!Sym->getFile())
+ if (!sym->getFile())
return false;
- StringRef LibName = sys::path::filename(Sym->getFile()->ParentName);
+ StringRef libName = sys::path::filename(sym->getFile()->parentName);
// Drop the file extension.
- LibName = LibName.substr(0, LibName.rfind('.'));
- if (!LibName.empty())
- return !ExcludeLibs.count(LibName);
+ libName = libName.substr(0, libName.rfind('.'));
+ if (!libName.empty())
+ return !excludeLibs.count(libName);
- StringRef FileName = sys::path::filename(Sym->getFile()->getName());
- return !ExcludeObjects.count(FileName);
+ StringRef fileName = sys::path::filename(sym->getFile()->getName());
+ return !excludeObjects.count(fileName);
}
-void coff::writeDefFile(StringRef Name) {
- std::error_code EC;
- raw_fd_ostream OS(Name, EC, sys::fs::F_None);
- if (EC)
- fatal("cannot open " + Name + ": " + EC.message());
-
- OS << "EXPORTS\n";
- for (Export &E : Config->Exports) {
- OS << " " << E.ExportName << " "
- << "@" << E.Ordinal;
- if (auto *Def = dyn_cast_or_null<Defined>(E.Sym)) {
- if (Def && Def->getChunk() &&
- !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
- OS << " DATA";
+void coff::writeDefFile(StringRef name) {
+ std::error_code ec;
+ raw_fd_ostream os(name, ec, sys::fs::F_None);
+ if (ec)
+ fatal("cannot open " + name + ": " + ec.message());
+
+ os << "EXPORTS\n";
+ for (Export &e : config->exports) {
+ os << " " << e.exportName << " "
+ << "@" << e.ordinal;
+ if (auto *def = dyn_cast_or_null<Defined>(e.sym)) {
+ if (def && def->getChunk() &&
+ !(def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
+ os << " DATA";
}
- OS << "\n";
+ os << "\n";
}
}
public:
AutoExporter();
- void addWholeArchive(StringRef Path);
+ void addWholeArchive(StringRef path);
- llvm::StringSet<> ExcludeSymbols;
- llvm::StringSet<> ExcludeSymbolPrefixes;
- llvm::StringSet<> ExcludeSymbolSuffixes;
- llvm::StringSet<> ExcludeLibs;
- llvm::StringSet<> ExcludeObjects;
+ llvm::StringSet<> excludeSymbols;
+ llvm::StringSet<> excludeSymbolPrefixes;
+ llvm::StringSet<> excludeSymbolSuffixes;
+ llvm::StringSet<> excludeLibs;
+ llvm::StringSet<> excludeObjects;
- bool shouldExport(Defined *Sym) const;
+ bool shouldExport(Defined *sym) const;
};
-void writeDefFile(StringRef Name);
+void writeDefFile(StringRef name);
} // namespace coff
} // namespace lld
using llvm::object::coff_section;
-static ExitOnError ExitOnErr;
+static ExitOnError exitOnErr;
-static Timer TotalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root());
+static Timer totalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root());
-static Timer AddObjectsTimer("Add Objects", TotalPdbLinkTimer);
-static Timer TypeMergingTimer("Type Merging", AddObjectsTimer);
-static Timer SymbolMergingTimer("Symbol Merging", AddObjectsTimer);
-static Timer GlobalsLayoutTimer("Globals Stream Layout", TotalPdbLinkTimer);
-static Timer TpiStreamLayoutTimer("TPI Stream Layout", TotalPdbLinkTimer);
-static Timer DiskCommitTimer("Commit to Disk", TotalPdbLinkTimer);
+static Timer addObjectsTimer("Add Objects", totalPdbLinkTimer);
+static Timer typeMergingTimer("Type Merging", addObjectsTimer);
+static Timer symbolMergingTimer("Symbol Merging", addObjectsTimer);
+static Timer globalsLayoutTimer("Globals Stream Layout", totalPdbLinkTimer);
+static Timer tpiStreamLayoutTimer("TPI Stream Layout", totalPdbLinkTimer);
+static Timer diskCommitTimer("Commit to Disk", totalPdbLinkTimer);
namespace {
class DebugSHandler;
friend DebugSHandler;
public:
- PDBLinker(SymbolTable *Symtab)
- : Alloc(), Symtab(Symtab), Builder(Alloc), TMerger(Alloc) {
+ PDBLinker(SymbolTable *symtab)
+ : alloc(), symtab(symtab), builder(alloc), tMerger(alloc) {
// This isn't strictly necessary, but link.exe usually puts an empty string
// as the first "valid" string in the string table, so we do the same in
// order to maintain as much byte-for-byte compatibility as possible.
- PDBStrTab.insert("");
+ pdbStrTab.insert("");
}
/// Emit the basic PDB structure: initial streams, headers, etc.
- void initialize(llvm::codeview::DebugInfo *BuildId);
+ void initialize(llvm::codeview::DebugInfo *buildId);
/// Add natvis files specified on the command line.
void addNatvisFiles();
void addObjectsToPDB();
/// Link info for each import file in the symbol table into the PDB.
- void addImportFilesToPDB(ArrayRef<OutputSection *> OutputSections);
+ void addImportFilesToPDB(ArrayRef<OutputSection *> outputSections);
/// Link CodeView from a single object file into the target (output) PDB.
/// When a precompiled headers object is linked, its TPI map might be provided
/// externally.
- void addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap = nullptr);
+ void addObjFile(ObjFile *file, CVIndexMap *externIndexMap = nullptr);
/// Produce a mapping from the type and item indices used in the object
/// file to those in the destination PDB.
/// If the object does not use a type server PDB (compiled with /Z7), we merge
/// all the type and item records from the .debug$S stream and fill in the
/// caller-provided ObjectIndexMap.
- Expected<const CVIndexMap &> mergeDebugT(ObjFile *File,
- CVIndexMap *ObjectIndexMap);
+ Expected<const CVIndexMap &> mergeDebugT(ObjFile *file,
+ CVIndexMap *objectIndexMap);
/// Reads and makes available a PDB.
- Expected<const CVIndexMap &> maybeMergeTypeServerPDB(ObjFile *File);
+ Expected<const CVIndexMap &> maybeMergeTypeServerPDB(ObjFile *file);
/// Merges a precompiled headers TPI map into the current TPI map. The
/// precompiled headers object will also be loaded and remapped in the
/// process.
- Error mergeInPrecompHeaderObj(ObjFile *File, CVIndexMap *ObjectIndexMap);
+ Error mergeInPrecompHeaderObj(ObjFile *file, CVIndexMap *objectIndexMap);
/// Reads and makes available a precompiled headers object.
///
///
/// If the precompiled headers object was already loaded, this function will
/// simply return its (remapped) TPI map.
- Expected<const CVIndexMap &> aquirePrecompObj(ObjFile *File);
+ Expected<const CVIndexMap &> aquirePrecompObj(ObjFile *file);
/// Adds a precompiled headers object signature -> TPI mapping.
std::pair<CVIndexMap &, bool /*already there*/>
- registerPrecompiledHeaders(uint32_t Signature);
+ registerPrecompiledHeaders(uint32_t signature);
- void mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap,
- std::vector<ulittle32_t *> &StringTableRefs,
- BinaryStreamRef SymData);
+ void mergeSymbolRecords(ObjFile *file, const CVIndexMap &indexMap,
+ std::vector<ulittle32_t *> &stringTableRefs,
+ BinaryStreamRef symData);
/// Add the section map and section contributions to the PDB.
- void addSections(ArrayRef<OutputSection *> OutputSections,
- ArrayRef<uint8_t> SectionTable);
+ void addSections(ArrayRef<OutputSection *> outputSections,
+ ArrayRef<uint8_t> sectionTable);
/// Write the PDB to disk and store the Guid generated for it in *Guid.
- void commit(codeview::GUID *Guid);
+ void commit(codeview::GUID *guid);
// Print statistics regarding the final PDB
void printStats();
private:
- BumpPtrAllocator Alloc;
+ BumpPtrAllocator alloc;
- SymbolTable *Symtab;
+ SymbolTable *symtab;
- pdb::PDBFileBuilder Builder;
+ pdb::PDBFileBuilder builder;
- TypeMerger TMerger;
+ TypeMerger tMerger;
/// PDBs use a single global string table for filenames in the file checksum
/// table.
- DebugStringTableSubsection PDBStrTab;
+ DebugStringTableSubsection pdbStrTab;
- llvm::SmallString<128> NativePath;
+ llvm::SmallString<128> nativePath;
- std::vector<pdb::SecMapEntry> SectionMap;
+ std::vector<pdb::SecMapEntry> sectionMap;
/// Type index mappings of type server PDBs that we've loaded so far.
- std::map<codeview::GUID, CVIndexMap> TypeServerIndexMappings;
+ std::map<codeview::GUID, CVIndexMap> typeServerIndexMappings;
/// Type index mappings of precompiled objects type map that we've loaded so
/// far.
- std::map<uint32_t, CVIndexMap> PrecompTypeIndexMappings;
+ std::map<uint32_t, CVIndexMap> precompTypeIndexMappings;
// For statistics
- uint64_t GlobalSymbols = 0;
- uint64_t ModuleSymbols = 0;
- uint64_t PublicSymbols = 0;
+ uint64_t globalSymbols = 0;
+ uint64_t moduleSymbols = 0;
+ uint64_t publicSymbols = 0;
};
class DebugSHandler {
- PDBLinker &Linker;
+ PDBLinker &linker;
/// The object file whose .debug$S sections we're processing.
- ObjFile &File;
+ ObjFile &file;
/// The result of merging type indices.
- const CVIndexMap &IndexMap;
+ const CVIndexMap &indexMap;
/// The DEBUG_S_STRINGTABLE subsection. These strings are referred to by
/// index from other records in the .debug$S section. All of these strings
/// need to be added to the global PDB string table, and all references to
/// these strings need to have their indices re-written to refer to the
/// global PDB string table.
- DebugStringTableSubsectionRef CVStrTab;
+ DebugStringTableSubsectionRef cVStrTab;
/// The DEBUG_S_FILECHKSMS subsection. As above, these are referred to
/// by other records in the .debug$S section and need to be merged into the
/// PDB.
- DebugChecksumsSubsectionRef Checksums;
+ DebugChecksumsSubsectionRef checksums;
/// The DEBUG_S_INLINEELINES subsection. There can be only one of these per
/// object file.
- DebugInlineeLinesSubsectionRef InlineeLines;
+ DebugInlineeLinesSubsectionRef inlineeLines;
/// The DEBUG_S_FRAMEDATA subsection(s). There can be more than one of
/// these and they need not appear in any specific order. However, they
/// contain string table references which need to be re-written, so we
/// collect them all here and re-write them after all subsections have been
/// discovered and processed.
- std::vector<DebugFrameDataSubsectionRef> NewFpoFrames;
+ std::vector<DebugFrameDataSubsectionRef> newFpoFrames;
/// Pointers to raw memory that we determine have string table references
/// that need to be re-written. We first process all .debug$S subsections
/// up this list as we go. At the end, we use the string table (which must
/// have been discovered by now else it is an error) to re-write these
/// references.
- std::vector<ulittle32_t *> StringTableReferences;
+ std::vector<ulittle32_t *> stringTableReferences;
public:
- DebugSHandler(PDBLinker &Linker, ObjFile &File, const CVIndexMap &IndexMap)
- : Linker(Linker), File(File), IndexMap(IndexMap) {}
+ DebugSHandler(PDBLinker &linker, ObjFile &file, const CVIndexMap &indexMap)
+ : linker(linker), file(file), indexMap(indexMap) {}
- void handleDebugS(lld::coff::SectionChunk &DebugS);
+ void handleDebugS(lld::coff::SectionChunk &debugS);
std::shared_ptr<DebugInlineeLinesSubsection>
- mergeInlineeLines(DebugChecksumsSubsection *NewChecksums);
+ mergeInlineeLines(DebugChecksumsSubsection *newChecksums);
void finish();
};
// Visual Studio's debugger requires absolute paths in various places in the
// PDB to work without additional configuration:
// https://docs.microsoft.com/en-us/visualstudio/debugger/debug-source-files-common-properties-solution-property-pages-dialog-box
-static void pdbMakeAbsolute(SmallVectorImpl<char> &FileName) {
+static void pdbMakeAbsolute(SmallVectorImpl<char> &fileName) {
// The default behavior is to produce paths that are valid within the context
// of the machine that you perform the link on. If the linker is running on
// a POSIX system, we will output absolute POSIX paths. If the linker is
// user desires any other kind of behavior, they should explicitly pass
// /pdbsourcepath, in which case we will treat the exact string the user
// passed in as the gospel and not normalize, canonicalize it.
- if (sys::path::is_absolute(FileName, sys::path::Style::windows) ||
- sys::path::is_absolute(FileName, sys::path::Style::posix))
+ if (sys::path::is_absolute(fileName, sys::path::Style::windows) ||
+ sys::path::is_absolute(fileName, sys::path::Style::posix))
return;
// It's not absolute in any path syntax. Relative paths necessarily refer to
// the local file system, so we can make it native without ending up with a
// nonsensical path.
- if (Config->PDBSourcePath.empty()) {
- sys::path::native(FileName);
- sys::fs::make_absolute(FileName);
+ if (config->pdbSourcePath.empty()) {
+ sys::path::native(fileName);
+ sys::fs::make_absolute(fileName);
return;
}
// Since PDB's are more of a Windows thing, we make this conservative and only
// decide that it's a unix path if we're fairly certain. Specifically, if
// it starts with a forward slash.
- SmallString<128> AbsoluteFileName = Config->PDBSourcePath;
- sys::path::Style GuessedStyle = AbsoluteFileName.startswith("/")
+ SmallString<128> absoluteFileName = config->pdbSourcePath;
+ sys::path::Style guessedStyle = absoluteFileName.startswith("/")
? sys::path::Style::posix
: sys::path::Style::windows;
- sys::path::append(AbsoluteFileName, GuessedStyle, FileName);
- sys::path::native(AbsoluteFileName, GuessedStyle);
- sys::path::remove_dots(AbsoluteFileName, true, GuessedStyle);
+ sys::path::append(absoluteFileName, guessedStyle, fileName);
+ sys::path::native(absoluteFileName, guessedStyle);
+ sys::path::remove_dots(absoluteFileName, true, guessedStyle);
- FileName = std::move(AbsoluteFileName);
+ fileName = std::move(absoluteFileName);
}
// A COFF .debug$H section is currently a clang extension. This function checks
// if a .debug$H section is in a format that we expect / understand, so that we
// can ignore any sections which are coincidentally also named .debug$H but do
// not contain a format we recognize.
-static bool canUseDebugH(ArrayRef<uint8_t> DebugH) {
- if (DebugH.size() < sizeof(object::debug_h_header))
+static bool canUseDebugH(ArrayRef<uint8_t> debugH) {
+ if (debugH.size() < sizeof(object::debug_h_header))
return false;
- auto *Header =
- reinterpret_cast<const object::debug_h_header *>(DebugH.data());
- DebugH = DebugH.drop_front(sizeof(object::debug_h_header));
- return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC &&
- Header->Version == 0 &&
- Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) &&
- (DebugH.size() % 8 == 0);
+ auto *header =
+ reinterpret_cast<const object::debug_h_header *>(debugH.data());
+ debugH = debugH.drop_front(sizeof(object::debug_h_header));
+ return header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC &&
+ header->Version == 0 &&
+ header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) &&
+ (debugH.size() % 8 == 0);
}
-static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *File) {
- SectionChunk *Sec =
- SectionChunk::findByName(File->getDebugChunks(), ".debug$H");
- if (!Sec)
+static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *file) {
+ SectionChunk *sec =
+ SectionChunk::findByName(file->getDebugChunks(), ".debug$H");
+ if (!sec)
return llvm::None;
- ArrayRef<uint8_t> Contents = Sec->getContents();
- if (!canUseDebugH(Contents))
+ ArrayRef<uint8_t> contents = sec->getContents();
+ if (!canUseDebugH(contents))
return None;
- return Contents;
+ return contents;
}
static ArrayRef<GloballyHashedType>
-getHashesFromDebugH(ArrayRef<uint8_t> DebugH) {
- assert(canUseDebugH(DebugH));
+getHashesFromDebugH(ArrayRef<uint8_t> debugH) {
+ assert(canUseDebugH(debugH));
- DebugH = DebugH.drop_front(sizeof(object::debug_h_header));
- uint32_t Count = DebugH.size() / sizeof(GloballyHashedType);
- return {reinterpret_cast<const GloballyHashedType *>(DebugH.data()), Count};
+ debugH = debugH.drop_front(sizeof(object::debug_h_header));
+ uint32_t count = debugH.size() / sizeof(GloballyHashedType);
+ return {reinterpret_cast<const GloballyHashedType *>(debugH.data()), count};
}
-static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
- TypeCollection &TypeTable) {
+static void addTypeInfo(pdb::TpiStreamBuilder &tpiBuilder,
+ TypeCollection &typeTable) {
// Start the TPI or IPI stream header.
- TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
+ tpiBuilder.setVersionHeader(pdb::PdbTpiV80);
// Flatten the in memory type table and hash each type.
- TypeTable.ForEachRecord([&](TypeIndex TI, const CVType &Type) {
- auto Hash = pdb::hashTypeRecord(Type);
- if (auto E = Hash.takeError())
+ typeTable.ForEachRecord([&](TypeIndex ti, const CVType &type) {
+ auto hash = pdb::hashTypeRecord(type);
+ if (auto e = hash.takeError())
fatal("type hashing error");
- TpiBuilder.addTypeRecord(Type.RecordData, *Hash);
+ tpiBuilder.addTypeRecord(type.RecordData, *hash);
});
}
Expected<const CVIndexMap &>
-PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap *ObjectIndexMap) {
- ScopedTimer T(TypeMergingTimer);
+PDBLinker::mergeDebugT(ObjFile *file, CVIndexMap *objectIndexMap) {
+ ScopedTimer t(typeMergingTimer);
- if (!File->DebugTypesObj)
- return *ObjectIndexMap; // no Types stream
+ if (!file->debugTypesObj)
+ return *objectIndexMap; // no Types stream
// Precompiled headers objects need to save the index map for further
// reference by other objects which use the precompiled headers.
- if (File->DebugTypesObj->Kind == TpiSource::PCH) {
- uint32_t PCHSignature = File->PCHSignature.getValueOr(0);
- if (PCHSignature == 0)
+ if (file->debugTypesObj->kind == TpiSource::PCH) {
+ uint32_t pchSignature = file->pchSignature.getValueOr(0);
+ if (pchSignature == 0)
fatal("No signature found for the precompiled headers OBJ (" +
- File->getName() + ")");
+ file->getName() + ")");
// When a precompiled headers object comes first on the command-line, we
// update the mapping here. Otherwise, if an object referencing the
// precompiled headers object comes first, the mapping is created in
// aquirePrecompObj(), thus we would skip this block.
- if (!ObjectIndexMap->IsPrecompiledTypeMap) {
- auto R = registerPrecompiledHeaders(PCHSignature);
- if (R.second)
+ if (!objectIndexMap->isPrecompiledTypeMap) {
+ auto r = registerPrecompiledHeaders(pchSignature);
+ if (r.second)
fatal(
"A precompiled headers OBJ with the same signature was already "
"provided! (" +
- File->getName() + ")");
+ file->getName() + ")");
- ObjectIndexMap = &R.first;
+ objectIndexMap = &r.first;
}
}
- if (File->DebugTypesObj->Kind == TpiSource::UsingPDB) {
+ if (file->debugTypesObj->kind == TpiSource::UsingPDB) {
// Look through type servers. If we've already seen this type server,
// don't merge any type information.
- return maybeMergeTypeServerPDB(File);
+ return maybeMergeTypeServerPDB(file);
}
- CVTypeArray &Types = *File->DebugTypes;
+ CVTypeArray &types = *file->debugTypes;
- if (File->DebugTypesObj->Kind == TpiSource::UsingPCH) {
+ if (file->debugTypesObj->kind == TpiSource::UsingPCH) {
// This object was compiled with /Yu, so process the corresponding
// precompiled headers object (/Yc) first. Some type indices in the current
// object are referencing data in the precompiled headers object, so we need
// both to be loaded.
- Error E = mergeInPrecompHeaderObj(File, ObjectIndexMap);
- if (E)
- return std::move(E);
+ Error e = mergeInPrecompHeaderObj(file, objectIndexMap);
+ if (e)
+ return std::move(e);
// Drop LF_PRECOMP record from the input stream, as it has been replaced
// with the precompiled headers Type stream in the mergeInPrecompHeaderObj()
// call above. Note that we can't just call Types.drop_front(), as we
// explicitly want to rebase the stream.
- CVTypeArray::Iterator FirstType = Types.begin();
- Types.setUnderlyingStream(
- Types.getUnderlyingStream().drop_front(FirstType->RecordData.size()));
+ CVTypeArray::Iterator firstType = types.begin();
+ types.setUnderlyingStream(
+ types.getUnderlyingStream().drop_front(firstType->RecordData.size()));
}
// Fill in the temporary, caller-provided ObjectIndexMap.
- if (Config->DebugGHashes) {
- ArrayRef<GloballyHashedType> Hashes;
- std::vector<GloballyHashedType> OwnedHashes;
- if (Optional<ArrayRef<uint8_t>> DebugH = getDebugH(File))
- Hashes = getHashesFromDebugH(*DebugH);
+ if (config->debugGHashes) {
+ ArrayRef<GloballyHashedType> hashes;
+ std::vector<GloballyHashedType> ownedHashes;
+ if (Optional<ArrayRef<uint8_t>> debugH = getDebugH(file))
+ hashes = getHashesFromDebugH(*debugH);
else {
- OwnedHashes = GloballyHashedType::hashTypes(Types);
- Hashes = OwnedHashes;
+ ownedHashes = GloballyHashedType::hashTypes(types);
+ hashes = ownedHashes;
}
- if (auto Err = mergeTypeAndIdRecords(
- TMerger.GlobalIDTable, TMerger.GlobalTypeTable,
- ObjectIndexMap->TPIMap, Types, Hashes, File->PCHSignature))
+ if (auto err = mergeTypeAndIdRecords(
+ tMerger.globalIDTable, tMerger.globalTypeTable,
+ objectIndexMap->tpiMap, types, hashes, file->pchSignature))
fatal("codeview::mergeTypeAndIdRecords failed: " +
- toString(std::move(Err)));
+ toString(std::move(err)));
} else {
- if (auto Err = mergeTypeAndIdRecords(TMerger.IDTable, TMerger.TypeTable,
- ObjectIndexMap->TPIMap, Types,
- File->PCHSignature))
+ if (auto err = mergeTypeAndIdRecords(tMerger.iDTable, tMerger.typeTable,
+ objectIndexMap->tpiMap, types,
+ file->pchSignature))
fatal("codeview::mergeTypeAndIdRecords failed: " +
- toString(std::move(Err)));
+ toString(std::move(err)));
}
- return *ObjectIndexMap;
+ return *objectIndexMap;
}
-Expected<const CVIndexMap &> PDBLinker::maybeMergeTypeServerPDB(ObjFile *File) {
- Expected<llvm::pdb::NativeSession *> PDBSession = findTypeServerSource(File);
- if (!PDBSession)
- return PDBSession.takeError();
+Expected<const CVIndexMap &> PDBLinker::maybeMergeTypeServerPDB(ObjFile *file) {
+ Expected<llvm::pdb::NativeSession *> pdbSession = findTypeServerSource(file);
+ if (!pdbSession)
+ return pdbSession.takeError();
- pdb::PDBFile &PDBFile = PDBSession.get()->getPDBFile();
- pdb::InfoStream &Info = cantFail(PDBFile.getPDBInfoStream());
+ pdb::PDBFile &pdbFile = pdbSession.get()->getPDBFile();
+ pdb::InfoStream &info = cantFail(pdbFile.getPDBInfoStream());
- auto It = TypeServerIndexMappings.emplace(Info.getGuid(), CVIndexMap());
- CVIndexMap &IndexMap = It.first->second;
- if (!It.second)
- return IndexMap; // already merged
+ auto it = typeServerIndexMappings.emplace(info.getGuid(), CVIndexMap());
+ CVIndexMap &indexMap = it.first->second;
+ if (!it.second)
+ return indexMap; // already merged
// Mark this map as a type server map.
- IndexMap.IsTypeServerMap = true;
-
- Expected<pdb::TpiStream &> ExpectedTpi = PDBFile.getPDBTpiStream();
- if (auto E = ExpectedTpi.takeError())
- fatal("Type server does not have TPI stream: " + toString(std::move(E)));
- pdb::TpiStream *MaybeIpi = nullptr;
- if (PDBFile.hasPDBIpiStream()) {
- Expected<pdb::TpiStream &> ExpectedIpi = PDBFile.getPDBIpiStream();
- if (auto E = ExpectedIpi.takeError())
- fatal("Error getting type server IPI stream: " + toString(std::move(E)));
- MaybeIpi = &*ExpectedIpi;
+ indexMap.isTypeServerMap = true;
+
+ Expected<pdb::TpiStream &> expectedTpi = pdbFile.getPDBTpiStream();
+ if (auto e = expectedTpi.takeError())
+ fatal("Type server does not have TPI stream: " + toString(std::move(e)));
+ pdb::TpiStream *maybeIpi = nullptr;
+ if (pdbFile.hasPDBIpiStream()) {
+ Expected<pdb::TpiStream &> expectedIpi = pdbFile.getPDBIpiStream();
+ if (auto e = expectedIpi.takeError())
+ fatal("Error getting type server IPI stream: " + toString(std::move(e)));
+ maybeIpi = &*expectedIpi;
}
- if (Config->DebugGHashes) {
+ if (config->debugGHashes) {
// PDBs do not actually store global hashes, so when merging a type server
// PDB we have to synthesize global hashes. To do this, we first synthesize
// global hashes for the TPI stream, since it is independent, then we
// synthesize hashes for the IPI stream, using the hashes for the TPI stream
// as inputs.
- auto TpiHashes = GloballyHashedType::hashTypes(ExpectedTpi->typeArray());
- Optional<uint32_t> EndPrecomp;
+ auto tpiHashes = GloballyHashedType::hashTypes(expectedTpi->typeArray());
+ Optional<uint32_t> endPrecomp;
// Merge TPI first, because the IPI stream will reference type indices.
- if (auto Err =
- mergeTypeRecords(TMerger.GlobalTypeTable, IndexMap.TPIMap,
- ExpectedTpi->typeArray(), TpiHashes, EndPrecomp))
- fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err)));
+ if (auto err =
+ mergeTypeRecords(tMerger.globalTypeTable, indexMap.tpiMap,
+ expectedTpi->typeArray(), tpiHashes, endPrecomp))
+ fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err)));
// Merge IPI.
- if (MaybeIpi) {
- auto IpiHashes =
- GloballyHashedType::hashIds(MaybeIpi->typeArray(), TpiHashes);
- if (auto Err =
- mergeIdRecords(TMerger.GlobalIDTable, IndexMap.TPIMap,
- IndexMap.IPIMap, MaybeIpi->typeArray(), IpiHashes))
- fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err)));
+ if (maybeIpi) {
+ auto ipiHashes =
+ GloballyHashedType::hashIds(maybeIpi->typeArray(), tpiHashes);
+ if (auto err =
+ mergeIdRecords(tMerger.globalIDTable, indexMap.tpiMap,
+ indexMap.ipiMap, maybeIpi->typeArray(), ipiHashes))
+ fatal("codeview::mergeIdRecords failed: " + toString(std::move(err)));
}
} else {
// Merge TPI first, because the IPI stream will reference type indices.
- if (auto Err = mergeTypeRecords(TMerger.TypeTable, IndexMap.TPIMap,
- ExpectedTpi->typeArray()))
- fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err)));
+ if (auto err = mergeTypeRecords(tMerger.typeTable, indexMap.tpiMap,
+ expectedTpi->typeArray()))
+ fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err)));
// Merge IPI.
- if (MaybeIpi) {
- if (auto Err = mergeIdRecords(TMerger.IDTable, IndexMap.TPIMap,
- IndexMap.IPIMap, MaybeIpi->typeArray()))
- fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err)));
+ if (maybeIpi) {
+ if (auto err = mergeIdRecords(tMerger.iDTable, indexMap.tpiMap,
+ indexMap.ipiMap, maybeIpi->typeArray()))
+ fatal("codeview::mergeIdRecords failed: " + toString(std::move(err)));
}
}
- return IndexMap;
+ return indexMap;
}
-Error PDBLinker::mergeInPrecompHeaderObj(ObjFile *File,
- CVIndexMap *ObjectIndexMap) {
- const PrecompRecord &Precomp =
- retrieveDependencyInfo<PrecompRecord>(File->DebugTypesObj);
+Error PDBLinker::mergeInPrecompHeaderObj(ObjFile *file,
+ CVIndexMap *objectIndexMap) {
+ const PrecompRecord &precomp =
+ retrieveDependencyInfo<PrecompRecord>(file->debugTypesObj);
- Expected<const CVIndexMap &> E = aquirePrecompObj(File);
- if (!E)
- return E.takeError();
+ Expected<const CVIndexMap &> e = aquirePrecompObj(file);
+ if (!e)
+ return e.takeError();
- const CVIndexMap &PrecompIndexMap = *E;
- assert(PrecompIndexMap.IsPrecompiledTypeMap);
+ const CVIndexMap &precompIndexMap = *e;
+ assert(precompIndexMap.isPrecompiledTypeMap);
- if (PrecompIndexMap.TPIMap.empty())
+ if (precompIndexMap.tpiMap.empty())
return Error::success();
- assert(Precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex);
- assert(Precomp.getTypesCount() <= PrecompIndexMap.TPIMap.size());
+ assert(precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex);
+ assert(precomp.getTypesCount() <= precompIndexMap.tpiMap.size());
// Use the previously remapped index map from the precompiled headers.
- ObjectIndexMap->TPIMap.append(PrecompIndexMap.TPIMap.begin(),
- PrecompIndexMap.TPIMap.begin() +
- Precomp.getTypesCount());
+ objectIndexMap->tpiMap.append(precompIndexMap.tpiMap.begin(),
+ precompIndexMap.tpiMap.begin() +
+ precomp.getTypesCount());
return Error::success();
}
}
// Find by name an OBJ provided on the command line
-static ObjFile *findObjByName(StringRef FileNameOnly) {
- SmallString<128> CurrentPath;
+static ObjFile *findObjByName(StringRef fileNameOnly) {
+ SmallString<128> currentPath;
- for (ObjFile *F : ObjFile::Instances) {
- StringRef CurrentFileName = sys::path::filename(F->getName());
+ for (ObjFile *f : ObjFile::instances) {
+ StringRef currentFileName = sys::path::filename(f->getName());
// Compare based solely on the file name (link.exe behavior)
- if (equals_path(CurrentFileName, FileNameOnly))
- return F;
+ if (equals_path(currentFileName, fileNameOnly))
+ return f;
}
return nullptr;
}
std::pair<CVIndexMap &, bool /*already there*/>
-PDBLinker::registerPrecompiledHeaders(uint32_t Signature) {
- auto Insertion = PrecompTypeIndexMappings.insert({Signature, CVIndexMap()});
- CVIndexMap &IndexMap = Insertion.first->second;
- if (!Insertion.second)
- return {IndexMap, true};
+PDBLinker::registerPrecompiledHeaders(uint32_t signature) {
+ auto insertion = precompTypeIndexMappings.insert({signature, CVIndexMap()});
+ CVIndexMap &indexMap = insertion.first->second;
+ if (!insertion.second)
+ return {indexMap, true};
// Mark this map as a precompiled types map.
- IndexMap.IsPrecompiledTypeMap = true;
- return {IndexMap, false};
+ indexMap.isPrecompiledTypeMap = true;
+ return {indexMap, false};
}
-Expected<const CVIndexMap &> PDBLinker::aquirePrecompObj(ObjFile *File) {
- const PrecompRecord &Precomp =
- retrieveDependencyInfo<PrecompRecord>(File->DebugTypesObj);
+Expected<const CVIndexMap &> PDBLinker::aquirePrecompObj(ObjFile *file) {
+ const PrecompRecord &precomp =
+ retrieveDependencyInfo<PrecompRecord>(file->debugTypesObj);
// First, check if we already loaded the precompiled headers object with this
// signature. Return the type index mapping if we've already seen it.
- auto R = registerPrecompiledHeaders(Precomp.getSignature());
- if (R.second)
- return R.first;
+ auto r = registerPrecompiledHeaders(precomp.getSignature());
+ if (r.second)
+ return r.first;
- CVIndexMap &IndexMap = R.first;
+ CVIndexMap &indexMap = r.first;
// Cross-compile warning: given that Clang doesn't generate LF_PRECOMP
// records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,
// the paths embedded in the OBJs are in the Windows format.
- SmallString<128> PrecompFileName = sys::path::filename(
- Precomp.getPrecompFilePath(), sys::path::Style::windows);
+ SmallString<128> precompFileName = sys::path::filename(
+ precomp.getPrecompFilePath(), sys::path::Style::windows);
// link.exe requires that a precompiled headers object must always be provided
// on the command-line, even if that's not necessary.
- auto PrecompFile = findObjByName(PrecompFileName);
- if (!PrecompFile)
+ auto precompFile = findObjByName(precompFileName);
+ if (!precompFile)
return createFileError(
- PrecompFileName.str(),
+ precompFileName.str(),
make_error<pdb::PDBError>(pdb::pdb_error_code::external_cmdline_ref));
- addObjFile(PrecompFile, &IndexMap);
+ addObjFile(precompFile, &indexMap);
- if (!PrecompFile->PCHSignature)
- fatal(PrecompFile->getName() + " is not a precompiled headers object");
+ if (!precompFile->pchSignature)
+ fatal(precompFile->getName() + " is not a precompiled headers object");
- if (Precomp.getSignature() != PrecompFile->PCHSignature.getValueOr(0))
+ if (precomp.getSignature() != precompFile->pchSignature.getValueOr(0))
return createFileError(
- Precomp.getPrecompFilePath().str(),
+ precomp.getPrecompFilePath().str(),
make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
- return IndexMap;
+ return indexMap;
}
-static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
- if (TI.isSimple())
+static bool remapTypeIndex(TypeIndex &ti, ArrayRef<TypeIndex> typeIndexMap) {
+ if (ti.isSimple())
return true;
- if (TI.toArrayIndex() >= TypeIndexMap.size())
+ if (ti.toArrayIndex() >= typeIndexMap.size())
return false;
- TI = TypeIndexMap[TI.toArrayIndex()];
+ ti = typeIndexMap[ti.toArrayIndex()];
return true;
}
-static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind,
- MutableArrayRef<uint8_t> RecordBytes,
- const CVIndexMap &IndexMap,
- ArrayRef<TiReference> TypeRefs) {
- MutableArrayRef<uint8_t> Contents =
- RecordBytes.drop_front(sizeof(RecordPrefix));
- for (const TiReference &Ref : TypeRefs) {
- unsigned ByteSize = Ref.Count * sizeof(TypeIndex);
- if (Contents.size() < Ref.Offset + ByteSize)
+static void remapTypesInSymbolRecord(ObjFile *file, SymbolKind symKind,
+ MutableArrayRef<uint8_t> recordBytes,
+ const CVIndexMap &indexMap,
+ ArrayRef<TiReference> typeRefs) {
+ MutableArrayRef<uint8_t> contents =
+ recordBytes.drop_front(sizeof(RecordPrefix));
+ for (const TiReference &ref : typeRefs) {
+ unsigned byteSize = ref.Count * sizeof(TypeIndex);
+ if (contents.size() < ref.Offset + byteSize)
fatal("symbol record too short");
// This can be an item index or a type index. Choose the appropriate map.
- ArrayRef<TypeIndex> TypeOrItemMap = IndexMap.TPIMap;
- bool IsItemIndex = Ref.Kind == TiRefKind::IndexRef;
- if (IsItemIndex && IndexMap.IsTypeServerMap)
- TypeOrItemMap = IndexMap.IPIMap;
-
- MutableArrayRef<TypeIndex> TIs(
- reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count);
- for (TypeIndex &TI : TIs) {
- if (!remapTypeIndex(TI, TypeOrItemMap)) {
- log("ignoring symbol record of kind 0x" + utohexstr(SymKind) + " in " +
- File->getName() + " with bad " + (IsItemIndex ? "item" : "type") +
- " index 0x" + utohexstr(TI.getIndex()));
- TI = TypeIndex(SimpleTypeKind::NotTranslated);
+ ArrayRef<TypeIndex> typeOrItemMap = indexMap.tpiMap;
+ bool isItemIndex = ref.Kind == TiRefKind::IndexRef;
+ if (isItemIndex && indexMap.isTypeServerMap)
+ typeOrItemMap = indexMap.ipiMap;
+
+ MutableArrayRef<TypeIndex> tIs(
+ reinterpret_cast<TypeIndex *>(contents.data() + ref.Offset), ref.Count);
+ for (TypeIndex &ti : tIs) {
+ if (!remapTypeIndex(ti, typeOrItemMap)) {
+ log("ignoring symbol record of kind 0x" + utohexstr(symKind) + " in " +
+ file->getName() + " with bad " + (isItemIndex ? "item" : "type") +
+ " index 0x" + utohexstr(ti.getIndex()));
+ ti = TypeIndex(SimpleTypeKind::NotTranslated);
continue;
}
}
}
static void
-recordStringTableReferenceAtOffset(MutableArrayRef<uint8_t> Contents,
- uint32_t Offset,
- std::vector<ulittle32_t *> &StrTableRefs) {
- Contents =
- Contents.drop_front(Offset).take_front(sizeof(support::ulittle32_t));
- ulittle32_t *Index = reinterpret_cast<ulittle32_t *>(Contents.data());
- StrTableRefs.push_back(Index);
+recordStringTableReferenceAtOffset(MutableArrayRef<uint8_t> contents,
+ uint32_t offset,
+ std::vector<ulittle32_t *> &strTableRefs) {
+ contents =
+ contents.drop_front(offset).take_front(sizeof(support::ulittle32_t));
+ ulittle32_t *index = reinterpret_cast<ulittle32_t *>(contents.data());
+ strTableRefs.push_back(index);
}
static void
-recordStringTableReferences(SymbolKind Kind, MutableArrayRef<uint8_t> Contents,
- std::vector<ulittle32_t *> &StrTableRefs) {
+recordStringTableReferences(SymbolKind kind, MutableArrayRef<uint8_t> contents,
+ std::vector<ulittle32_t *> &strTableRefs) {
// For now we only handle S_FILESTATIC, but we may need the same logic for
// S_DEFRANGE and S_DEFRANGE_SUBFIELD. However, I cannot seem to generate any
// PDBs that contain these types of records, so because of the uncertainty
// they are omitted here until we can prove that it's necessary.
- switch (Kind) {
+ switch (kind) {
case SymbolKind::S_FILESTATIC:
// FileStaticSym::ModFileOffset
- recordStringTableReferenceAtOffset(Contents, 8, StrTableRefs);
+ recordStringTableReferenceAtOffset(contents, 8, strTableRefs);
break;
case SymbolKind::S_DEFRANGE:
case SymbolKind::S_DEFRANGE_SUBFIELD:
}
}
-static SymbolKind symbolKind(ArrayRef<uint8_t> RecordData) {
- const RecordPrefix *Prefix =
- reinterpret_cast<const RecordPrefix *>(RecordData.data());
- return static_cast<SymbolKind>(uint16_t(Prefix->RecordKind));
+static SymbolKind symbolKind(ArrayRef<uint8_t> recordData) {
+ const RecordPrefix *prefix =
+ reinterpret_cast<const RecordPrefix *>(recordData.data());
+ return static_cast<SymbolKind>(uint16_t(prefix->RecordKind));
}
/// MSVC translates S_PROC_ID_END to S_END, and S_[LG]PROC32_ID to S_[LG]PROC32
-static void translateIdSymbols(MutableArrayRef<uint8_t> &RecordData,
- TypeCollection &IDTable) {
- RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(RecordData.data());
+static void translateIdSymbols(MutableArrayRef<uint8_t> &recordData,
+ TypeCollection &iDTable) {
+ RecordPrefix *prefix = reinterpret_cast<RecordPrefix *>(recordData.data());
- SymbolKind Kind = symbolKind(RecordData);
+ SymbolKind kind = symbolKind(recordData);
- if (Kind == SymbolKind::S_PROC_ID_END) {
- Prefix->RecordKind = SymbolKind::S_END;
+ if (kind == SymbolKind::S_PROC_ID_END) {
+ prefix->RecordKind = SymbolKind::S_END;
return;
}
// to the PDB file's ID stream index space, but we need to convert this to a
// symbol that refers to the type stream index space. So we remap again from
// ID index space to type index space.
- if (Kind == SymbolKind::S_GPROC32_ID || Kind == SymbolKind::S_LPROC32_ID) {
- SmallVector<TiReference, 1> Refs;
- auto Content = RecordData.drop_front(sizeof(RecordPrefix));
- CVSymbol Sym(RecordData);
- discoverTypeIndicesInSymbol(Sym, Refs);
- assert(Refs.size() == 1);
- assert(Refs.front().Count == 1);
-
- TypeIndex *TI =
- reinterpret_cast<TypeIndex *>(Content.data() + Refs[0].Offset);
+ if (kind == SymbolKind::S_GPROC32_ID || kind == SymbolKind::S_LPROC32_ID) {
+ SmallVector<TiReference, 1> refs;
+ auto content = recordData.drop_front(sizeof(RecordPrefix));
+ CVSymbol sym(recordData);
+ discoverTypeIndicesInSymbol(sym, refs);
+ assert(refs.size() == 1);
+ assert(refs.front().Count == 1);
+
+ TypeIndex *ti =
+ reinterpret_cast<TypeIndex *>(content.data() + refs[0].Offset);
// `TI` is the index of a FuncIdRecord or MemberFuncIdRecord which lives in
// the IPI stream, whose `FunctionType` member refers to the TPI stream.
// Note that LF_FUNC_ID and LF_MEMFUNC_ID have the same record layout, and
// in both cases we just need the second type index.
- if (!TI->isSimple() && !TI->isNoneType()) {
- CVType FuncIdData = IDTable.getType(*TI);
- SmallVector<TypeIndex, 2> Indices;
- discoverTypeIndices(FuncIdData, Indices);
- assert(Indices.size() == 2);
- *TI = Indices[1];
+ if (!ti->isSimple() && !ti->isNoneType()) {
+ CVType funcIdData = iDTable.getType(*ti);
+ SmallVector<TypeIndex, 2> indices;
+ discoverTypeIndices(funcIdData, indices);
+ assert(indices.size() == 2);
+ *ti = indices[1];
}
- Kind = (Kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32
+ kind = (kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32
: SymbolKind::S_LPROC32;
- Prefix->RecordKind = uint16_t(Kind);
+ prefix->RecordKind = uint16_t(kind);
}
}
/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned.
/// The object file may not be aligned.
static MutableArrayRef<uint8_t>
-copyAndAlignSymbol(const CVSymbol &Sym, MutableArrayRef<uint8_t> &AlignedMem) {
- size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb));
- assert(Size >= 4 && "record too short");
- assert(Size <= MaxRecordLength && "record too long");
- assert(AlignedMem.size() >= Size && "didn't preallocate enough");
+copyAndAlignSymbol(const CVSymbol &sym, MutableArrayRef<uint8_t> &alignedMem) {
+ size_t size = alignTo(sym.length(), alignOf(CodeViewContainer::Pdb));
+ assert(size >= 4 && "record too short");
+ assert(size <= MaxRecordLength && "record too long");
+ assert(alignedMem.size() >= size && "didn't preallocate enough");
// Copy the symbol record and zero out any padding bytes.
- MutableArrayRef<uint8_t> NewData = AlignedMem.take_front(Size);
- AlignedMem = AlignedMem.drop_front(Size);
- memcpy(NewData.data(), Sym.data().data(), Sym.length());
- memset(NewData.data() + Sym.length(), 0, Size - Sym.length());
+ MutableArrayRef<uint8_t> newData = alignedMem.take_front(size);
+ alignedMem = alignedMem.drop_front(size);
+ memcpy(newData.data(), sym.data().data(), sym.length());
+ memset(newData.data() + sym.length(), 0, size - sym.length());
// Update the record prefix length. It should point to the beginning of the
// next record.
- auto *Prefix = reinterpret_cast<RecordPrefix *>(NewData.data());
- Prefix->RecordLen = Size - 2;
- return NewData;
+ auto *prefix = reinterpret_cast<RecordPrefix *>(newData.data());
+ prefix->RecordLen = size - 2;
+ return newData;
}
struct ScopeRecord {
- ulittle32_t PtrParent;
- ulittle32_t PtrEnd;
+ ulittle32_t ptrParent;
+ ulittle32_t ptrEnd;
};
struct SymbolScope {
- ScopeRecord *OpeningRecord;
- uint32_t ScopeOffset;
+ ScopeRecord *openingRecord;
+ uint32_t scopeOffset;
};
-static void scopeStackOpen(SmallVectorImpl<SymbolScope> &Stack,
- uint32_t CurOffset, CVSymbol &Sym) {
- assert(symbolOpensScope(Sym.kind()));
- SymbolScope S;
- S.ScopeOffset = CurOffset;
- S.OpeningRecord = const_cast<ScopeRecord *>(
- reinterpret_cast<const ScopeRecord *>(Sym.content().data()));
- S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset;
- Stack.push_back(S);
+static void scopeStackOpen(SmallVectorImpl<SymbolScope> &stack,
+ uint32_t curOffset, CVSymbol &sym) {
+ assert(symbolOpensScope(sym.kind()));
+ SymbolScope s;
+ s.scopeOffset = curOffset;
+ s.openingRecord = const_cast<ScopeRecord *>(
+ reinterpret_cast<const ScopeRecord *>(sym.content().data()));
+ s.openingRecord->ptrParent = stack.empty() ? 0 : stack.back().scopeOffset;
+ stack.push_back(s);
}
-static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack,
- uint32_t CurOffset, InputFile *File) {
- if (Stack.empty()) {
- warn("symbol scopes are not balanced in " + File->getName());
+static void scopeStackClose(SmallVectorImpl<SymbolScope> &stack,
+ uint32_t curOffset, InputFile *file) {
+ if (stack.empty()) {
+ warn("symbol scopes are not balanced in " + file->getName());
return;
}
- SymbolScope S = Stack.pop_back_val();
- S.OpeningRecord->PtrEnd = CurOffset;
+ SymbolScope s = stack.pop_back_val();
+ s.openingRecord->ptrEnd = curOffset;
}
-static bool symbolGoesInModuleStream(const CVSymbol &Sym, bool IsGlobalScope) {
- switch (Sym.kind()) {
+static bool symbolGoesInModuleStream(const CVSymbol &sym, bool isGlobalScope) {
+ switch (sym.kind()) {
case SymbolKind::S_GDATA32:
case SymbolKind::S_CONSTANT:
// We really should not be seeing S_PROCREF and S_LPROCREF in the first place
return false;
// S_UDT records go in the module stream if it is not a global S_UDT.
case SymbolKind::S_UDT:
- return !IsGlobalScope;
+ return !isGlobalScope;
// S_GDATA32 does not go in the module stream, but S_LDATA32 does.
case SymbolKind::S_LDATA32:
default:
}
}
-static bool symbolGoesInGlobalsStream(const CVSymbol &Sym, bool IsGlobalScope) {
- switch (Sym.kind()) {
+static bool symbolGoesInGlobalsStream(const CVSymbol &sym, bool isGlobalScope) {
+ switch (sym.kind()) {
case SymbolKind::S_CONSTANT:
case SymbolKind::S_GDATA32:
// S_LDATA32 goes in both the module stream and the globals stream.
return true;
// S_UDT records go in the globals stream if it is a global S_UDT.
case SymbolKind::S_UDT:
- return IsGlobalScope;
+ return isGlobalScope;
default:
return false;
}
}
-static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, uint16_t ModIndex,
- unsigned SymOffset, const CVSymbol &Sym) {
- switch (Sym.kind()) {
+static void addGlobalSymbol(pdb::GSIStreamBuilder &builder, uint16_t modIndex,
+ unsigned symOffset, const CVSymbol &sym) {
+ switch (sym.kind()) {
case SymbolKind::S_CONSTANT:
case SymbolKind::S_UDT:
case SymbolKind::S_GDATA32:
case SymbolKind::S_LDATA32:
case SymbolKind::S_PROCREF:
case SymbolKind::S_LPROCREF:
- Builder.addGlobalSymbol(Sym);
+ builder.addGlobalSymbol(sym);
break;
case SymbolKind::S_GPROC32:
case SymbolKind::S_LPROC32: {
- SymbolRecordKind K = SymbolRecordKind::ProcRefSym;
- if (Sym.kind() == SymbolKind::S_LPROC32)
- K = SymbolRecordKind::LocalProcRef;
- ProcRefSym PS(K);
- PS.Module = ModIndex;
+ SymbolRecordKind k = SymbolRecordKind::ProcRefSym;
+ if (sym.kind() == SymbolKind::S_LPROC32)
+ k = SymbolRecordKind::LocalProcRef;
+ ProcRefSym ps(k);
+ ps.Module = modIndex;
// For some reason, MSVC seems to add one to this value.
- ++PS.Module;
- PS.Name = getSymbolName(Sym);
- PS.SumName = 0;
- PS.SymOffset = SymOffset;
- Builder.addGlobalSymbol(PS);
+ ++ps.Module;
+ ps.Name = getSymbolName(sym);
+ ps.SumName = 0;
+ ps.SymOffset = symOffset;
+ builder.addGlobalSymbol(ps);
break;
}
default:
}
}
-void PDBLinker::mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap,
- std::vector<ulittle32_t *> &StringTableRefs,
- BinaryStreamRef SymData) {
- ArrayRef<uint8_t> SymsBuffer;
- cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer));
- SmallVector<SymbolScope, 4> Scopes;
+void PDBLinker::mergeSymbolRecords(ObjFile *file, const CVIndexMap &indexMap,
+ std::vector<ulittle32_t *> &stringTableRefs,
+ BinaryStreamRef symData) {
+ ArrayRef<uint8_t> symsBuffer;
+ cantFail(symData.readBytes(0, symData.getLength(), symsBuffer));
+ SmallVector<SymbolScope, 4> scopes;
// Iterate every symbol to check if any need to be realigned, and if so, how
// much space we need to allocate for them.
- bool NeedsRealignment = false;
- unsigned TotalRealignedSize = 0;
- auto EC = forEachCodeViewRecord<CVSymbol>(
- SymsBuffer, [&](CVSymbol Sym) -> llvm::Error {
- unsigned RealignedSize =
- alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb));
- NeedsRealignment |= RealignedSize != Sym.length();
- TotalRealignedSize += RealignedSize;
+ bool needsRealignment = false;
+ unsigned totalRealignedSize = 0;
+ auto ec = forEachCodeViewRecord<CVSymbol>(
+ symsBuffer, [&](CVSymbol sym) -> llvm::Error {
+ unsigned realignedSize =
+ alignTo(sym.length(), alignOf(CodeViewContainer::Pdb));
+ needsRealignment |= realignedSize != sym.length();
+ totalRealignedSize += realignedSize;
return Error::success();
});
// If any of the symbol record lengths was corrupt, ignore them all, warn
// about it, and move on.
- if (EC) {
- warn("corrupt symbol records in " + File->getName());
- consumeError(std::move(EC));
+ if (ec) {
+ warn("corrupt symbol records in " + file->getName());
+ consumeError(std::move(ec));
return;
}
// If any symbol needed realignment, allocate enough contiguous memory for
// them all. Typically symbol subsections are small enough that this will not
// cause fragmentation.
- MutableArrayRef<uint8_t> AlignedSymbolMem;
- if (NeedsRealignment) {
- void *AlignedData =
- Alloc.Allocate(TotalRealignedSize, alignOf(CodeViewContainer::Pdb));
- AlignedSymbolMem = makeMutableArrayRef(
- reinterpret_cast<uint8_t *>(AlignedData), TotalRealignedSize);
+ MutableArrayRef<uint8_t> alignedSymbolMem;
+ if (needsRealignment) {
+ void *alignedData =
+ alloc.Allocate(totalRealignedSize, alignOf(CodeViewContainer::Pdb));
+ alignedSymbolMem = makeMutableArrayRef(
+ reinterpret_cast<uint8_t *>(alignedData), totalRealignedSize);
}
// Iterate again, this time doing the real work.
- unsigned CurSymOffset = File->ModuleDBI->getNextSymbolOffset();
- ArrayRef<uint8_t> BulkSymbols;
+ unsigned curSymOffset = file->moduleDBI->getNextSymbolOffset();
+ ArrayRef<uint8_t> bulkSymbols;
cantFail(forEachCodeViewRecord<CVSymbol>(
- SymsBuffer, [&](CVSymbol Sym) -> llvm::Error {
+ symsBuffer, [&](CVSymbol sym) -> llvm::Error {
// Align the record if required.
- MutableArrayRef<uint8_t> RecordBytes;
- if (NeedsRealignment) {
- RecordBytes = copyAndAlignSymbol(Sym, AlignedSymbolMem);
- Sym = CVSymbol(RecordBytes);
+ MutableArrayRef<uint8_t> recordBytes;
+ if (needsRealignment) {
+ recordBytes = copyAndAlignSymbol(sym, alignedSymbolMem);
+ sym = CVSymbol(recordBytes);
} else {
// Otherwise, we can actually mutate the symbol directly, since we
// copied it to apply relocations.
- RecordBytes = makeMutableArrayRef(
- const_cast<uint8_t *>(Sym.data().data()), Sym.length());
+ recordBytes = makeMutableArrayRef(
+ const_cast<uint8_t *>(sym.data().data()), sym.length());
}
// Discover type index references in the record. Skip it if we don't
// know where they are.
- SmallVector<TiReference, 32> TypeRefs;
- if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
+ SmallVector<TiReference, 32> typeRefs;
+ if (!discoverTypeIndicesInSymbol(sym, typeRefs)) {
log("ignoring unknown symbol record with kind 0x" +
- utohexstr(Sym.kind()));
+ utohexstr(sym.kind()));
return Error::success();
}
// Re-map all the type index references.
- remapTypesInSymbolRecord(File, Sym.kind(), RecordBytes, IndexMap,
- TypeRefs);
+ remapTypesInSymbolRecord(file, sym.kind(), recordBytes, indexMap,
+ typeRefs);
// An object file may have S_xxx_ID symbols, but these get converted to
// "real" symbols in a PDB.
- translateIdSymbols(RecordBytes, TMerger.getIDTable());
- Sym = CVSymbol(RecordBytes);
+ translateIdSymbols(recordBytes, tMerger.getIDTable());
+ sym = CVSymbol(recordBytes);
// If this record refers to an offset in the object file's string table,
// add that item to the global PDB string table and re-write the index.
- recordStringTableReferences(Sym.kind(), RecordBytes, StringTableRefs);
+ recordStringTableReferences(sym.kind(), recordBytes, stringTableRefs);
// Fill in "Parent" and "End" fields by maintaining a stack of scopes.
- if (symbolOpensScope(Sym.kind()))
- scopeStackOpen(Scopes, CurSymOffset, Sym);
- else if (symbolEndsScope(Sym.kind()))
- scopeStackClose(Scopes, CurSymOffset, File);
+ if (symbolOpensScope(sym.kind()))
+ scopeStackOpen(scopes, curSymOffset, sym);
+ else if (symbolEndsScope(sym.kind()))
+ scopeStackClose(scopes, curSymOffset, file);
// Add the symbol to the globals stream if necessary. Do this before
// adding the symbol to the module since we may need to get the next
// symbol offset, and writing to the module's symbol stream will update
// that offset.
- if (symbolGoesInGlobalsStream(Sym, Scopes.empty())) {
- addGlobalSymbol(Builder.getGsiBuilder(),
- File->ModuleDBI->getModuleIndex(), CurSymOffset, Sym);
- ++GlobalSymbols;
+ if (symbolGoesInGlobalsStream(sym, scopes.empty())) {
+ addGlobalSymbol(builder.getGsiBuilder(),
+ file->moduleDBI->getModuleIndex(), curSymOffset, sym);
+ ++globalSymbols;
}
- if (symbolGoesInModuleStream(Sym, Scopes.empty())) {
+ if (symbolGoesInModuleStream(sym, scopes.empty())) {
// Add symbols to the module in bulk. If this symbol is contiguous
// with the previous run of symbols to add, combine the ranges. If
// not, close the previous range of symbols and start a new one.
- if (Sym.data().data() == BulkSymbols.end()) {
- BulkSymbols = makeArrayRef(BulkSymbols.data(),
- BulkSymbols.size() + Sym.length());
+ if (sym.data().data() == bulkSymbols.end()) {
+ bulkSymbols = makeArrayRef(bulkSymbols.data(),
+ bulkSymbols.size() + sym.length());
} else {
- File->ModuleDBI->addSymbolsInBulk(BulkSymbols);
- BulkSymbols = RecordBytes;
+ file->moduleDBI->addSymbolsInBulk(bulkSymbols);
+ bulkSymbols = recordBytes;
}
- CurSymOffset += Sym.length();
- ++ModuleSymbols;
+ curSymOffset += sym.length();
+ ++moduleSymbols;
}
return Error::success();
}));
// Add any remaining symbols we've accumulated.
- File->ModuleDBI->addSymbolsInBulk(BulkSymbols);
+ file->moduleDBI->addSymbolsInBulk(bulkSymbols);
}
// Allocate memory for a .debug$S / .debug$F section and relocate it.
-static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc,
- SectionChunk &DebugChunk) {
- uint8_t *Buffer = Alloc.Allocate<uint8_t>(DebugChunk.getSize());
- assert(DebugChunk.getOutputSectionIdx() == 0 &&
+static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &alloc,
+ SectionChunk &debugChunk) {
+ uint8_t *buffer = alloc.Allocate<uint8_t>(debugChunk.getSize());
+ assert(debugChunk.getOutputSectionIdx() == 0 &&
"debug sections should not be in output sections");
- DebugChunk.writeTo(Buffer);
- return makeArrayRef(Buffer, DebugChunk.getSize());
+ debugChunk.writeTo(buffer);
+ return makeArrayRef(buffer, debugChunk.getSize());
}
-static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) {
- OutputSection *OS = C ? C->getOutputSection() : nullptr;
- pdb::SectionContrib SC;
- memset(&SC, 0, sizeof(SC));
- SC.ISect = OS ? OS->SectionIndex : llvm::pdb::kInvalidStreamIndex;
- SC.Off = C && OS ? C->getRVA() - OS->getRVA() : 0;
- SC.Size = C ? C->getSize() : -1;
- if (auto *SecChunk = dyn_cast_or_null<SectionChunk>(C)) {
- SC.Characteristics = SecChunk->Header->Characteristics;
- SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex();
- ArrayRef<uint8_t> Contents = SecChunk->getContents();
- JamCRC CRC(0);
- ArrayRef<char> CharContents = makeArrayRef(
- reinterpret_cast<const char *>(Contents.data()), Contents.size());
- CRC.update(CharContents);
- SC.DataCrc = CRC.getCRC();
+static pdb::SectionContrib createSectionContrib(const Chunk *c, uint32_t modi) {
+ OutputSection *os = c ? c->getOutputSection() : nullptr;
+ pdb::SectionContrib sc;
+ memset(&sc, 0, sizeof(sc));
+ sc.ISect = os ? os->sectionIndex : llvm::pdb::kInvalidStreamIndex;
+ sc.Off = c && os ? c->getRVA() - os->getRVA() : 0;
+ sc.Size = c ? c->getSize() : -1;
+ if (auto *secChunk = dyn_cast_or_null<SectionChunk>(c)) {
+ sc.Characteristics = secChunk->header->Characteristics;
+ sc.Imod = secChunk->file->moduleDBI->getModuleIndex();
+ ArrayRef<uint8_t> contents = secChunk->getContents();
+ JamCRC crc(0);
+ ArrayRef<char> charContents = makeArrayRef(
+ reinterpret_cast<const char *>(contents.data()), contents.size());
+ crc.update(charContents);
+ sc.DataCrc = crc.getCRC();
} else {
- SC.Characteristics = OS ? OS->Header.Characteristics : 0;
- SC.Imod = Modi;
+ sc.Characteristics = os ? os->header.Characteristics : 0;
+ sc.Imod = modi;
}
- SC.RelocCrc = 0; // FIXME
+ sc.RelocCrc = 0; // FIXME
- return SC;
+ return sc;
}
static uint32_t
-translateStringTableIndex(uint32_t ObjIndex,
- const DebugStringTableSubsectionRef &ObjStrTable,
- DebugStringTableSubsection &PdbStrTable) {
- auto ExpectedString = ObjStrTable.getString(ObjIndex);
- if (!ExpectedString) {
+translateStringTableIndex(uint32_t objIndex,
+ const DebugStringTableSubsectionRef &objStrTable,
+ DebugStringTableSubsection &pdbStrTable) {
+ auto expectedString = objStrTable.getString(objIndex);
+ if (!expectedString) {
warn("Invalid string table reference");
- consumeError(ExpectedString.takeError());
+ consumeError(expectedString.takeError());
return 0;
}
- return PdbStrTable.insert(*ExpectedString);
+ return pdbStrTable.insert(*expectedString);
}
-void DebugSHandler::handleDebugS(lld::coff::SectionChunk &DebugS) {
- DebugSubsectionArray Subsections;
+void DebugSHandler::handleDebugS(lld::coff::SectionChunk &debugS) {
+ DebugSubsectionArray subsections;
- ArrayRef<uint8_t> RelocatedDebugContents = SectionChunk::consumeDebugMagic(
- relocateDebugChunk(Linker.Alloc, DebugS), DebugS.getSectionName());
+ ArrayRef<uint8_t> relocatedDebugContents = SectionChunk::consumeDebugMagic(
+ relocateDebugChunk(linker.alloc, debugS), debugS.getSectionName());
- BinaryStreamReader Reader(RelocatedDebugContents, support::little);
- ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size()));
+ BinaryStreamReader reader(relocatedDebugContents, support::little);
+ exitOnErr(reader.readArray(subsections, relocatedDebugContents.size()));
- for (const DebugSubsectionRecord &SS : Subsections) {
+ for (const DebugSubsectionRecord &ss : subsections) {
// Ignore subsections with the 'ignore' bit. Some versions of the Visual C++
// runtime have subsections with this bit set.
- if (uint32_t(SS.kind()) & codeview::SubsectionIgnoreFlag)
+ if (uint32_t(ss.kind()) & codeview::SubsectionIgnoreFlag)
continue;
- switch (SS.kind()) {
+ switch (ss.kind()) {
case DebugSubsectionKind::StringTable: {
- assert(!CVStrTab.valid() &&
+ assert(!cVStrTab.valid() &&
"Encountered multiple string table subsections!");
- ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+ exitOnErr(cVStrTab.initialize(ss.getRecordData()));
break;
}
case DebugSubsectionKind::FileChecksums:
- assert(!Checksums.valid() &&
+ assert(!checksums.valid() &&
"Encountered multiple checksum subsections!");
- ExitOnErr(Checksums.initialize(SS.getRecordData()));
+ exitOnErr(checksums.initialize(ss.getRecordData()));
break;
case DebugSubsectionKind::Lines:
// We can add the relocated line table directly to the PDB without
// modification because the file checksum offsets will stay the same.
- File.ModuleDBI->addDebugSubsection(SS);
+ file.moduleDBI->addDebugSubsection(ss);
break;
case DebugSubsectionKind::InlineeLines:
- assert(!InlineeLines.valid() &&
+ assert(!inlineeLines.valid() &&
"Encountered multiple inlinee lines subsections!");
- ExitOnErr(InlineeLines.initialize(SS.getRecordData()));
+ exitOnErr(inlineeLines.initialize(ss.getRecordData()));
break;
case DebugSubsectionKind::FrameData: {
// We need to re-write string table indices here, so save off all
// frame data subsections until we've processed the entire list of
// subsections so that we can be sure we have the string table.
- DebugFrameDataSubsectionRef FDS;
- ExitOnErr(FDS.initialize(SS.getRecordData()));
- NewFpoFrames.push_back(std::move(FDS));
+ DebugFrameDataSubsectionRef fds;
+ exitOnErr(fds.initialize(ss.getRecordData()));
+ newFpoFrames.push_back(std::move(fds));
break;
}
case DebugSubsectionKind::Symbols: {
- Linker.mergeSymbolRecords(&File, IndexMap, StringTableReferences,
- SS.getRecordData());
+ linker.mergeSymbolRecords(&file, indexMap, stringTableReferences,
+ ss.getRecordData());
break;
}
default:
warn("ignoring unknown debug$S subsection kind 0x" +
- utohexstr(uint32_t(SS.kind())) + " in file " + toString(&File));
+ utohexstr(uint32_t(ss.kind())) + " in file " + toString(&file));
break;
}
}
}
static Expected<StringRef>
-getFileName(const DebugStringTableSubsectionRef &Strings,
- const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {
- auto Iter = Checksums.getArray().at(FileID);
- if (Iter == Checksums.getArray().end())
+getFileName(const DebugStringTableSubsectionRef &strings,
+ const DebugChecksumsSubsectionRef &checksums, uint32_t fileID) {
+ auto iter = checksums.getArray().at(fileID);
+ if (iter == checksums.getArray().end())
return make_error<CodeViewError>(cv_error_code::no_records);
- uint32_t Offset = Iter->FileNameOffset;
- return Strings.getString(Offset);
+ uint32_t offset = iter->FileNameOffset;
+ return strings.getString(offset);
}
std::shared_ptr<DebugInlineeLinesSubsection>
-DebugSHandler::mergeInlineeLines(DebugChecksumsSubsection *NewChecksums) {
- auto NewInlineeLines = std::make_shared<DebugInlineeLinesSubsection>(
- *NewChecksums, InlineeLines.hasExtraFiles());
-
- for (const InlineeSourceLine &Line : InlineeLines) {
- TypeIndex Inlinee = Line.Header->Inlinee;
- uint32_t FileID = Line.Header->FileID;
- uint32_t SourceLine = Line.Header->SourceLineNum;
-
- ArrayRef<TypeIndex> TypeOrItemMap =
- IndexMap.IsTypeServerMap ? IndexMap.IPIMap : IndexMap.TPIMap;
- if (!remapTypeIndex(Inlinee, TypeOrItemMap)) {
- log("ignoring inlinee line record in " + File.getName() +
- " with bad inlinee index 0x" + utohexstr(Inlinee.getIndex()));
+DebugSHandler::mergeInlineeLines(DebugChecksumsSubsection *newChecksums) {
+ auto newInlineeLines = std::make_shared<DebugInlineeLinesSubsection>(
+ *newChecksums, inlineeLines.hasExtraFiles());
+
+ for (const InlineeSourceLine &line : inlineeLines) {
+ TypeIndex inlinee = line.Header->Inlinee;
+ uint32_t fileID = line.Header->FileID;
+ uint32_t sourceLine = line.Header->SourceLineNum;
+
+ ArrayRef<TypeIndex> typeOrItemMap =
+ indexMap.isTypeServerMap ? indexMap.ipiMap : indexMap.tpiMap;
+ if (!remapTypeIndex(inlinee, typeOrItemMap)) {
+ log("ignoring inlinee line record in " + file.getName() +
+ " with bad inlinee index 0x" + utohexstr(inlinee.getIndex()));
continue;
}
- SmallString<128> Filename =
- ExitOnErr(getFileName(CVStrTab, Checksums, FileID));
- pdbMakeAbsolute(Filename);
- NewInlineeLines->addInlineSite(Inlinee, Filename, SourceLine);
+ SmallString<128> filename =
+ exitOnErr(getFileName(cVStrTab, checksums, fileID));
+ pdbMakeAbsolute(filename);
+ newInlineeLines->addInlineSite(inlinee, filename, sourceLine);
- if (InlineeLines.hasExtraFiles()) {
- for (uint32_t ExtraFileId : Line.ExtraFiles) {
- Filename = ExitOnErr(getFileName(CVStrTab, Checksums, ExtraFileId));
- pdbMakeAbsolute(Filename);
- NewInlineeLines->addExtraFile(Filename);
+ if (inlineeLines.hasExtraFiles()) {
+ for (uint32_t extraFileId : line.ExtraFiles) {
+ filename = exitOnErr(getFileName(cVStrTab, checksums, extraFileId));
+ pdbMakeAbsolute(filename);
+ newInlineeLines->addExtraFile(filename);
}
}
}
- return NewInlineeLines;
+ return newInlineeLines;
}
void DebugSHandler::finish() {
- pdb::DbiStreamBuilder &DbiBuilder = Linker.Builder.getDbiBuilder();
+ pdb::DbiStreamBuilder &dbiBuilder = linker.builder.getDbiBuilder();
// We should have seen all debug subsections across the entire object file now
// which means that if a StringTable subsection and Checksums subsection were
// present, now is the time to handle them.
- if (!CVStrTab.valid()) {
- if (Checksums.valid())
+ if (!cVStrTab.valid()) {
+ if (checksums.valid())
fatal(".debug$S sections with a checksums subsection must also contain a "
"string table subsection");
- if (!StringTableReferences.empty())
+ if (!stringTableReferences.empty())
warn("No StringTable subsection was encountered, but there are string "
"table references");
return;
// Rewrite string table indices in the Fpo Data and symbol records to refer to
// the global PDB string table instead of the object file string table.
- for (DebugFrameDataSubsectionRef &FDS : NewFpoFrames) {
- const ulittle32_t *Reloc = FDS.getRelocPtr();
- for (codeview::FrameData FD : FDS) {
- FD.RvaStart += *Reloc;
- FD.FrameFunc =
- translateStringTableIndex(FD.FrameFunc, CVStrTab, Linker.PDBStrTab);
- DbiBuilder.addNewFpoData(FD);
+ for (DebugFrameDataSubsectionRef &fds : newFpoFrames) {
+ const ulittle32_t *reloc = fds.getRelocPtr();
+ for (codeview::FrameData fd : fds) {
+ fd.RvaStart += *reloc;
+ fd.FrameFunc =
+ translateStringTableIndex(fd.FrameFunc, cVStrTab, linker.pdbStrTab);
+ dbiBuilder.addNewFpoData(fd);
}
}
- for (ulittle32_t *Ref : StringTableReferences)
- *Ref = translateStringTableIndex(*Ref, CVStrTab, Linker.PDBStrTab);
+ for (ulittle32_t *ref : stringTableReferences)
+ *ref = translateStringTableIndex(*ref, cVStrTab, linker.pdbStrTab);
// Make a new file checksum table that refers to offsets in the PDB-wide
// string table. Generally the string table subsection appears after the
// checksum table, so we have to do this after looping over all the
// subsections.
- auto NewChecksums = make_unique<DebugChecksumsSubsection>(Linker.PDBStrTab);
- for (FileChecksumEntry &FC : Checksums) {
- SmallString<128> Filename =
- ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
- pdbMakeAbsolute(Filename);
- ExitOnErr(DbiBuilder.addModuleSourceFile(*File.ModuleDBI, Filename));
- NewChecksums->addChecksum(Filename, FC.Kind, FC.Checksum);
+ auto newChecksums = make_unique<DebugChecksumsSubsection>(linker.pdbStrTab);
+ for (FileChecksumEntry &fc : checksums) {
+ SmallString<128> filename =
+ exitOnErr(cVStrTab.getString(fc.FileNameOffset));
+ pdbMakeAbsolute(filename);
+ exitOnErr(dbiBuilder.addModuleSourceFile(*file.moduleDBI, filename));
+ newChecksums->addChecksum(filename, fc.Kind, fc.Checksum);
}
// Rewrite inlinee item indices if present.
- if (InlineeLines.valid())
- File.ModuleDBI->addDebugSubsection(mergeInlineeLines(NewChecksums.get()));
+ if (inlineeLines.valid())
+ file.moduleDBI->addDebugSubsection(mergeInlineeLines(newChecksums.get()));
- File.ModuleDBI->addDebugSubsection(std::move(NewChecksums));
+ file.moduleDBI->addDebugSubsection(std::move(newChecksums));
}
-void PDBLinker::addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap) {
- if (File->MergedIntoPDB)
+void PDBLinker::addObjFile(ObjFile *file, CVIndexMap *externIndexMap) {
+ if (file->mergedIntoPDB)
return;
- File->MergedIntoPDB = true;
+ file->mergedIntoPDB = true;
// Before we can process symbol substreams from .debug$S, we need to process
// type information, file checksums, and the string table. Add type info to
// the PDB first, so that we can get the map from object file type and item
// indices to PDB type and item indices.
- CVIndexMap ObjectIndexMap;
- auto IndexMapResult =
- mergeDebugT(File, ExternIndexMap ? ExternIndexMap : &ObjectIndexMap);
+ CVIndexMap objectIndexMap;
+ auto indexMapResult =
+ mergeDebugT(file, externIndexMap ? externIndexMap : &objectIndexMap);
// If the .debug$T sections fail to merge, assume there is no debug info.
- if (!IndexMapResult) {
- if (!Config->WarnDebugInfoUnusable) {
- consumeError(IndexMapResult.takeError());
+ if (!indexMapResult) {
+ if (!config->warnDebugInfoUnusable) {
+ consumeError(indexMapResult.takeError());
return;
}
- warn("Cannot use debug info for '" + toString(File) + "' [LNK4099]\n" +
+ warn("Cannot use debug info for '" + toString(file) + "' [LNK4099]\n" +
">>> failed to load reference " +
- StringRef(toString(IndexMapResult.takeError())));
+ StringRef(toString(indexMapResult.takeError())));
return;
}
- ScopedTimer T(SymbolMergingTimer);
+ ScopedTimer t(symbolMergingTimer);
- pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
- DebugSHandler DSH(*this, *File, *IndexMapResult);
+ pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
+ DebugSHandler dsh(*this, *file, *indexMapResult);
// Now do all live .debug$S and .debug$F sections.
- for (SectionChunk *DebugChunk : File->getDebugChunks()) {
- if (!DebugChunk->Live || DebugChunk->getSize() == 0)
+ for (SectionChunk *debugChunk : file->getDebugChunks()) {
+ if (!debugChunk->live || debugChunk->getSize() == 0)
continue;
- if (DebugChunk->getSectionName() == ".debug$S") {
- DSH.handleDebugS(*DebugChunk);
+ if (debugChunk->getSectionName() == ".debug$S") {
+ dsh.handleDebugS(*debugChunk);
continue;
}
- if (DebugChunk->getSectionName() == ".debug$F") {
- ArrayRef<uint8_t> RelocatedDebugContents =
- relocateDebugChunk(Alloc, *DebugChunk);
+ if (debugChunk->getSectionName() == ".debug$F") {
+ ArrayRef<uint8_t> relocatedDebugContents =
+ relocateDebugChunk(alloc, *debugChunk);
- FixedStreamArray<object::FpoData> FpoRecords;
- BinaryStreamReader Reader(RelocatedDebugContents, support::little);
- uint32_t Count = RelocatedDebugContents.size() / sizeof(object::FpoData);
- ExitOnErr(Reader.readArray(FpoRecords, Count));
+ FixedStreamArray<object::FpoData> fpoRecords;
+ BinaryStreamReader reader(relocatedDebugContents, support::little);
+ uint32_t count = relocatedDebugContents.size() / sizeof(object::FpoData);
+ exitOnErr(reader.readArray(fpoRecords, count));
// These are already relocated and don't refer to the string table, so we
// can just copy it.
- for (const object::FpoData &FD : FpoRecords)
- DbiBuilder.addOldFpoData(FD);
+ for (const object::FpoData &fd : fpoRecords)
+ dbiBuilder.addOldFpoData(fd);
continue;
}
}
// Do any post-processing now that all .debug$S sections have been processed.
- DSH.finish();
+ dsh.finish();
}
// Add a module descriptor for every object file. We need to put an absolute
// path to the object into the PDB. If this is a plain object, we make its
// path absolute. If it's an object in an archive, we make the archive path
// absolute.
-static void createModuleDBI(pdb::PDBFileBuilder &Builder) {
- pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
- SmallString<128> ObjName;
+static void createModuleDBI(pdb::PDBFileBuilder &builder) {
+ pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
+ SmallString<128> objName;
- for (ObjFile *File : ObjFile::Instances) {
+ for (ObjFile *file : ObjFile::instances) {
- bool InArchive = !File->ParentName.empty();
- ObjName = InArchive ? File->ParentName : File->getName();
- pdbMakeAbsolute(ObjName);
- StringRef ModName = InArchive ? File->getName() : StringRef(ObjName);
+ bool inArchive = !file->parentName.empty();
+ objName = inArchive ? file->parentName : file->getName();
+ pdbMakeAbsolute(objName);
+ StringRef modName = inArchive ? file->getName() : StringRef(objName);
- File->ModuleDBI = &ExitOnErr(DbiBuilder.addModuleInfo(ModName));
- File->ModuleDBI->setObjFileName(ObjName);
+ file->moduleDBI = &exitOnErr(dbiBuilder.addModuleInfo(modName));
+ file->moduleDBI->setObjFileName(objName);
- ArrayRef<Chunk *> Chunks = File->getChunks();
- uint32_t Modi = File->ModuleDBI->getModuleIndex();
+ ArrayRef<Chunk *> chunks = file->getChunks();
+ uint32_t modi = file->moduleDBI->getModuleIndex();
- for (Chunk *C : Chunks) {
- auto *SecChunk = dyn_cast<SectionChunk>(C);
- if (!SecChunk || !SecChunk->Live)
+ for (Chunk *c : chunks) {
+ auto *secChunk = dyn_cast<SectionChunk>(c);
+ if (!secChunk || !secChunk->live)
continue;
- pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi);
- File->ModuleDBI->setFirstSectionContrib(SC);
+ pdb::SectionContrib sc = createSectionContrib(secChunk, modi);
+ file->moduleDBI->setFirstSectionContrib(sc);
break;
}
}
}
-static PublicSym32 createPublic(Defined *Def) {
- PublicSym32 Pub(SymbolKind::S_PUB32);
- Pub.Name = Def->getName();
- if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
- if (D->getCOFFSymbol().isFunctionDefinition())
- Pub.Flags = PublicSymFlags::Function;
- } else if (isa<DefinedImportThunk>(Def)) {
- Pub.Flags = PublicSymFlags::Function;
+static PublicSym32 createPublic(Defined *def) {
+ PublicSym32 pub(SymbolKind::S_PUB32);
+ pub.Name = def->getName();
+ if (auto *d = dyn_cast<DefinedCOFF>(def)) {
+ if (d->getCOFFSymbol().isFunctionDefinition())
+ pub.Flags = PublicSymFlags::Function;
+ } else if (isa<DefinedImportThunk>(def)) {
+ pub.Flags = PublicSymFlags::Function;
}
- OutputSection *OS = Def->getChunk()->getOutputSection();
- assert(OS && "all publics should be in final image");
- Pub.Offset = Def->getRVA() - OS->getRVA();
- Pub.Segment = OS->SectionIndex;
- return Pub;
+ OutputSection *os = def->getChunk()->getOutputSection();
+ assert(os && "all publics should be in final image");
+ pub.Offset = def->getRVA() - os->getRVA();
+ pub.Segment = os->sectionIndex;
+ return pub;
}
// Add all object files to the PDB. Merge .debug$T sections into IpiData and
// TpiData.
void PDBLinker::addObjectsToPDB() {
- ScopedTimer T1(AddObjectsTimer);
+ ScopedTimer t1(addObjectsTimer);
- createModuleDBI(Builder);
+ createModuleDBI(builder);
- for (ObjFile *File : ObjFile::Instances)
- addObjFile(File);
+ for (ObjFile *file : ObjFile::instances)
+ addObjFile(file);
- Builder.getStringTableBuilder().setStrings(PDBStrTab);
- T1.stop();
+ builder.getStringTableBuilder().setStrings(pdbStrTab);
+ t1.stop();
// Construct TPI and IPI stream contents.
- ScopedTimer T2(TpiStreamLayoutTimer);
- addTypeInfo(Builder.getTpiBuilder(), TMerger.getTypeTable());
- addTypeInfo(Builder.getIpiBuilder(), TMerger.getIDTable());
- T2.stop();
+ ScopedTimer t2(tpiStreamLayoutTimer);
+ addTypeInfo(builder.getTpiBuilder(), tMerger.getTypeTable());
+ addTypeInfo(builder.getIpiBuilder(), tMerger.getIDTable());
+ t2.stop();
- ScopedTimer T3(GlobalsLayoutTimer);
+ ScopedTimer t3(globalsLayoutTimer);
// Compute the public and global symbols.
- auto &GsiBuilder = Builder.getGsiBuilder();
- std::vector<PublicSym32> Publics;
- Symtab->forEachSymbol([&Publics](Symbol *S) {
+ auto &gsiBuilder = builder.getGsiBuilder();
+ std::vector<PublicSym32> publics;
+ symtab->forEachSymbol([&publics](Symbol *s) {
// Only emit defined, live symbols that have a chunk.
- auto *Def = dyn_cast<Defined>(S);
- if (Def && Def->isLive() && Def->getChunk())
- Publics.push_back(createPublic(Def));
+ auto *def = dyn_cast<Defined>(s);
+ if (def && def->isLive() && def->getChunk())
+ publics.push_back(createPublic(def));
});
- if (!Publics.empty()) {
- PublicSymbols = Publics.size();
+ if (!publics.empty()) {
+ publicSymbols = publics.size();
// Sort the public symbols and add them to the stream.
- parallelSort(Publics, [](const PublicSym32 &L, const PublicSym32 &R) {
- return L.Name < R.Name;
+ parallelSort(publics, [](const PublicSym32 &l, const PublicSym32 &r) {
+ return l.Name < r.Name;
});
- for (const PublicSym32 &Pub : Publics)
- GsiBuilder.addPublicSymbol(Pub);
+ for (const PublicSym32 &pub : publics)
+ gsiBuilder.addPublicSymbol(pub);
}
}
void PDBLinker::printStats() {
- if (!Config->ShowSummary)
+ if (!config->showSummary)
return;
- SmallString<256> Buffer;
- raw_svector_ostream Stream(Buffer);
+ SmallString<256> buffer;
+ raw_svector_ostream stream(buffer);
- Stream << center_justify("Summary", 80) << '\n'
+ stream << center_justify("Summary", 80) << '\n'
<< std::string(80, '-') << '\n';
- auto Print = [&](uint64_t V, StringRef S) {
- Stream << format_decimal(V, 15) << " " << S << '\n';
+ auto print = [&](uint64_t v, StringRef s) {
+ stream << format_decimal(v, 15) << " " << s << '\n';
};
- Print(ObjFile::Instances.size(),
+ print(ObjFile::instances.size(),
"Input OBJ files (expanded from all cmd-line inputs)");
- Print(TypeServerIndexMappings.size(), "PDB type server dependencies");
- Print(PrecompTypeIndexMappings.size(), "Precomp OBJ dependencies");
- Print(TMerger.getTypeTable().size() + TMerger.getIDTable().size(),
+ print(typeServerIndexMappings.size(), "PDB type server dependencies");
+ print(precompTypeIndexMappings.size(), "Precomp OBJ dependencies");
+ print(tMerger.getTypeTable().size() + tMerger.getIDTable().size(),
"Merged TPI records");
- Print(PDBStrTab.size(), "Output PDB strings");
- Print(GlobalSymbols, "Global symbol records");
- Print(ModuleSymbols, "Module symbol records");
- Print(PublicSymbols, "Public symbol records");
+ print(pdbStrTab.size(), "Output PDB strings");
+ print(globalSymbols, "Global symbol records");
+ print(moduleSymbols, "Module symbol records");
+ print(publicSymbols, "Public symbol records");
- message(Buffer);
+ message(buffer);
}
void PDBLinker::addNatvisFiles() {
- for (StringRef File : Config->NatvisFiles) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> DataOrErr =
- MemoryBuffer::getFile(File);
- if (!DataOrErr) {
- warn("Cannot open input file: " + File);
+ for (StringRef file : config->natvisFiles) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> dataOrErr =
+ MemoryBuffer::getFile(file);
+ if (!dataOrErr) {
+ warn("Cannot open input file: " + file);
continue;
}
- Builder.addInjectedSource(File, std::move(*DataOrErr));
+ builder.addInjectedSource(file, std::move(*dataOrErr));
}
}
-static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) {
- switch (Machine) {
+static codeview::CPUType toCodeViewMachine(COFF::MachineTypes machine) {
+ switch (machine) {
case COFF::IMAGE_FILE_MACHINE_AMD64:
return codeview::CPUType::X64;
case COFF::IMAGE_FILE_MACHINE_ARM:
// Mimic MSVC which surrounds arguments containing whitespace with quotes.
// Double double-quotes are handled, so that the resulting string can be
// executed again on the cmd-line.
-static std::string quote(ArrayRef<StringRef> Args) {
- std::string R;
- R.reserve(256);
- for (StringRef A : Args) {
- if (!R.empty())
- R.push_back(' ');
- bool HasWS = A.find(' ') != StringRef::npos;
- bool HasQ = A.find('"') != StringRef::npos;
- if (HasWS || HasQ)
- R.push_back('"');
- if (HasQ) {
- SmallVector<StringRef, 4> S;
- A.split(S, '"');
- R.append(join(S, "\"\""));
+static std::string quote(ArrayRef<StringRef> args) {
+ std::string r;
+ r.reserve(256);
+ for (StringRef a : args) {
+ if (!r.empty())
+ r.push_back(' ');
+ bool hasWS = a.find(' ') != StringRef::npos;
+ bool hasQ = a.find('"') != StringRef::npos;
+ if (hasWS || hasQ)
+ r.push_back('"');
+ if (hasQ) {
+ SmallVector<StringRef, 4> s;
+ a.split(s, '"');
+ r.append(join(s, "\"\""));
} else {
- R.append(A);
+ r.append(a);
}
- if (HasWS || HasQ)
- R.push_back('"');
+ if (hasWS || hasQ)
+ r.push_back('"');
}
- return R;
+ return r;
}
-static void fillLinkerVerRecord(Compile3Sym &CS) {
- CS.Machine = toCodeViewMachine(Config->Machine);
+static void fillLinkerVerRecord(Compile3Sym &cs) {
+ cs.Machine = toCodeViewMachine(config->machine);
// Interestingly, if we set the string to 0.0.0.0, then when trying to view
// local variables WinDbg emits an error that private symbols are not present.
// By setting this to a valid MSVC linker version string, local variables are
// displayed properly. As such, even though it is not representative of
// LLVM's version information, we need this for compatibility.
- CS.Flags = CompileSym3Flags::None;
- CS.VersionBackendBuild = 25019;
- CS.VersionBackendMajor = 14;
- CS.VersionBackendMinor = 10;
- CS.VersionBackendQFE = 0;
+ cs.Flags = CompileSym3Flags::None;
+ cs.VersionBackendBuild = 25019;
+ cs.VersionBackendMajor = 14;
+ cs.VersionBackendMinor = 10;
+ cs.VersionBackendQFE = 0;
// MSVC also sets the frontend to 0.0.0.0 since this is specifically for the
// linker module (which is by definition a backend), so we don't need to do
// anything here. Also, it seems we can use "LLVM Linker" for the linker name
// without any problems. Only the backend version has to be hardcoded to a
// magic number.
- CS.VersionFrontendBuild = 0;
- CS.VersionFrontendMajor = 0;
- CS.VersionFrontendMinor = 0;
- CS.VersionFrontendQFE = 0;
- CS.Version = "LLVM Linker";
- CS.setLanguage(SourceLanguage::Link);
+ cs.VersionFrontendBuild = 0;
+ cs.VersionFrontendMajor = 0;
+ cs.VersionFrontendMinor = 0;
+ cs.VersionFrontendQFE = 0;
+ cs.Version = "LLVM Linker";
+ cs.setLanguage(SourceLanguage::Link);
}
-static void addCommonLinkerModuleSymbols(StringRef Path,
- pdb::DbiModuleDescriptorBuilder &Mod,
- BumpPtrAllocator &Allocator) {
- ObjNameSym ONS(SymbolRecordKind::ObjNameSym);
- EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym);
- Compile3Sym CS(SymbolRecordKind::Compile3Sym);
- fillLinkerVerRecord(CS);
+static void addCommonLinkerModuleSymbols(StringRef path,
+ pdb::DbiModuleDescriptorBuilder &mod,
+ BumpPtrAllocator &allocator) {
+ ObjNameSym ons(SymbolRecordKind::ObjNameSym);
+ EnvBlockSym ebs(SymbolRecordKind::EnvBlockSym);
+ Compile3Sym cs(SymbolRecordKind::Compile3Sym);
+ fillLinkerVerRecord(cs);
- ONS.Name = "* Linker *";
- ONS.Signature = 0;
+ ons.Name = "* Linker *";
+ ons.Signature = 0;
- ArrayRef<StringRef> Args = makeArrayRef(Config->Argv).drop_front();
- std::string ArgStr = quote(Args);
- EBS.Fields.push_back("cwd");
+ ArrayRef<StringRef> args = makeArrayRef(config->argv).drop_front();
+ std::string argStr = quote(args);
+ ebs.Fields.push_back("cwd");
SmallString<64> cwd;
- if (Config->PDBSourcePath.empty())
+ if (config->pdbSourcePath.empty())
sys::fs::current_path(cwd);
else
- cwd = Config->PDBSourcePath;
- EBS.Fields.push_back(cwd);
- EBS.Fields.push_back("exe");
- SmallString<64> exe = Config->Argv[0];
+ cwd = config->pdbSourcePath;
+ ebs.Fields.push_back(cwd);
+ ebs.Fields.push_back("exe");
+ SmallString<64> exe = config->argv[0];
pdbMakeAbsolute(exe);
- EBS.Fields.push_back(exe);
- EBS.Fields.push_back("pdb");
- EBS.Fields.push_back(Path);
- EBS.Fields.push_back("cmd");
- EBS.Fields.push_back(ArgStr);
- Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
- ONS, Allocator, CodeViewContainer::Pdb));
- Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
- CS, Allocator, CodeViewContainer::Pdb));
- Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
- EBS, Allocator, CodeViewContainer::Pdb));
+ ebs.Fields.push_back(exe);
+ ebs.Fields.push_back("pdb");
+ ebs.Fields.push_back(path);
+ ebs.Fields.push_back("cmd");
+ ebs.Fields.push_back(argStr);
+ mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ ons, allocator, CodeViewContainer::Pdb));
+ mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ cs, allocator, CodeViewContainer::Pdb));
+ mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ ebs, allocator, CodeViewContainer::Pdb));
}
-static void addLinkerModuleCoffGroup(PartialSection *Sec,
- pdb::DbiModuleDescriptorBuilder &Mod,
- OutputSection &OS,
- BumpPtrAllocator &Allocator) {
+static void addLinkerModuleCoffGroup(PartialSection *sec,
+ pdb::DbiModuleDescriptorBuilder &mod,
+ OutputSection &os,
+ BumpPtrAllocator &allocator) {
// If there's a section, there's at least one chunk
- assert(!Sec->Chunks.empty());
- const Chunk *firstChunk = *Sec->Chunks.begin();
- const Chunk *lastChunk = *Sec->Chunks.rbegin();
+ assert(!sec->chunks.empty());
+ const Chunk *firstChunk = *sec->chunks.begin();
+ const Chunk *lastChunk = *sec->chunks.rbegin();
// Emit COFF group
- CoffGroupSym CGS(SymbolRecordKind::CoffGroupSym);
- CGS.Name = Sec->Name;
- CGS.Segment = OS.SectionIndex;
- CGS.Offset = firstChunk->getRVA() - OS.getRVA();
- CGS.Size = lastChunk->getRVA() + lastChunk->getSize() - firstChunk->getRVA();
- CGS.Characteristics = Sec->Characteristics;
+ CoffGroupSym cgs(SymbolRecordKind::CoffGroupSym);
+ cgs.Name = sec->name;
+ cgs.Segment = os.sectionIndex;
+ cgs.Offset = firstChunk->getRVA() - os.getRVA();
+ cgs.Size = lastChunk->getRVA() + lastChunk->getSize() - firstChunk->getRVA();
+ cgs.Characteristics = sec->characteristics;
// Somehow .idata sections & sections groups in the debug symbol stream have
// the "write" flag set. However the section header for the corresponding
// .idata section doesn't have it.
- if (CGS.Name.startswith(".idata"))
- CGS.Characteristics |= llvm::COFF::IMAGE_SCN_MEM_WRITE;
+ if (cgs.Name.startswith(".idata"))
+ cgs.Characteristics |= llvm::COFF::IMAGE_SCN_MEM_WRITE;
- Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
- CGS, Allocator, CodeViewContainer::Pdb));
+ mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ cgs, allocator, CodeViewContainer::Pdb));
}
-static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod,
- OutputSection &OS,
- BumpPtrAllocator &Allocator) {
- SectionSym Sym(SymbolRecordKind::SectionSym);
- Sym.Alignment = 12; // 2^12 = 4KB
- Sym.Characteristics = OS.Header.Characteristics;
- Sym.Length = OS.getVirtualSize();
- Sym.Name = OS.Name;
- Sym.Rva = OS.getRVA();
- Sym.SectionNumber = OS.SectionIndex;
- Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
- Sym, Allocator, CodeViewContainer::Pdb));
+static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &mod,
+ OutputSection &os,
+ BumpPtrAllocator &allocator) {
+ SectionSym sym(SymbolRecordKind::SectionSym);
+ sym.Alignment = 12; // 2^12 = 4KB
+ sym.Characteristics = os.header.Characteristics;
+ sym.Length = os.getVirtualSize();
+ sym.Name = os.name;
+ sym.Rva = os.getRVA();
+ sym.SectionNumber = os.sectionIndex;
+ mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ sym, allocator, CodeViewContainer::Pdb));
// Skip COFF groups in MinGW because it adds a significant footprint to the
// PDB, due to each function being in its own section
- if (Config->MinGW)
+ if (config->mingw)
return;
// Output COFF groups for individual chunks of this section.
- for (PartialSection *Sec : OS.ContribSections) {
- addLinkerModuleCoffGroup(Sec, Mod, OS, Allocator);
+ for (PartialSection *sec : os.contribSections) {
+ addLinkerModuleCoffGroup(sec, mod, os, allocator);
}
}
// Add all import files as modules to the PDB.
-void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> OutputSections) {
- if (ImportFile::Instances.empty())
+void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
+ if (ImportFile::instances.empty())
return;
- std::map<std::string, llvm::pdb::DbiModuleDescriptorBuilder *> DllToModuleDbi;
+ std::map<std::string, llvm::pdb::DbiModuleDescriptorBuilder *> dllToModuleDbi;
- for (ImportFile *File : ImportFile::Instances) {
- if (!File->Live)
+ for (ImportFile *file : ImportFile::instances) {
+ if (!file->live)
continue;
- if (!File->ThunkSym)
+ if (!file->thunkSym)
continue;
- if (!File->ThunkLive)
+ if (!file->thunkLive)
continue;
- std::string DLL = StringRef(File->DLLName).lower();
- llvm::pdb::DbiModuleDescriptorBuilder *&Mod = DllToModuleDbi[DLL];
- if (!Mod) {
- pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
- SmallString<128> LibPath = File->ParentName;
- pdbMakeAbsolute(LibPath);
- sys::path::native(LibPath);
+ std::string dll = StringRef(file->dllName).lower();
+ llvm::pdb::DbiModuleDescriptorBuilder *&mod = dllToModuleDbi[dll];
+ if (!mod) {
+ pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
+ SmallString<128> libPath = file->parentName;
+ pdbMakeAbsolute(libPath);
+ sys::path::native(libPath);
// Name modules similar to MSVC's link.exe.
// The first module is the simple dll filename
- llvm::pdb::DbiModuleDescriptorBuilder &FirstMod =
- ExitOnErr(DbiBuilder.addModuleInfo(File->DLLName));
- FirstMod.setObjFileName(LibPath);
- pdb::SectionContrib SC =
+ llvm::pdb::DbiModuleDescriptorBuilder &firstMod =
+ exitOnErr(dbiBuilder.addModuleInfo(file->dllName));
+ firstMod.setObjFileName(libPath);
+ pdb::SectionContrib sc =
createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex);
- FirstMod.setFirstSectionContrib(SC);
+ firstMod.setFirstSectionContrib(sc);
// The second module is where the import stream goes.
- Mod = &ExitOnErr(DbiBuilder.addModuleInfo("Import:" + File->DLLName));
- Mod->setObjFileName(LibPath);
+ mod = &exitOnErr(dbiBuilder.addModuleInfo("Import:" + file->dllName));
+ mod->setObjFileName(libPath);
}
- DefinedImportThunk *Thunk = cast<DefinedImportThunk>(File->ThunkSym);
- Chunk *ThunkChunk = Thunk->getChunk();
- OutputSection *ThunkOS = ThunkChunk->getOutputSection();
+ DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym);
+ Chunk *thunkChunk = thunk->getChunk();
+ OutputSection *thunkOS = thunkChunk->getOutputSection();
- ObjNameSym ONS(SymbolRecordKind::ObjNameSym);
- Compile3Sym CS(SymbolRecordKind::Compile3Sym);
- Thunk32Sym TS(SymbolRecordKind::Thunk32Sym);
- ScopeEndSym ES(SymbolRecordKind::ScopeEndSym);
+ ObjNameSym ons(SymbolRecordKind::ObjNameSym);
+ Compile3Sym cs(SymbolRecordKind::Compile3Sym);
+ Thunk32Sym ts(SymbolRecordKind::Thunk32Sym);
+ ScopeEndSym es(SymbolRecordKind::ScopeEndSym);
- ONS.Name = File->DLLName;
- ONS.Signature = 0;
+ ons.Name = file->dllName;
+ ons.Signature = 0;
- fillLinkerVerRecord(CS);
+ fillLinkerVerRecord(cs);
- TS.Name = Thunk->getName();
- TS.Parent = 0;
- TS.End = 0;
- TS.Next = 0;
- TS.Thunk = ThunkOrdinal::Standard;
- TS.Length = ThunkChunk->getSize();
- TS.Segment = ThunkOS->SectionIndex;
- TS.Offset = ThunkChunk->getRVA() - ThunkOS->getRVA();
+ ts.Name = thunk->getName();
+ ts.Parent = 0;
+ ts.End = 0;
+ ts.Next = 0;
+ ts.Thunk = ThunkOrdinal::Standard;
+ ts.Length = thunkChunk->getSize();
+ ts.Segment = thunkOS->sectionIndex;
+ ts.Offset = thunkChunk->getRVA() - thunkOS->getRVA();
- Mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol(
- ONS, Alloc, CodeViewContainer::Pdb));
- Mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol(
- CS, Alloc, CodeViewContainer::Pdb));
+ mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ ons, alloc, CodeViewContainer::Pdb));
+ mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ cs, alloc, CodeViewContainer::Pdb));
- SmallVector<SymbolScope, 4> Scopes;
- CVSymbol NewSym = codeview::SymbolSerializer::writeOneSymbol(
- TS, Alloc, CodeViewContainer::Pdb);
- scopeStackOpen(Scopes, Mod->getNextSymbolOffset(), NewSym);
+ SmallVector<SymbolScope, 4> scopes;
+ CVSymbol newSym = codeview::SymbolSerializer::writeOneSymbol(
+ ts, alloc, CodeViewContainer::Pdb);
+ scopeStackOpen(scopes, mod->getNextSymbolOffset(), newSym);
- Mod->addSymbol(NewSym);
+ mod->addSymbol(newSym);
- NewSym = codeview::SymbolSerializer::writeOneSymbol(ES, Alloc,
+ newSym = codeview::SymbolSerializer::writeOneSymbol(es, alloc,
CodeViewContainer::Pdb);
- scopeStackClose(Scopes, Mod->getNextSymbolOffset(), File);
+ scopeStackClose(scopes, mod->getNextSymbolOffset(), file);
- Mod->addSymbol(NewSym);
+ mod->addSymbol(newSym);
- pdb::SectionContrib SC =
- createSectionContrib(Thunk->getChunk(), Mod->getModuleIndex());
- Mod->setFirstSectionContrib(SC);
+ pdb::SectionContrib sc =
+ createSectionContrib(thunk->getChunk(), mod->getModuleIndex());
+ mod->setFirstSectionContrib(sc);
}
}
// Creates a PDB file.
-void coff::createPDB(SymbolTable *Symtab,
- ArrayRef<OutputSection *> OutputSections,
- ArrayRef<uint8_t> SectionTable,
- llvm::codeview::DebugInfo *BuildId) {
- ScopedTimer T1(TotalPdbLinkTimer);
- PDBLinker PDB(Symtab);
-
- PDB.initialize(BuildId);
- PDB.addObjectsToPDB();
- PDB.addImportFilesToPDB(OutputSections);
- PDB.addSections(OutputSections, SectionTable);
- PDB.addNatvisFiles();
-
- ScopedTimer T2(DiskCommitTimer);
- codeview::GUID Guid;
- PDB.commit(&Guid);
- memcpy(&BuildId->PDB70.Signature, &Guid, 16);
-
- T2.stop();
- T1.stop();
- PDB.printStats();
+void coff::createPDB(SymbolTable *symtab,
+ ArrayRef<OutputSection *> outputSections,
+ ArrayRef<uint8_t> sectionTable,
+ llvm::codeview::DebugInfo *buildId) {
+ ScopedTimer t1(totalPdbLinkTimer);
+ PDBLinker pdb(symtab);
+
+ pdb.initialize(buildId);
+ pdb.addObjectsToPDB();
+ pdb.addImportFilesToPDB(outputSections);
+ pdb.addSections(outputSections, sectionTable);
+ pdb.addNatvisFiles();
+
+ ScopedTimer t2(diskCommitTimer);
+ codeview::GUID guid;
+ pdb.commit(&guid);
+ memcpy(&buildId->PDB70.Signature, &guid, 16);
+
+ t2.stop();
+ t1.stop();
+ pdb.printStats();
}
-void PDBLinker::initialize(llvm::codeview::DebugInfo *BuildId) {
- ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize
+void PDBLinker::initialize(llvm::codeview::DebugInfo *buildId) {
+ exitOnErr(builder.initialize(4096)); // 4096 is blocksize
- BuildId->Signature.CVSignature = OMF::Signature::PDB70;
+ buildId->Signature.CVSignature = OMF::Signature::PDB70;
// Signature is set to a hash of the PDB contents when the PDB is done.
- memset(BuildId->PDB70.Signature, 0, 16);
- BuildId->PDB70.Age = 1;
+ memset(buildId->PDB70.Signature, 0, 16);
+ buildId->PDB70.Age = 1;
// Create streams in MSF for predefined streams, namely
// PDB, TPI, DBI and IPI.
- for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
- ExitOnErr(Builder.getMsfBuilder().addStream(0));
+ for (int i = 0; i < (int)pdb::kSpecialStreamCount; ++i)
+ exitOnErr(builder.getMsfBuilder().addStream(0));
// Add an Info stream.
- auto &InfoBuilder = Builder.getInfoBuilder();
- InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
- InfoBuilder.setHashPDBContentsToGUID(true);
+ auto &infoBuilder = builder.getInfoBuilder();
+ infoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
+ infoBuilder.setHashPDBContentsToGUID(true);
// Add an empty DBI stream.
- pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
- DbiBuilder.setAge(BuildId->PDB70.Age);
- DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
- DbiBuilder.setMachineType(Config->Machine);
+ pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
+ dbiBuilder.setAge(buildId->PDB70.Age);
+ dbiBuilder.setVersionHeader(pdb::PdbDbiV70);
+ dbiBuilder.setMachineType(config->machine);
// Technically we are not link.exe 14.11, but there are known cases where
// debugging tools on Windows expect Microsoft-specific version numbers or
// they fail to work at all. Since we know we produce PDBs that are
// compatible with LINK 14.11, we set that version number here.
- DbiBuilder.setBuildNumber(14, 11);
+ dbiBuilder.setBuildNumber(14, 11);
}
-void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
- ArrayRef<uint8_t> SectionTable) {
+void PDBLinker::addSections(ArrayRef<OutputSection *> outputSections,
+ ArrayRef<uint8_t> sectionTable) {
// It's not entirely clear what this is, but the * Linker * module uses it.
- pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
- NativePath = Config->PDBPath;
- pdbMakeAbsolute(NativePath);
- uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
- auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
- LinkerModule.setPdbFilePathNI(PdbFilePathNI);
- addCommonLinkerModuleSymbols(NativePath, LinkerModule, Alloc);
+ pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
+ nativePath = config->pdbPath;
+ pdbMakeAbsolute(nativePath);
+ uint32_t pdbFilePathNI = dbiBuilder.addECName(nativePath);
+ auto &linkerModule = exitOnErr(dbiBuilder.addModuleInfo("* Linker *"));
+ linkerModule.setPdbFilePathNI(pdbFilePathNI);
+ addCommonLinkerModuleSymbols(nativePath, linkerModule, alloc);
// Add section contributions. They must be ordered by ascending RVA.
- for (OutputSection *OS : OutputSections) {
- addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc);
- for (Chunk *C : OS->Chunks) {
- pdb::SectionContrib SC =
- createSectionContrib(C, LinkerModule.getModuleIndex());
- Builder.getDbiBuilder().addSectionContrib(SC);
+ for (OutputSection *os : outputSections) {
+ addLinkerModuleSectionSymbol(linkerModule, *os, alloc);
+ for (Chunk *c : os->chunks) {
+ pdb::SectionContrib sc =
+ createSectionContrib(c, linkerModule.getModuleIndex());
+ builder.getDbiBuilder().addSectionContrib(sc);
}
}
// The * Linker * first section contrib is only used along with /INCREMENTAL,
// to provide trampolines thunks for incremental function patching. Set this
// as "unused" because LLD doesn't support /INCREMENTAL link.
- pdb::SectionContrib SC =
+ pdb::SectionContrib sc =
createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex);
- LinkerModule.setFirstSectionContrib(SC);
+ linkerModule.setFirstSectionContrib(sc);
// Add Section Map stream.
- ArrayRef<object::coff_section> Sections = {
- (const object::coff_section *)SectionTable.data(),
- SectionTable.size() / sizeof(object::coff_section)};
- SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections);
- DbiBuilder.setSectionMap(SectionMap);
+ ArrayRef<object::coff_section> sections = {
+ (const object::coff_section *)sectionTable.data(),
+ sectionTable.size() / sizeof(object::coff_section)};
+ sectionMap = pdb::DbiStreamBuilder::createSectionMap(sections);
+ dbiBuilder.setSectionMap(sectionMap);
// Add COFF section header stream.
- ExitOnErr(
- DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));
+ exitOnErr(
+ dbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, sectionTable));
}
-void PDBLinker::commit(codeview::GUID *Guid) {
+void PDBLinker::commit(codeview::GUID *guid) {
// Write to a file.
- ExitOnErr(Builder.commit(Config->PDBPath, Guid));
+ exitOnErr(builder.commit(config->pdbPath, guid));
}
static uint32_t getSecrelReloc() {
- switch (Config->Machine) {
+ switch (config->machine) {
case AMD64:
return COFF::IMAGE_REL_AMD64_SECREL;
case I386:
// that are used to interpret the line table, and the offset of Addr in the line
// table are stored in the output arguments. Returns whether a line table was
// found.
-static bool findLineTable(const SectionChunk *C, uint32_t Addr,
- DebugStringTableSubsectionRef &CVStrTab,
- DebugChecksumsSubsectionRef &Checksums,
- DebugLinesSubsectionRef &Lines,
- uint32_t &OffsetInLinetable) {
- ExitOnError ExitOnErr;
- uint32_t SecrelReloc = getSecrelReloc();
-
- for (SectionChunk *DbgC : C->File->getDebugChunks()) {
- if (DbgC->getSectionName() != ".debug$S")
+static bool findLineTable(const SectionChunk *c, uint32_t addr,
+ DebugStringTableSubsectionRef &cVStrTab,
+ DebugChecksumsSubsectionRef &checksums,
+ DebugLinesSubsectionRef &lines,
+ uint32_t &offsetInLinetable) {
+ ExitOnError exitOnErr;
+ uint32_t secrelReloc = getSecrelReloc();
+
+ for (SectionChunk *dbgC : c->file->getDebugChunks()) {
+ if (dbgC->getSectionName() != ".debug$S")
continue;
// Build a mapping of SECREL relocations in DbgC that refer to C.
- DenseMap<uint32_t, uint32_t> Secrels;
- for (const coff_relocation &R : DbgC->getRelocs()) {
- if (R.Type != SecrelReloc)
+ DenseMap<uint32_t, uint32_t> secrels;
+ for (const coff_relocation &r : dbgC->getRelocs()) {
+ if (r.Type != secrelReloc)
continue;
- if (auto *S = dyn_cast_or_null<DefinedRegular>(
- C->File->getSymbols()[R.SymbolTableIndex]))
- if (S->getChunk() == C)
- Secrels[R.VirtualAddress] = S->getValue();
+ if (auto *s = dyn_cast_or_null<DefinedRegular>(
+ c->file->getSymbols()[r.SymbolTableIndex]))
+ if (s->getChunk() == c)
+ secrels[r.VirtualAddress] = s->getValue();
}
- ArrayRef<uint8_t> Contents =
- SectionChunk::consumeDebugMagic(DbgC->getContents(), ".debug$S");
- DebugSubsectionArray Subsections;
- BinaryStreamReader Reader(Contents, support::little);
- ExitOnErr(Reader.readArray(Subsections, Contents.size()));
+ ArrayRef<uint8_t> contents =
+ SectionChunk::consumeDebugMagic(dbgC->getContents(), ".debug$S");
+ DebugSubsectionArray subsections;
+ BinaryStreamReader reader(contents, support::little);
+ exitOnErr(reader.readArray(subsections, contents.size()));
- for (const DebugSubsectionRecord &SS : Subsections) {
- switch (SS.kind()) {
+ for (const DebugSubsectionRecord &ss : subsections) {
+ switch (ss.kind()) {
case DebugSubsectionKind::StringTable: {
- assert(!CVStrTab.valid() &&
+ assert(!cVStrTab.valid() &&
"Encountered multiple string table subsections!");
- ExitOnErr(CVStrTab.initialize(SS.getRecordData()));
+ exitOnErr(cVStrTab.initialize(ss.getRecordData()));
break;
}
case DebugSubsectionKind::FileChecksums:
- assert(!Checksums.valid() &&
+ assert(!checksums.valid() &&
"Encountered multiple checksum subsections!");
- ExitOnErr(Checksums.initialize(SS.getRecordData()));
+ exitOnErr(checksums.initialize(ss.getRecordData()));
break;
case DebugSubsectionKind::Lines: {
- ArrayRef<uint8_t> Bytes;
- auto Ref = SS.getRecordData();
- ExitOnErr(Ref.readLongestContiguousChunk(0, Bytes));
- size_t OffsetInDbgC = Bytes.data() - DbgC->getContents().data();
+ ArrayRef<uint8_t> bytes;
+ auto ref = ss.getRecordData();
+ exitOnErr(ref.readLongestContiguousChunk(0, bytes));
+ size_t offsetInDbgC = bytes.data() - dbgC->getContents().data();
// Check whether this line table refers to C.
- auto I = Secrels.find(OffsetInDbgC);
- if (I == Secrels.end())
+ auto i = secrels.find(offsetInDbgC);
+ if (i == secrels.end())
break;
// Check whether this line table covers Addr in C.
- DebugLinesSubsectionRef LinesTmp;
- ExitOnErr(LinesTmp.initialize(BinaryStreamReader(Ref)));
- uint32_t OffsetInC = I->second + LinesTmp.header()->RelocOffset;
- if (Addr < OffsetInC || Addr >= OffsetInC + LinesTmp.header()->CodeSize)
+ DebugLinesSubsectionRef linesTmp;
+ exitOnErr(linesTmp.initialize(BinaryStreamReader(ref)));
+ uint32_t offsetInC = i->second + linesTmp.header()->RelocOffset;
+ if (addr < offsetInC || addr >= offsetInC + linesTmp.header()->CodeSize)
break;
- assert(!Lines.header() &&
+ assert(!lines.header() &&
"Encountered multiple line tables for function!");
- ExitOnErr(Lines.initialize(BinaryStreamReader(Ref)));
- OffsetInLinetable = Addr - OffsetInC;
+ exitOnErr(lines.initialize(BinaryStreamReader(ref)));
+ offsetInLinetable = addr - offsetInC;
break;
}
default:
break;
}
- if (CVStrTab.valid() && Checksums.valid() && Lines.header())
+ if (cVStrTab.valid() && checksums.valid() && lines.header())
return true;
}
}
// Use CodeView line tables to resolve a file and line number for the given
// offset into the given chunk and return them, or {"", 0} if a line table was
// not found.
-std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *C,
- uint32_t Addr) {
- ExitOnError ExitOnErr;
+std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *c,
+ uint32_t addr) {
+ ExitOnError exitOnErr;
- DebugStringTableSubsectionRef CVStrTab;
- DebugChecksumsSubsectionRef Checksums;
- DebugLinesSubsectionRef Lines;
- uint32_t OffsetInLinetable;
+ DebugStringTableSubsectionRef cVStrTab;
+ DebugChecksumsSubsectionRef checksums;
+ DebugLinesSubsectionRef lines;
+ uint32_t offsetInLinetable;
- if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable))
+ if (!findLineTable(c, addr, cVStrTab, checksums, lines, offsetInLinetable))
return {"", 0};
- Optional<uint32_t> NameIndex;
- Optional<uint32_t> LineNumber;
- for (LineColumnEntry &Entry : Lines) {
- for (const LineNumberEntry &LN : Entry.LineNumbers) {
- LineInfo LI(LN.Flags);
- if (LN.Offset > OffsetInLinetable) {
- if (!NameIndex) {
- NameIndex = Entry.NameIndex;
- LineNumber = LI.getStartLine();
+ Optional<uint32_t> nameIndex;
+ Optional<uint32_t> lineNumber;
+ for (LineColumnEntry &entry : lines) {
+ for (const LineNumberEntry &ln : entry.LineNumbers) {
+ LineInfo li(ln.Flags);
+ if (ln.Offset > offsetInLinetable) {
+ if (!nameIndex) {
+ nameIndex = entry.NameIndex;
+ lineNumber = li.getStartLine();
}
- StringRef Filename =
- ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex));
- return {Filename, *LineNumber};
+ StringRef filename =
+ exitOnErr(getFileName(cVStrTab, checksums, *nameIndex));
+ return {filename, *lineNumber};
}
- NameIndex = Entry.NameIndex;
- LineNumber = LI.getStartLine();
+ nameIndex = entry.NameIndex;
+ lineNumber = li.getStartLine();
}
}
- if (!NameIndex)
+ if (!nameIndex)
return {"", 0};
- StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex));
- return {Filename, *LineNumber};
+ StringRef filename = exitOnErr(getFileName(cVStrTab, checksums, *nameIndex));
+ return {filename, *lineNumber};
}
class SectionChunk;
class SymbolTable;
-void createPDB(SymbolTable *Symtab,
- llvm::ArrayRef<OutputSection *> OutputSections,
- llvm::ArrayRef<uint8_t> SectionTable,
- llvm::codeview::DebugInfo *BuildId);
+void createPDB(SymbolTable *symtab,
+ llvm::ArrayRef<OutputSection *> outputSections,
+ llvm::ArrayRef<uint8_t> sectionTable,
+ llvm::codeview::DebugInfo *buildId);
-std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *C,
- uint32_t Addr);
+std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *c,
+ uint32_t addr);
}
}
namespace lld {
namespace coff {
-static Timer LTOTimer("LTO", Timer::root());
+static Timer ltoTimer("LTO", Timer::root());
-SymbolTable *Symtab;
+SymbolTable *symtab;
-void SymbolTable::addFile(InputFile *File) {
- log("Reading " + toString(File));
- File->parse();
+void SymbolTable::addFile(InputFile *file) {
+ log("Reading " + toString(file));
+ file->parse();
- MachineTypes MT = File->getMachineType();
- if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
- Config->Machine = MT;
- } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) {
- error(toString(File) + ": machine type " + machineToStr(MT) +
- " conflicts with " + machineToStr(Config->Machine));
+ MachineTypes mt = file->getMachineType();
+ if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+ config->machine = mt;
+ } else if (mt != IMAGE_FILE_MACHINE_UNKNOWN && config->machine != mt) {
+ error(toString(file) + ": machine type " + machineToStr(mt) +
+ " conflicts with " + machineToStr(config->machine));
return;
}
- if (auto *F = dyn_cast<ObjFile>(File)) {
- ObjFile::Instances.push_back(F);
- } else if (auto *F = dyn_cast<BitcodeFile>(File)) {
- BitcodeFile::Instances.push_back(F);
- } else if (auto *F = dyn_cast<ImportFile>(File)) {
- ImportFile::Instances.push_back(F);
+ if (auto *f = dyn_cast<ObjFile>(file)) {
+ ObjFile::instances.push_back(f);
+ } else if (auto *f = dyn_cast<BitcodeFile>(file)) {
+ BitcodeFile::instances.push_back(f);
+ } else if (auto *f = dyn_cast<ImportFile>(file)) {
+ ImportFile::instances.push_back(f);
}
- Driver->parseDirectives(File);
+ driver->parseDirectives(file);
}
-static void errorOrWarn(const Twine &S) {
- if (Config->ForceUnresolved)
- warn(S);
+static void errorOrWarn(const Twine &s) {
+ if (config->forceUnresolved)
+ warn(s);
else
- error(S);
+ error(s);
}
// Returns the symbol in SC whose value is <= Addr that is closest to Addr.
// This is generally the global variable or function whose definition contains
// Addr.
-static Symbol *getSymbol(SectionChunk *SC, uint32_t Addr) {
- DefinedRegular *Candidate = nullptr;
+static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
+ DefinedRegular *candidate = nullptr;
- for (Symbol *S : SC->File->getSymbols()) {
- auto *D = dyn_cast_or_null<DefinedRegular>(S);
- if (!D || D->getChunk() != SC || D->getValue() > Addr ||
- (Candidate && D->getValue() < Candidate->getValue()))
+ for (Symbol *s : sc->file->getSymbols()) {
+ auto *d = dyn_cast_or_null<DefinedRegular>(s);
+ if (!d || d->getChunk() != sc || d->getValue() > addr ||
+ (candidate && d->getValue() < candidate->getValue()))
continue;
- Candidate = D;
+ candidate = d;
}
- return Candidate;
+ return candidate;
}
// Given a file and the index of a symbol in that file, returns a description
// of all references to that symbol from that file. If no debug information is
// available, returns just the name of the file, else one string per actual
// reference as described in the debug info.
-std::vector<std::string> getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
+std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
struct Location {
- Symbol *Sym;
- std::pair<StringRef, uint32_t> FileLine;
+ Symbol *sym;
+ std::pair<StringRef, uint32_t> fileLine;
};
- std::vector<Location> Locations;
+ std::vector<Location> locations;
- for (Chunk *C : File->getChunks()) {
- auto *SC = dyn_cast<SectionChunk>(C);
- if (!SC)
+ for (Chunk *c : file->getChunks()) {
+ auto *sc = dyn_cast<SectionChunk>(c);
+ if (!sc)
continue;
- for (const coff_relocation &R : SC->getRelocs()) {
- if (R.SymbolTableIndex != SymIndex)
+ for (const coff_relocation &r : sc->getRelocs()) {
+ if (r.SymbolTableIndex != symIndex)
continue;
- std::pair<StringRef, uint32_t> FileLine =
- getFileLine(SC, R.VirtualAddress);
- Symbol *Sym = getSymbol(SC, R.VirtualAddress);
- if (!FileLine.first.empty() || Sym)
- Locations.push_back({Sym, FileLine});
+ std::pair<StringRef, uint32_t> fileLine =
+ getFileLine(sc, r.VirtualAddress);
+ Symbol *sym = getSymbol(sc, r.VirtualAddress);
+ if (!fileLine.first.empty() || sym)
+ locations.push_back({sym, fileLine});
}
}
- if (Locations.empty())
- return std::vector<std::string>({"\n>>> referenced by " + toString(File)});
+ if (locations.empty())
+ return std::vector<std::string>({"\n>>> referenced by " + toString(file)});
- std::vector<std::string> SymbolLocations(Locations.size());
- size_t I = 0;
- for (Location Loc : Locations) {
- llvm::raw_string_ostream OS(SymbolLocations[I++]);
- OS << "\n>>> referenced by ";
- if (!Loc.FileLine.first.empty())
- OS << Loc.FileLine.first << ":" << Loc.FileLine.second
+ std::vector<std::string> symbolLocations(locations.size());
+ size_t i = 0;
+ for (Location loc : locations) {
+ llvm::raw_string_ostream os(symbolLocations[i++]);
+ os << "\n>>> referenced by ";
+ if (!loc.fileLine.first.empty())
+ os << loc.fileLine.first << ":" << loc.fileLine.second
<< "\n>>> ";
- OS << toString(File);
- if (Loc.Sym)
- OS << ":(" << toString(*Loc.Sym) << ')';
+ os << toString(file);
+ if (loc.sym)
+ os << ":(" << toString(*loc.sym) << ')';
}
- return SymbolLocations;
+ return symbolLocations;
}
// For an undefined symbol, stores all files referencing it and the index of
// the undefined symbol in each file.
struct UndefinedDiag {
- Symbol *Sym;
+ Symbol *sym;
struct File {
- ObjFile *OFile;
- uint64_t SymIndex;
+ ObjFile *oFile;
+ uint64_t symIndex;
};
- std::vector<File> Files;
+ std::vector<File> files;
};
-static void reportUndefinedSymbol(const UndefinedDiag &UndefDiag) {
- std::string Out;
- llvm::raw_string_ostream OS(Out);
- OS << "undefined symbol: " << toString(*UndefDiag.Sym);
-
- const size_t MaxUndefReferences = 10;
- size_t I = 0, NumRefs = 0;
- for (const UndefinedDiag::File &Ref : UndefDiag.Files) {
- std::vector<std::string> SymbolLocations =
- getSymbolLocations(Ref.OFile, Ref.SymIndex);
- NumRefs += SymbolLocations.size();
- for (const std::string &S : SymbolLocations) {
- if (I >= MaxUndefReferences)
+static void reportUndefinedSymbol(const UndefinedDiag &undefDiag) {
+ std::string out;
+ llvm::raw_string_ostream os(out);
+ os << "undefined symbol: " << toString(*undefDiag.sym);
+
+ const size_t maxUndefReferences = 10;
+ size_t i = 0, numRefs = 0;
+ for (const UndefinedDiag::File &ref : undefDiag.files) {
+ std::vector<std::string> symbolLocations =
+ getSymbolLocations(ref.oFile, ref.symIndex);
+ numRefs += symbolLocations.size();
+ for (const std::string &s : symbolLocations) {
+ if (i >= maxUndefReferences)
break;
- OS << S;
- I++;
+ os << s;
+ i++;
}
}
- if (I < NumRefs)
- OS << "\n>>> referenced " << NumRefs - I << " more times";
- errorOrWarn(OS.str());
+ if (i < numRefs)
+ os << "\n>>> referenced " << numRefs - i << " more times";
+ errorOrWarn(os.str());
}
void SymbolTable::loadMinGWAutomaticImports() {
- for (auto &I : SymMap) {
- Symbol *Sym = I.second;
- auto *Undef = dyn_cast<Undefined>(Sym);
- if (!Undef)
+ for (auto &i : symMap) {
+ Symbol *sym = i.second;
+ auto *undef = dyn_cast<Undefined>(sym);
+ if (!undef)
continue;
- if (!Sym->IsUsedInRegularObj)
+ if (!sym->isUsedInRegularObj)
continue;
- StringRef Name = Undef->getName();
+ StringRef name = undef->getName();
- if (Name.startswith("__imp_"))
+ if (name.startswith("__imp_"))
continue;
// If we have an undefined symbol, but we have a Lazy representing a
// symbol we could load from file, make sure to load that.
- Lazy *L = dyn_cast_or_null<Lazy>(find(("__imp_" + Name).str()));
- if (!L || L->PendingArchiveLoad)
+ Lazy *l = dyn_cast_or_null<Lazy>(find(("__imp_" + name).str()));
+ if (!l || l->pendingArchiveLoad)
continue;
- log("Loading lazy " + L->getName() + " from " + L->File->getName() +
+ log("Loading lazy " + l->getName() + " from " + l->file->getName() +
" for automatic import");
- L->PendingArchiveLoad = true;
- L->File->addMember(&L->Sym);
+ l->pendingArchiveLoad = true;
+ l->file->addMember(&l->sym);
}
}
-bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) {
- if (Name.startswith("__imp_"))
+bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
+ if (name.startswith("__imp_"))
return false;
- Defined *Imp = dyn_cast_or_null<Defined>(find(("__imp_" + Name).str()));
- if (!Imp)
+ Defined *imp = dyn_cast_or_null<Defined>(find(("__imp_" + name).str()));
+ if (!imp)
return false;
// Replace the reference directly to a variable with a reference
// will add runtime pseudo relocations for every relocation against
// this Symbol. The runtime pseudo relocation framework expects the
// reference itself to point at the IAT entry.
- size_t ImpSize = 0;
- if (isa<DefinedImportData>(Imp)) {
- log("Automatically importing " + Name + " from " +
- cast<DefinedImportData>(Imp)->getDLLName());
- ImpSize = sizeof(DefinedImportData);
- } else if (isa<DefinedRegular>(Imp)) {
- log("Automatically importing " + Name + " from " +
- toString(cast<DefinedRegular>(Imp)->File));
- ImpSize = sizeof(DefinedRegular);
+ size_t impSize = 0;
+ if (isa<DefinedImportData>(imp)) {
+ log("Automatically importing " + name + " from " +
+ cast<DefinedImportData>(imp)->getDLLName());
+ impSize = sizeof(DefinedImportData);
+ } else if (isa<DefinedRegular>(imp)) {
+ log("Automatically importing " + name + " from " +
+ toString(cast<DefinedRegular>(imp)->file));
+ impSize = sizeof(DefinedRegular);
} else {
- warn("unable to automatically import " + Name + " from " + Imp->getName() +
- " from " + toString(cast<DefinedRegular>(Imp)->File) +
+ warn("unable to automatically import " + name + " from " + imp->getName() +
+ " from " + toString(cast<DefinedRegular>(imp)->file) +
"; unexpected symbol type");
return false;
}
- Sym->replaceKeepingName(Imp, ImpSize);
- Sym->IsRuntimePseudoReloc = true;
+ sym->replaceKeepingName(imp, impSize);
+ sym->isRuntimePseudoReloc = true;
// There may exist symbols named .refptr.<name> which only consist
// of a single pointer to <name>. If it turns out <name> is
// automatically imported, we don't need to keep the .refptr.<name>
// pointer at all, but redirect all accesses to it to the IAT entry
// for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
- DefinedRegular *Refptr =
- dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str()));
- if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) {
- SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk());
- if (SC && SC->getRelocs().size() == 1 && *SC->symbols().begin() == Sym) {
- log("Replacing .refptr." + Name + " with " + Imp->getName());
- Refptr->getChunk()->Live = false;
- Refptr->replaceKeepingName(Imp, ImpSize);
+ DefinedRegular *refptr =
+ dyn_cast_or_null<DefinedRegular>(find((".refptr." + name).str()));
+ if (refptr && refptr->getChunk()->getSize() == config->wordsize) {
+ SectionChunk *sc = dyn_cast_or_null<SectionChunk>(refptr->getChunk());
+ if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) {
+ log("Replacing .refptr." + name + " with " + imp->getName());
+ refptr->getChunk()->live = false;
+ refptr->replaceKeepingName(imp, impSize);
}
}
return true;
}
void SymbolTable::reportRemainingUndefines() {
- SmallPtrSet<Symbol *, 8> Undefs;
- DenseMap<Symbol *, Symbol *> LocalImports;
+ SmallPtrSet<Symbol *, 8> undefs;
+ DenseMap<Symbol *, Symbol *> localImports;
- for (auto &I : SymMap) {
- Symbol *Sym = I.second;
- auto *Undef = dyn_cast<Undefined>(Sym);
- if (!Undef)
+ for (auto &i : symMap) {
+ Symbol *sym = i.second;
+ auto *undef = dyn_cast<Undefined>(sym);
+ if (!undef)
continue;
- if (!Sym->IsUsedInRegularObj)
+ if (!sym->isUsedInRegularObj)
continue;
- StringRef Name = Undef->getName();
+ StringRef name = undef->getName();
// A weak alias may have been resolved, so check for that.
- if (Defined *D = Undef->getWeakAlias()) {
+ if (Defined *d = undef->getWeakAlias()) {
// We want to replace Sym with D. However, we can't just blindly
// copy sizeof(SymbolUnion) bytes from D to Sym because D may be an
// internal symbol, and internal symbols are stored as "unparented"
// Symbols. For that reason we need to check which type of symbol we
// are dealing with and copy the correct number of bytes.
- if (isa<DefinedRegular>(D))
- memcpy(Sym, D, sizeof(DefinedRegular));
- else if (isa<DefinedAbsolute>(D))
- memcpy(Sym, D, sizeof(DefinedAbsolute));
+ if (isa<DefinedRegular>(d))
+ memcpy(sym, d, sizeof(DefinedRegular));
+ else if (isa<DefinedAbsolute>(d))
+ memcpy(sym, d, sizeof(DefinedAbsolute));
else
- memcpy(Sym, D, sizeof(SymbolUnion));
+ memcpy(sym, d, sizeof(SymbolUnion));
continue;
}
// If we can resolve a symbol by removing __imp_ prefix, do that.
// This odd rule is for compatibility with MSVC linker.
- if (Name.startswith("__imp_")) {
- Symbol *Imp = find(Name.substr(strlen("__imp_")));
- if (Imp && isa<Defined>(Imp)) {
- auto *D = cast<Defined>(Imp);
- replaceSymbol<DefinedLocalImport>(Sym, Name, D);
- LocalImportChunks.push_back(cast<DefinedLocalImport>(Sym)->getChunk());
- LocalImports[Sym] = D;
+ if (name.startswith("__imp_")) {
+ Symbol *imp = find(name.substr(strlen("__imp_")));
+ if (imp && isa<Defined>(imp)) {
+ auto *d = cast<Defined>(imp);
+ replaceSymbol<DefinedLocalImport>(sym, name, d);
+ localImportChunks.push_back(cast<DefinedLocalImport>(sym)->getChunk());
+ localImports[sym] = d;
continue;
}
}
// We don't want to report missing Microsoft precompiled headers symbols.
// A proper message will be emitted instead in PDBLinker::aquirePrecompObj
- if (Name.contains("_PchSym_"))
+ if (name.contains("_PchSym_"))
continue;
- if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name))
+ if (config->mingw && handleMinGWAutomaticImport(sym, name))
continue;
// Remaining undefined symbols are not fatal if /force is specified.
// They are replaced with dummy defined symbols.
- if (Config->ForceUnresolved)
- replaceSymbol<DefinedAbsolute>(Sym, Name, 0);
- Undefs.insert(Sym);
+ if (config->forceUnresolved)
+ replaceSymbol<DefinedAbsolute>(sym, name, 0);
+ undefs.insert(sym);
}
- if (Undefs.empty() && LocalImports.empty())
+ if (undefs.empty() && localImports.empty())
return;
- for (Symbol *B : Config->GCRoot) {
- if (Undefs.count(B))
- errorOrWarn("<root>: undefined symbol: " + toString(*B));
- if (Config->WarnLocallyDefinedImported)
- if (Symbol *Imp = LocalImports.lookup(B))
- warn("<root>: locally defined symbol imported: " + toString(*Imp) +
- " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
+ for (Symbol *b : config->gCRoot) {
+ if (undefs.count(b))
+ errorOrWarn("<root>: undefined symbol: " + toString(*b));
+ if (config->warnLocallyDefinedImported)
+ if (Symbol *imp = localImports.lookup(b))
+ warn("<root>: locally defined symbol imported: " + toString(*imp) +
+ " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
}
- std::vector<UndefinedDiag> UndefDiags;
- DenseMap<Symbol *, int> FirstDiag;
+ std::vector<UndefinedDiag> undefDiags;
+ DenseMap<Symbol *, int> firstDiag;
- for (ObjFile *File : ObjFile::Instances) {
- size_t SymIndex = (size_t)-1;
- for (Symbol *Sym : File->getSymbols()) {
- ++SymIndex;
- if (!Sym)
+ for (ObjFile *file : ObjFile::instances) {
+ size_t symIndex = (size_t)-1;
+ for (Symbol *sym : file->getSymbols()) {
+ ++symIndex;
+ if (!sym)
continue;
- if (Undefs.count(Sym)) {
- auto it = FirstDiag.find(Sym);
- if (it == FirstDiag.end()) {
- FirstDiag[Sym] = UndefDiags.size();
- UndefDiags.push_back({Sym, {{File, SymIndex}}});
+ if (undefs.count(sym)) {
+ auto it = firstDiag.find(sym);
+ if (it == firstDiag.end()) {
+ firstDiag[sym] = undefDiags.size();
+ undefDiags.push_back({sym, {{file, symIndex}}});
} else {
- UndefDiags[it->second].Files.push_back({File, SymIndex});
+ undefDiags[it->second].files.push_back({file, symIndex});
}
}
- if (Config->WarnLocallyDefinedImported)
- if (Symbol *Imp = LocalImports.lookup(Sym))
- warn(toString(File) +
- ": locally defined symbol imported: " + toString(*Imp) +
- " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
+ if (config->warnLocallyDefinedImported)
+ if (Symbol *imp = localImports.lookup(sym))
+ warn(toString(file) +
+ ": locally defined symbol imported: " + toString(*imp) +
+ " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
}
}
- for (const UndefinedDiag& UndefDiag : UndefDiags)
- reportUndefinedSymbol(UndefDiag);
+ for (const UndefinedDiag& undefDiag : undefDiags)
+ reportUndefinedSymbol(undefDiag);
}
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
- bool Inserted = false;
- Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
- if (!Sym) {
- Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Sym->IsUsedInRegularObj = false;
- Sym->PendingArchiveLoad = false;
- Inserted = true;
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
+ bool inserted = false;
+ Symbol *&sym = symMap[CachedHashStringRef(name)];
+ if (!sym) {
+ sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ sym->isUsedInRegularObj = false;
+ sym->pendingArchiveLoad = false;
+ inserted = true;
}
- return {Sym, Inserted};
+ return {sym, inserted};
}
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
- std::pair<Symbol *, bool> Result = insert(Name);
- if (!File || !isa<BitcodeFile>(File))
- Result.first->IsUsedInRegularObj = true;
- return Result;
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef name, InputFile *file) {
+ std::pair<Symbol *, bool> result = insert(name);
+ if (!file || !isa<BitcodeFile>(file))
+ result.first->isUsedInRegularObj = true;
+ return result;
}
-Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F,
- bool IsWeakAlias) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, F);
- if (WasInserted || (isa<Lazy>(S) && IsWeakAlias)) {
- replaceSymbol<Undefined>(S, Name);
- return S;
+Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
+ bool isWeakAlias) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, f);
+ if (wasInserted || (isa<Lazy>(s) && isWeakAlias)) {
+ replaceSymbol<Undefined>(s, name);
+ return s;
}
- if (auto *L = dyn_cast<Lazy>(S)) {
- if (!S->PendingArchiveLoad) {
- S->PendingArchiveLoad = true;
- L->File->addMember(&L->Sym);
+ if (auto *l = dyn_cast<Lazy>(s)) {
+ if (!s->pendingArchiveLoad) {
+ s->pendingArchiveLoad = true;
+ l->file->addMember(&l->sym);
}
}
- return S;
+ return s;
}
-void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
- StringRef Name = Sym.getName();
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- if (WasInserted) {
- replaceSymbol<Lazy>(S, F, Sym);
+void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol sym) {
+ StringRef name = sym.getName();
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name);
+ if (wasInserted) {
+ replaceSymbol<Lazy>(s, f, sym);
return;
}
- auto *U = dyn_cast<Undefined>(S);
- if (!U || U->WeakAlias || S->PendingArchiveLoad)
+ auto *u = dyn_cast<Undefined>(s);
+ if (!u || u->weakAlias || s->pendingArchiveLoad)
return;
- S->PendingArchiveLoad = true;
- F->addMember(&Sym);
+ s->pendingArchiveLoad = true;
+ f->addMember(&sym);
}
-void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
- std::string Msg = "duplicate symbol: " + toString(*Existing) + " in " +
- toString(Existing->getFile()) + " and in " +
- toString(NewFile);
+void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) {
+ std::string msg = "duplicate symbol: " + toString(*existing) + " in " +
+ toString(existing->getFile()) + " and in " +
+ toString(newFile);
- if (Config->ForceMultiple)
- warn(Msg);
+ if (config->forceMultiple)
+ warn(msg);
else
- error(Msg);
+ error(msg);
}
-Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(N, nullptr);
- S->IsUsedInRegularObj = true;
- if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
- replaceSymbol<DefinedAbsolute>(S, N, Sym);
- else if (!isa<DefinedCOFF>(S))
- reportDuplicate(S, nullptr);
- return S;
+Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(n, nullptr);
+ s->isUsedInRegularObj = true;
+ if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+ replaceSymbol<DefinedAbsolute>(s, n, sym);
+ else if (!isa<DefinedCOFF>(s))
+ reportDuplicate(s, nullptr);
+ return s;
}
-Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(N, nullptr);
- S->IsUsedInRegularObj = true;
- if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
- replaceSymbol<DefinedAbsolute>(S, N, VA);
- else if (!isa<DefinedCOFF>(S))
- reportDuplicate(S, nullptr);
- return S;
+Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(n, nullptr);
+ s->isUsedInRegularObj = true;
+ if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+ replaceSymbol<DefinedAbsolute>(s, n, va);
+ else if (!isa<DefinedCOFF>(s))
+ reportDuplicate(s, nullptr);
+ return s;
}
-Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(N, nullptr);
- S->IsUsedInRegularObj = true;
- if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
- replaceSymbol<DefinedSynthetic>(S, N, C);
- else if (!isa<DefinedCOFF>(S))
- reportDuplicate(S, nullptr);
- return S;
+Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(n, nullptr);
+ s->isUsedInRegularObj = true;
+ if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+ replaceSymbol<DefinedSynthetic>(s, n, c);
+ else if (!isa<DefinedCOFF>(s))
+ reportDuplicate(s, nullptr);
+ return s;
}
-Symbol *SymbolTable::addRegular(InputFile *F, StringRef N,
- const coff_symbol_generic *Sym,
- SectionChunk *C) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(N, F);
- if (WasInserted || !isa<DefinedRegular>(S))
- replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ false,
- /*IsExternal*/ true, Sym, C);
+Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,
+ const coff_symbol_generic *sym,
+ SectionChunk *c) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(n, f);
+ if (wasInserted || !isa<DefinedRegular>(s))
+ replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ false,
+ /*IsExternal*/ true, sym, c);
else
- reportDuplicate(S, F);
- return S;
+ reportDuplicate(s, f);
+ return s;
}
std::pair<DefinedRegular *, bool>
-SymbolTable::addComdat(InputFile *F, StringRef N,
- const coff_symbol_generic *Sym) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(N, F);
- if (WasInserted || !isa<DefinedRegular>(S)) {
- replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ true,
- /*IsExternal*/ true, Sym, nullptr);
- return {cast<DefinedRegular>(S), true};
+SymbolTable::addComdat(InputFile *f, StringRef n,
+ const coff_symbol_generic *sym) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(n, f);
+ if (wasInserted || !isa<DefinedRegular>(s)) {
+ replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ true,
+ /*IsExternal*/ true, sym, nullptr);
+ return {cast<DefinedRegular>(s), true};
}
- auto *ExistingSymbol = cast<DefinedRegular>(S);
- if (!ExistingSymbol->IsCOMDAT)
- reportDuplicate(S, F);
- return {ExistingSymbol, false};
+ auto *existingSymbol = cast<DefinedRegular>(s);
+ if (!existingSymbol->isCOMDAT)
+ reportDuplicate(s, f);
+ return {existingSymbol, false};
}
-Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
- const coff_symbol_generic *Sym, CommonChunk *C) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(N, F);
- if (WasInserted || !isa<DefinedCOFF>(S))
- replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C);
- else if (auto *DC = dyn_cast<DefinedCommon>(S))
- if (Size > DC->getSize())
- replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C);
- return S;
+Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size,
+ const coff_symbol_generic *sym, CommonChunk *c) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(n, f);
+ if (wasInserted || !isa<DefinedCOFF>(s))
+ replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
+ else if (auto *dc = dyn_cast<DefinedCommon>(s))
+ if (size > dc->getSize())
+ replaceSymbol<DefinedCommon>(s, f, n, size, sym, c);
+ return s;
}
-Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(N, nullptr);
- S->IsUsedInRegularObj = true;
- if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
- replaceSymbol<DefinedImportData>(S, N, F);
- return S;
+Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(n, nullptr);
+ s->isUsedInRegularObj = true;
+ if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
+ replaceSymbol<DefinedImportData>(s, n, f);
+ return s;
}
- reportDuplicate(S, F);
+ reportDuplicate(s, f);
return nullptr;
}
-Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID,
- uint16_t Machine) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, nullptr);
- S->IsUsedInRegularObj = true;
- if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
- replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine);
- return S;
+Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
+ uint16_t machine) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, nullptr);
+ s->isUsedInRegularObj = true;
+ if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
+ replaceSymbol<DefinedImportThunk>(s, name, id, machine);
+ return s;
}
- reportDuplicate(S, ID->File);
+ reportDuplicate(s, id->file);
return nullptr;
}
std::vector<Chunk *> SymbolTable::getChunks() {
- std::vector<Chunk *> Res;
- for (ObjFile *File : ObjFile::Instances) {
- ArrayRef<Chunk *> V = File->getChunks();
- Res.insert(Res.end(), V.begin(), V.end());
+ std::vector<Chunk *> res;
+ for (ObjFile *file : ObjFile::instances) {
+ ArrayRef<Chunk *> v = file->getChunks();
+ res.insert(res.end(), v.begin(), v.end());
}
- return Res;
+ return res;
}
-Symbol *SymbolTable::find(StringRef Name) {
- return SymMap.lookup(CachedHashStringRef(Name));
+Symbol *SymbolTable::find(StringRef name) {
+ return symMap.lookup(CachedHashStringRef(name));
}
-Symbol *SymbolTable::findUnderscore(StringRef Name) {
- if (Config->Machine == I386)
- return find(("_" + Name).str());
- return find(Name);
+Symbol *SymbolTable::findUnderscore(StringRef name) {
+ if (config->machine == I386)
+ return find(("_" + name).str());
+ return find(name);
}
// Return all symbols that start with Prefix, possibly ignoring the first
// character of Prefix or the first character symbol.
-std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef Prefix) {
- std::vector<Symbol *> Syms;
- for (auto Pair : SymMap) {
- StringRef Name = Pair.first.val();
- if (Name.startswith(Prefix) || Name.startswith(Prefix.drop_front()) ||
- Name.drop_front().startswith(Prefix) ||
- Name.drop_front().startswith(Prefix.drop_front())) {
- Syms.push_back(Pair.second);
+std::vector<Symbol *> SymbolTable::getSymsWithPrefix(StringRef prefix) {
+ std::vector<Symbol *> syms;
+ for (auto pair : symMap) {
+ StringRef name = pair.first.val();
+ if (name.startswith(prefix) || name.startswith(prefix.drop_front()) ||
+ name.drop_front().startswith(prefix) ||
+ name.drop_front().startswith(prefix.drop_front())) {
+ syms.push_back(pair.second);
}
}
- return Syms;
+ return syms;
}
-Symbol *SymbolTable::findMangle(StringRef Name) {
- if (Symbol *Sym = find(Name))
- if (!isa<Undefined>(Sym))
- return Sym;
+Symbol *SymbolTable::findMangle(StringRef name) {
+ if (Symbol *sym = find(name))
+ if (!isa<Undefined>(sym))
+ return sym;
// Efficient fuzzy string lookup is impossible with a hash table, so iterate
// the symbol table once and collect all possibly matching symbols into this
// vector. Then compare each possibly matching symbol with each possible
// mangling.
- std::vector<Symbol *> Syms = getSymsWithPrefix(Name);
- auto FindByPrefix = [&Syms](const Twine &T) -> Symbol * {
- std::string Prefix = T.str();
- for (auto *S : Syms)
- if (S->getName().startswith(Prefix))
- return S;
+ std::vector<Symbol *> syms = getSymsWithPrefix(name);
+ auto findByPrefix = [&syms](const Twine &t) -> Symbol * {
+ std::string prefix = t.str();
+ for (auto *s : syms)
+ if (s->getName().startswith(prefix))
+ return s;
return nullptr;
};
// For non-x86, just look for C++ functions.
- if (Config->Machine != I386)
- return FindByPrefix("?" + Name + "@@Y");
+ if (config->machine != I386)
+ return findByPrefix("?" + name + "@@Y");
- if (!Name.startswith("_"))
+ if (!name.startswith("_"))
return nullptr;
// Search for x86 stdcall function.
- if (Symbol *S = FindByPrefix(Name + "@"))
- return S;
+ if (Symbol *s = findByPrefix(name + "@"))
+ return s;
// Search for x86 fastcall function.
- if (Symbol *S = FindByPrefix("@" + Name.substr(1) + "@"))
- return S;
+ if (Symbol *s = findByPrefix("@" + name.substr(1) + "@"))
+ return s;
// Search for x86 vectorcall function.
- if (Symbol *S = FindByPrefix(Name.substr(1) + "@@"))
- return S;
+ if (Symbol *s = findByPrefix(name.substr(1) + "@@"))
+ return s;
// Search for x86 C++ non-member function.
- return FindByPrefix("?" + Name.substr(1) + "@@Y");
+ return findByPrefix("?" + name.substr(1) + "@@Y");
}
-Symbol *SymbolTable::addUndefined(StringRef Name) {
- return addUndefined(Name, nullptr, false);
+Symbol *SymbolTable::addUndefined(StringRef name) {
+ return addUndefined(name, nullptr, false);
}
std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
- LTO.reset(new BitcodeCompiler);
- for (BitcodeFile *F : BitcodeFile::Instances)
- LTO->add(*F);
- return LTO->compile();
+ lto.reset(new BitcodeCompiler);
+ for (BitcodeFile *f : BitcodeFile::instances)
+ lto->add(*f);
+ return lto->compile();
}
void SymbolTable::addCombinedLTOObjects() {
- if (BitcodeFile::Instances.empty())
+ if (BitcodeFile::instances.empty())
return;
- ScopedTimer T(LTOTimer);
- for (StringRef Object : compileBitcodeFiles()) {
- auto *Obj = make<ObjFile>(MemoryBufferRef(Object, "lto.tmp"));
- Obj->parse();
- ObjFile::Instances.push_back(Obj);
+ ScopedTimer t(ltoTimer);
+ for (StringRef object : compileBitcodeFiles()) {
+ auto *obj = make<ObjFile>(MemoryBufferRef(object, "lto.tmp"));
+ obj->parse();
+ ObjFile::instances.push_back(obj);
}
}
// There is one add* function per symbol type.
class SymbolTable {
public:
- void addFile(InputFile *File);
+ void addFile(InputFile *file);
// Try to resolve any undefined symbols and update the symbol table
// accordingly, then print an error message for any remaining undefined
void reportRemainingUndefines();
void loadMinGWAutomaticImports();
- bool handleMinGWAutomaticImport(Symbol *Sym, StringRef Name);
+ bool handleMinGWAutomaticImport(Symbol *sym, StringRef name);
// Returns a list of chunks of selected symbols.
std::vector<Chunk *> getChunks();
// Returns a symbol for a given name. Returns a nullptr if not found.
- Symbol *find(StringRef Name);
- Symbol *findUnderscore(StringRef Name);
+ Symbol *find(StringRef name);
+ Symbol *findUnderscore(StringRef name);
// Occasionally we have to resolve an undefined symbol to its
// mangled symbol. This function tries to find a mangled name
// for U from the symbol table, and if found, set the symbol as
// a weak alias for U.
- Symbol *findMangle(StringRef Name);
+ Symbol *findMangle(StringRef name);
// Build a set of COFF objects representing the combined contents of
// BitcodeFiles and add them to the symbol table. Called after all files are
std::vector<StringRef> compileBitcodeFiles();
// Creates an Undefined symbol for a given name.
- Symbol *addUndefined(StringRef Name);
+ Symbol *addUndefined(StringRef name);
- Symbol *addSynthetic(StringRef N, Chunk *C);
- Symbol *addAbsolute(StringRef N, uint64_t VA);
+ Symbol *addSynthetic(StringRef n, Chunk *c);
+ Symbol *addAbsolute(StringRef n, uint64_t va);
- Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias);
- void addLazy(ArchiveFile *F, const Archive::Symbol Sym);
- Symbol *addAbsolute(StringRef N, COFFSymbolRef S);
- Symbol *addRegular(InputFile *F, StringRef N,
- const llvm::object::coff_symbol_generic *S = nullptr,
- SectionChunk *C = nullptr);
+ Symbol *addUndefined(StringRef name, InputFile *f, bool isWeakAlias);
+ void addLazy(ArchiveFile *f, const Archive::Symbol sym);
+ Symbol *addAbsolute(StringRef n, COFFSymbolRef s);
+ Symbol *addRegular(InputFile *f, StringRef n,
+ const llvm::object::coff_symbol_generic *s = nullptr,
+ SectionChunk *c = nullptr);
std::pair<DefinedRegular *, bool>
- addComdat(InputFile *F, StringRef N,
- const llvm::object::coff_symbol_generic *S = nullptr);
- Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size,
- const llvm::object::coff_symbol_generic *S = nullptr,
- CommonChunk *C = nullptr);
- Symbol *addImportData(StringRef N, ImportFile *F);
- Symbol *addImportThunk(StringRef Name, DefinedImportData *S,
- uint16_t Machine);
+ addComdat(InputFile *f, StringRef n,
+ const llvm::object::coff_symbol_generic *s = nullptr);
+ Symbol *addCommon(InputFile *f, StringRef n, uint64_t size,
+ const llvm::object::coff_symbol_generic *s = nullptr,
+ CommonChunk *c = nullptr);
+ Symbol *addImportData(StringRef n, ImportFile *f);
+ Symbol *addImportThunk(StringRef name, DefinedImportData *s,
+ uint16_t machine);
- void reportDuplicate(Symbol *Existing, InputFile *NewFile);
+ void reportDuplicate(Symbol *existing, InputFile *newFile);
// A list of chunks which to be added to .rdata.
- std::vector<Chunk *> LocalImportChunks;
+ std::vector<Chunk *> localImportChunks;
// Iterates symbols in non-determinstic hash table order.
- template <typename T> void forEachSymbol(T Callback) {
- for (auto &Pair : SymMap)
- Callback(Pair.second);
+ template <typename T> void forEachSymbol(T callback) {
+ for (auto &pair : symMap)
+ callback(pair.second);
}
private:
/// Inserts symbol if not already present.
- std::pair<Symbol *, bool> insert(StringRef Name);
+ std::pair<Symbol *, bool> insert(StringRef name);
/// Same as insert(Name), but also sets IsUsedInRegularObj.
- std::pair<Symbol *, bool> insert(StringRef Name, InputFile *F);
+ std::pair<Symbol *, bool> insert(StringRef name, InputFile *f);
- std::vector<Symbol *> getSymsWithPrefix(StringRef Prefix);
+ std::vector<Symbol *> getSymsWithPrefix(StringRef prefix);
- llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap;
- std::unique_ptr<BitcodeCompiler> LTO;
+ llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> symMap;
+ std::unique_ptr<BitcodeCompiler> lto;
};
-extern SymbolTable *Symtab;
+extern SymbolTable *symtab;
-std::vector<std::string> getSymbolLocations(ObjFile *File, uint32_t SymIndex);
+std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex);
} // namespace coff
} // namespace lld
"symbols should be optimized for memory usage");
// Returns a symbol name for an error message.
-std::string lld::toString(coff::Symbol &B) {
- if (Config->Demangle)
- if (Optional<std::string> S = lld::demangleMSVC(B.getName()))
- return *S;
- return B.getName();
+std::string lld::toString(coff::Symbol &b) {
+ if (config->demangle)
+ if (Optional<std::string> s = lld::demangleMSVC(b.getName()))
+ return *s;
+ return b.getName();
}
namespace lld {
// name. Object files contain lots of non-external symbols, and creating
// StringRefs for them (which involves lots of strlen() on the string table)
// is a waste of time.
- if (NameData == nullptr) {
- auto *D = cast<DefinedCOFF>(this);
- StringRef NameStr;
- cast<ObjFile>(D->File)->getCOFFObj()->getSymbolName(D->Sym, NameStr);
- NameData = NameStr.data();
- NameSize = NameStr.size();
- assert(NameSize == NameStr.size() && "name length truncated");
+ if (nameData == nullptr) {
+ auto *d = cast<DefinedCOFF>(this);
+ StringRef nameStr;
+ cast<ObjFile>(d->file)->getCOFFObj()->getSymbolName(d->sym, nameStr);
+ nameData = nameStr.data();
+ nameSize = nameStr.size();
+ assert(nameSize == nameStr.size() && "name length truncated");
}
- return StringRef(NameData, NameSize);
+ return StringRef(nameData, nameSize);
}
InputFile *Symbol::getFile() {
- if (auto *Sym = dyn_cast<DefinedCOFF>(this))
- return Sym->File;
- if (auto *Sym = dyn_cast<Lazy>(this))
- return Sym->File;
+ if (auto *sym = dyn_cast<DefinedCOFF>(this))
+ return sym->file;
+ if (auto *sym = dyn_cast<Lazy>(this))
+ return sym->file;
return nullptr;
}
bool Symbol::isLive() const {
- if (auto *R = dyn_cast<DefinedRegular>(this))
- return R->getChunk()->Live;
- if (auto *Imp = dyn_cast<DefinedImportData>(this))
- return Imp->File->Live;
- if (auto *Imp = dyn_cast<DefinedImportThunk>(this))
- return Imp->WrappedSym->File->ThunkLive;
+ if (auto *r = dyn_cast<DefinedRegular>(this))
+ return r->getChunk()->live;
+ if (auto *imp = dyn_cast<DefinedImportData>(this))
+ return imp->file->live;
+ if (auto *imp = dyn_cast<DefinedImportThunk>(this))
+ return imp->wrappedSym->file->thunkLive;
// Assume any other kind of symbol is live.
return true;
}
// MinGW specific.
-void Symbol::replaceKeepingName(Symbol *Other, size_t Size) {
- StringRef OrigName = getName();
- memcpy(this, Other, Size);
- NameData = OrigName.data();
- NameSize = OrigName.size();
+void Symbol::replaceKeepingName(Symbol *other, size_t size) {
+ StringRef origName = getName();
+ memcpy(this, other, size);
+ nameData = origName.data();
+ nameSize = origName.size();
}
COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
- size_t SymSize = cast<ObjFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
- if (SymSize == sizeof(coff_symbol16))
- return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym));
- assert(SymSize == sizeof(coff_symbol32));
- return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));
+ size_t symSize = cast<ObjFile>(file)->getCOFFObj()->getSymbolTableEntrySize();
+ if (symSize == sizeof(coff_symbol16))
+ return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(sym));
+ assert(symSize == sizeof(coff_symbol32));
+ return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(sym));
}
-uint16_t DefinedAbsolute::NumOutputSections;
+uint16_t DefinedAbsolute::numOutputSections;
-static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) {
- if (Machine == AMD64)
- return make<ImportThunkChunkX64>(S);
- if (Machine == I386)
- return make<ImportThunkChunkX86>(S);
- if (Machine == ARM64)
- return make<ImportThunkChunkARM64>(S);
- assert(Machine == ARMNT);
- return make<ImportThunkChunkARM>(S);
+static Chunk *makeImportThunk(DefinedImportData *s, uint16_t machine) {
+ if (machine == AMD64)
+ return make<ImportThunkChunkX64>(s);
+ if (machine == I386)
+ return make<ImportThunkChunkX86>(s);
+ if (machine == ARM64)
+ return make<ImportThunkChunkARM64>(s);
+ assert(machine == ARMNT);
+ return make<ImportThunkChunkARM>(s);
}
-DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S,
- uint16_t Machine)
- : Defined(DefinedImportThunkKind, Name), WrappedSym(S),
- Data(makeImportThunk(S, Machine)) {}
+DefinedImportThunk::DefinedImportThunk(StringRef name, DefinedImportData *s,
+ uint16_t machine)
+ : Defined(DefinedImportThunkKind, name), wrappedSym(s),
+ data(makeImportThunk(s, machine)) {}
Defined *Undefined::getWeakAlias() {
// A weak alias may be a weak alias to another symbol, so check recursively.
- for (Symbol *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias)
- if (auto *D = dyn_cast<Defined>(A))
- return D;
+ for (Symbol *a = weakAlias; a; a = cast<Undefined>(a)->weakAlias)
+ if (auto *d = dyn_cast<Defined>(a))
+ return d;
return nullptr;
}
} // namespace coff
LastDefinedKind = DefinedSyntheticKind,
};
- Kind kind() const { return static_cast<Kind>(SymbolKind); }
+ Kind kind() const { return static_cast<Kind>(symbolKind); }
// Returns the symbol name.
StringRef getName();
- void replaceKeepingName(Symbol *Other, size_t Size);
+ void replaceKeepingName(Symbol *other, size_t size);
// Returns the file from which this symbol was created.
InputFile *getFile();
protected:
friend SymbolTable;
- explicit Symbol(Kind K, StringRef N = "")
- : SymbolKind(K), IsExternal(true), IsCOMDAT(false),
- WrittenToSymtab(false), PendingArchiveLoad(false), IsGCRoot(false),
- IsRuntimePseudoReloc(false), NameSize(N.size()),
- NameData(N.empty() ? nullptr : N.data()) {}
+ explicit Symbol(Kind k, StringRef n = "")
+ : symbolKind(k), isExternal(true), isCOMDAT(false),
+ writtenToSymtab(false), pendingArchiveLoad(false), isGCRoot(false),
+ isRuntimePseudoReloc(false), nameSize(n.size()),
+ nameData(n.empty() ? nullptr : n.data()) {}
- const unsigned SymbolKind : 8;
- unsigned IsExternal : 1;
+ const unsigned symbolKind : 8;
+ unsigned isExternal : 1;
public:
// This bit is used by the \c DefinedRegular subclass.
- unsigned IsCOMDAT : 1;
+ unsigned isCOMDAT : 1;
// This bit is used by Writer::createSymbolAndStringTable() to prevent
// symbols from being written to the symbol table more than once.
- unsigned WrittenToSymtab : 1;
+ unsigned writtenToSymtab : 1;
// True if this symbol was referenced by a regular (non-bitcode) object.
- unsigned IsUsedInRegularObj : 1;
+ unsigned isUsedInRegularObj : 1;
// True if we've seen both a lazy and an undefined symbol with this symbol
// name, which means that we have enqueued an archive member load and should
// not load any more archive members to resolve the same symbol.
- unsigned PendingArchiveLoad : 1;
+ unsigned pendingArchiveLoad : 1;
/// True if we've already added this symbol to the list of GC roots.
- unsigned IsGCRoot : 1;
+ unsigned isGCRoot : 1;
- unsigned IsRuntimePseudoReloc : 1;
+ unsigned isRuntimePseudoReloc : 1;
protected:
// Symbol name length. Assume symbol lengths fit in a 32-bit integer.
- uint32_t NameSize;
+ uint32_t nameSize;
- const char *NameData;
+ const char *nameData;
};
// The base class for any defined symbols, including absolute symbols,
// etc.
class Defined : public Symbol {
public:
- Defined(Kind K, StringRef N) : Symbol(K, N) {}
+ Defined(Kind k, StringRef n) : Symbol(k, n) {}
- static bool classof(const Symbol *S) { return S->kind() <= LastDefinedKind; }
+ static bool classof(const Symbol *s) { return s->kind() <= LastDefinedKind; }
// Returns the RVA (relative virtual address) of this symbol. The
// writer sets and uses RVAs.
friend Symbol;
public:
- DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S)
- : Defined(K, N), File(F), Sym(S) {}
+ DefinedCOFF(Kind k, InputFile *f, StringRef n, const coff_symbol_generic *s)
+ : Defined(k, n), file(f), sym(s) {}
- static bool classof(const Symbol *S) {
- return S->kind() <= LastDefinedCOFFKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() <= LastDefinedCOFFKind;
}
- InputFile *getFile() { return File; }
+ InputFile *getFile() { return file; }
COFFSymbolRef getCOFFSymbol();
- InputFile *File;
+ InputFile *file;
protected:
- const coff_symbol_generic *Sym;
+ const coff_symbol_generic *sym;
};
// Regular defined symbols read from object file symbol tables.
class DefinedRegular : public DefinedCOFF {
public:
- DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT,
- bool IsExternal = false,
- const coff_symbol_generic *S = nullptr,
- SectionChunk *C = nullptr)
- : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) {
- this->IsExternal = IsExternal;
- this->IsCOMDAT = IsCOMDAT;
+ DefinedRegular(InputFile *f, StringRef n, bool isCOMDAT,
+ bool isExternal = false,
+ const coff_symbol_generic *s = nullptr,
+ SectionChunk *c = nullptr)
+ : DefinedCOFF(DefinedRegularKind, f, n, s), data(c ? &c->repl : nullptr) {
+ this->isExternal = isExternal;
+ this->isCOMDAT = isCOMDAT;
}
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedRegularKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedRegularKind;
}
- uint64_t getRVA() const { return (*Data)->getRVA() + Sym->Value; }
- SectionChunk *getChunk() const { return *Data; }
- uint32_t getValue() const { return Sym->Value; }
+ uint64_t getRVA() const { return (*data)->getRVA() + sym->Value; }
+ SectionChunk *getChunk() const { return *data; }
+ uint32_t getValue() const { return sym->Value; }
- SectionChunk **Data;
+ SectionChunk **data;
};
class DefinedCommon : public DefinedCOFF {
public:
- DefinedCommon(InputFile *F, StringRef N, uint64_t Size,
- const coff_symbol_generic *S = nullptr,
- CommonChunk *C = nullptr)
- : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) {
- this->IsExternal = true;
+ DefinedCommon(InputFile *f, StringRef n, uint64_t size,
+ const coff_symbol_generic *s = nullptr,
+ CommonChunk *c = nullptr)
+ : DefinedCOFF(DefinedCommonKind, f, n, s), data(c), size(size) {
+ this->isExternal = true;
}
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedCommonKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedCommonKind;
}
- uint64_t getRVA() { return Data->getRVA(); }
- CommonChunk *getChunk() { return Data; }
+ uint64_t getRVA() { return data->getRVA(); }
+ CommonChunk *getChunk() { return data; }
private:
friend SymbolTable;
- uint64_t getSize() const { return Size; }
- CommonChunk *Data;
- uint64_t Size;
+ uint64_t getSize() const { return size; }
+ CommonChunk *data;
+ uint64_t size;
};
// Absolute symbols.
class DefinedAbsolute : public Defined {
public:
- DefinedAbsolute(StringRef N, COFFSymbolRef S)
- : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) {
- IsExternal = S.isExternal();
+ DefinedAbsolute(StringRef n, COFFSymbolRef s)
+ : Defined(DefinedAbsoluteKind, n), va(s.getValue()) {
+ isExternal = s.isExternal();
}
- DefinedAbsolute(StringRef N, uint64_t V)
- : Defined(DefinedAbsoluteKind, N), VA(V) {}
+ DefinedAbsolute(StringRef n, uint64_t v)
+ : Defined(DefinedAbsoluteKind, n), va(v) {}
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedAbsoluteKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedAbsoluteKind;
}
- uint64_t getRVA() { return VA - Config->ImageBase; }
- void setVA(uint64_t V) { VA = V; }
+ uint64_t getRVA() { return va - config->imageBase; }
+ void setVA(uint64_t v) { va = v; }
// Section index relocations against absolute symbols resolve to
// this 16 bit number, and it is the largest valid section index
// plus one. This variable keeps it.
- static uint16_t NumOutputSections;
+ static uint16_t numOutputSections;
private:
- uint64_t VA;
+ uint64_t va;
};
// This symbol is used for linker-synthesized symbols like __ImageBase and
// __safe_se_handler_table.
class DefinedSynthetic : public Defined {
public:
- explicit DefinedSynthetic(StringRef Name, Chunk *C)
- : Defined(DefinedSyntheticKind, Name), C(C) {}
+ explicit DefinedSynthetic(StringRef name, Chunk *c)
+ : Defined(DefinedSyntheticKind, name), c(c) {}
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedSyntheticKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedSyntheticKind;
}
// A null chunk indicates that this is __ImageBase. Otherwise, this is some
// other synthesized chunk, like SEHTableChunk.
- uint32_t getRVA() { return C ? C->getRVA() : 0; }
- Chunk *getChunk() { return C; }
+ uint32_t getRVA() { return c ? c->getRVA() : 0; }
+ Chunk *getChunk() { return c; }
private:
- Chunk *C;
+ Chunk *c;
};
// This class represents a symbol defined in an archive file. It is
// the same name, it will ask the Lazy to load a file.
class Lazy : public Symbol {
public:
- Lazy(ArchiveFile *F, const Archive::Symbol S)
- : Symbol(LazyKind, S.getName()), File(F), Sym(S) {}
+ Lazy(ArchiveFile *f, const Archive::Symbol s)
+ : Symbol(LazyKind, s.getName()), file(f), sym(s) {}
- static bool classof(const Symbol *S) { return S->kind() == LazyKind; }
+ static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
- ArchiveFile *File;
+ ArchiveFile *file;
private:
friend SymbolTable;
private:
- const Archive::Symbol Sym;
+ const Archive::Symbol sym;
};
// Undefined symbols.
class Undefined : public Symbol {
public:
- explicit Undefined(StringRef N) : Symbol(UndefinedKind, N) {}
+ explicit Undefined(StringRef n) : Symbol(UndefinedKind, n) {}
- static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; }
+ static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; }
// An undefined symbol can have a fallback symbol which gives an
// undefined symbol a second chance if it would remain undefined.
// If it remains undefined, it'll be replaced with whatever the
// Alias pointer points to.
- Symbol *WeakAlias = nullptr;
+ Symbol *weakAlias = nullptr;
// If this symbol is external weak, try to resolve it to a defined
// symbol by searching the chain of fallback symbols. Returns the symbol if
// table in an output. The former has "__imp_" prefix.
class DefinedImportData : public Defined {
public:
- DefinedImportData(StringRef N, ImportFile *F)
- : Defined(DefinedImportDataKind, N), File(F) {
+ DefinedImportData(StringRef n, ImportFile *f)
+ : Defined(DefinedImportDataKind, n), file(f) {
}
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedImportDataKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedImportDataKind;
}
- uint64_t getRVA() { return File->Location->getRVA(); }
- Chunk *getChunk() { return File->Location; }
- void setLocation(Chunk *AddressTable) { File->Location = AddressTable; }
+ uint64_t getRVA() { return file->location->getRVA(); }
+ Chunk *getChunk() { return file->location; }
+ void setLocation(Chunk *addressTable) { file->location = addressTable; }
- StringRef getDLLName() { return File->DLLName; }
- StringRef getExternalName() { return File->ExternalName; }
- uint16_t getOrdinal() { return File->Hdr->OrdinalHint; }
+ StringRef getDLLName() { return file->dllName; }
+ StringRef getExternalName() { return file->externalName; }
+ uint16_t getOrdinal() { return file->hdr->OrdinalHint; }
- ImportFile *File;
+ ImportFile *file;
};
// This class represents a symbol for a jump table entry which jumps
// a regular name. A function pointer is given as a DefinedImportData.
class DefinedImportThunk : public Defined {
public:
- DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine);
+ DefinedImportThunk(StringRef name, DefinedImportData *s, uint16_t machine);
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedImportThunkKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedImportThunkKind;
}
- uint64_t getRVA() { return Data->getRVA(); }
- Chunk *getChunk() { return Data; }
+ uint64_t getRVA() { return data->getRVA(); }
+ Chunk *getChunk() { return data; }
- DefinedImportData *WrappedSym;
+ DefinedImportData *wrappedSym;
private:
- Chunk *Data;
+ Chunk *data;
};
// If you have a symbol "foo" in your object file, a symbol name
// This is here just for compatibility with MSVC.
class DefinedLocalImport : public Defined {
public:
- DefinedLocalImport(StringRef N, Defined *S)
- : Defined(DefinedLocalImportKind, N), Data(make<LocalImportChunk>(S)) {}
+ DefinedLocalImport(StringRef n, Defined *s)
+ : Defined(DefinedLocalImportKind, n), data(make<LocalImportChunk>(s)) {}
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedLocalImportKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedLocalImportKind;
}
- uint64_t getRVA() { return Data->getRVA(); }
- Chunk *getChunk() { return Data; }
+ uint64_t getRVA() { return data->getRVA(); }
+ Chunk *getChunk() { return data; }
private:
- LocalImportChunk *Data;
+ LocalImportChunk *data;
};
inline uint64_t Defined::getRVA() {
// object. We allocate memory using this class and instantiate a symbol
// using the placement new.
union SymbolUnion {
- alignas(DefinedRegular) char A[sizeof(DefinedRegular)];
- alignas(DefinedCommon) char B[sizeof(DefinedCommon)];
- alignas(DefinedAbsolute) char C[sizeof(DefinedAbsolute)];
- alignas(DefinedSynthetic) char D[sizeof(DefinedSynthetic)];
- alignas(Lazy) char E[sizeof(Lazy)];
- alignas(Undefined) char F[sizeof(Undefined)];
- alignas(DefinedImportData) char G[sizeof(DefinedImportData)];
- alignas(DefinedImportThunk) char H[sizeof(DefinedImportThunk)];
- alignas(DefinedLocalImport) char I[sizeof(DefinedLocalImport)];
+ alignas(DefinedRegular) char a[sizeof(DefinedRegular)];
+ alignas(DefinedCommon) char b[sizeof(DefinedCommon)];
+ alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];
+ alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];
+ alignas(Lazy) char e[sizeof(Lazy)];
+ alignas(Undefined) char f[sizeof(Undefined)];
+ alignas(DefinedImportData) char g[sizeof(DefinedImportData)];
+ alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)];
+ alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)];
};
template <typename T, typename... ArgT>
-void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+void replaceSymbol(Symbol *s, ArgT &&... arg) {
static_assert(std::is_trivially_destructible<T>(),
"Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");
"SymbolUnion not aligned enough");
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a Symbol");
- new (S) T(std::forward<ArgT>(Arg)...);
+ new (s) T(std::forward<ArgT>(arg)...);
}
} // namespace coff
-std::string toString(coff::Symbol &B);
+std::string toString(coff::Symbol &b);
} // namespace lld
#endif
class TypeMerger {
public:
- TypeMerger(llvm::BumpPtrAllocator &Alloc)
- : TypeTable(Alloc), IDTable(Alloc), GlobalTypeTable(Alloc),
- GlobalIDTable(Alloc) {}
+ TypeMerger(llvm::BumpPtrAllocator &alloc)
+ : typeTable(alloc), iDTable(alloc), globalTypeTable(alloc),
+ globalIDTable(alloc) {}
/// Get the type table or the global type table if /DEBUG:GHASH is enabled.
inline llvm::codeview::TypeCollection &getTypeTable() {
- if (Config->DebugGHashes)
- return GlobalTypeTable;
- return TypeTable;
+ if (config->debugGHashes)
+ return globalTypeTable;
+ return typeTable;
}
/// Get the ID table or the global ID table if /DEBUG:GHASH is enabled.
inline llvm::codeview::TypeCollection &getIDTable() {
- if (Config->DebugGHashes)
- return GlobalIDTable;
- return IDTable;
+ if (config->debugGHashes)
+ return globalIDTable;
+ return iDTable;
}
/// Type records that will go into the PDB TPI stream.
- llvm::codeview::MergingTypeTableBuilder TypeTable;
+ llvm::codeview::MergingTypeTableBuilder typeTable;
/// Item records that will go into the PDB IPI stream.
- llvm::codeview::MergingTypeTableBuilder IDTable;
+ llvm::codeview::MergingTypeTableBuilder iDTable;
/// Type records that will go into the PDB TPI stream (for /DEBUG:GHASH)
- llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable;
+ llvm::codeview::GlobalTypeTableBuilder globalTypeTable;
/// Item records that will go into the PDB IPI stream (for /DEBUG:GHASH)
- llvm::codeview::GlobalTypeTableBuilder GlobalIDTable;
+ llvm::codeview::GlobalTypeTableBuilder globalIDTable;
};
/// Map from type index and item index in a type server PDB to the
/// corresponding index in the destination PDB.
struct CVIndexMap {
- llvm::SmallVector<llvm::codeview::TypeIndex, 0> TPIMap;
- llvm::SmallVector<llvm::codeview::TypeIndex, 0> IPIMap;
- bool IsTypeServerMap = false;
- bool IsPrecompiledTypeMap = false;
+ llvm::SmallVector<llvm::codeview::TypeIndex, 0> tpiMap;
+ llvm::SmallVector<llvm::codeview::TypeIndex, 0> ipiMap;
+ bool isTypeServerMap = false;
+ bool isPrecompiledTypeMap = false;
};
} // namespace coff
$ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin
$ xxd -i /tmp/DOSProgram.bin
*/
-static unsigned char DOSProgram[] = {
+static unsigned char dosProgram[] = {
0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c,
0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65,
0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00
};
-static_assert(sizeof(DOSProgram) % 8 == 0,
+static_assert(sizeof(dosProgram) % 8 == 0,
"DOSProgram size must be multiple of 8");
-static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram);
-static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8");
+static const int dosStubSize = sizeof(dos_header) + sizeof(dosProgram);
+static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8");
-static const int NumberOfDataDirectory = 16;
+static const int numberOfDataDirectory = 16;
// Global vector of all output sections. After output sections are finalized,
// this can be indexed by Chunk::getOutputSection.
-static std::vector<OutputSection *> OutputSections;
+static std::vector<OutputSection *> outputSections;
OutputSection *Chunk::getOutputSection() const {
- return OSIdx == 0 ? nullptr : OutputSections[OSIdx - 1];
+ return osidx == 0 ? nullptr : outputSections[osidx - 1];
}
namespace {
class DebugDirectoryChunk : public NonSectionChunk {
public:
- DebugDirectoryChunk(const std::vector<Chunk *> &R, bool WriteRepro)
- : Records(R), WriteRepro(WriteRepro) {}
+ DebugDirectoryChunk(const std::vector<Chunk *> &r, bool writeRepro)
+ : records(r), writeRepro(writeRepro) {}
size_t getSize() const override {
- return (Records.size() + int(WriteRepro)) * sizeof(debug_directory);
+ return (records.size() + int(writeRepro)) * sizeof(debug_directory);
}
- void writeTo(uint8_t *B) const override {
- auto *D = reinterpret_cast<debug_directory *>(B);
+ void writeTo(uint8_t *b) const override {
+ auto *d = reinterpret_cast<debug_directory *>(b);
- for (const Chunk *Record : Records) {
- OutputSection *OS = Record->getOutputSection();
- uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA());
- fillEntry(D, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, Record->getSize(),
- Record->getRVA(), Offs);
- ++D;
+ for (const Chunk *record : records) {
+ OutputSection *os = record->getOutputSection();
+ uint64_t offs = os->getFileOff() + (record->getRVA() - os->getRVA());
+ fillEntry(d, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, record->getSize(),
+ record->getRVA(), offs);
+ ++d;
}
- if (WriteRepro) {
+ if (writeRepro) {
// FIXME: The COFF spec allows either a 0-sized entry to just say
// "the timestamp field is really a hash", or a 4-byte size field
// followed by that many bytes containing a longer hash (with the
// lowest 4 bytes usually being the timestamp in little-endian order).
// Consider storing the full 8 bytes computed by xxHash64 here.
- fillEntry(D, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0);
+ fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0);
}
}
- void setTimeDateStamp(uint32_t TimeDateStamp) {
- for (support::ulittle32_t *TDS : TimeDateStamps)
- *TDS = TimeDateStamp;
+ void setTimeDateStamp(uint32_t timeDateStamp) {
+ for (support::ulittle32_t *tds : timeDateStamps)
+ *tds = timeDateStamp;
}
private:
- void fillEntry(debug_directory *D, COFF::DebugType DebugType, size_t Size,
- uint64_t RVA, uint64_t Offs) const {
- D->Characteristics = 0;
- D->TimeDateStamp = 0;
- D->MajorVersion = 0;
- D->MinorVersion = 0;
- D->Type = DebugType;
- D->SizeOfData = Size;
- D->AddressOfRawData = RVA;
- D->PointerToRawData = Offs;
-
- TimeDateStamps.push_back(&D->TimeDateStamp);
- }
-
- mutable std::vector<support::ulittle32_t *> TimeDateStamps;
- const std::vector<Chunk *> &Records;
- bool WriteRepro;
+ void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size,
+ uint64_t rva, uint64_t offs) const {
+ d->Characteristics = 0;
+ d->TimeDateStamp = 0;
+ d->MajorVersion = 0;
+ d->MinorVersion = 0;
+ d->Type = debugType;
+ d->SizeOfData = size;
+ d->AddressOfRawData = rva;
+ d->PointerToRawData = offs;
+
+ timeDateStamps.push_back(&d->TimeDateStamp);
+ }
+
+ mutable std::vector<support::ulittle32_t *> timeDateStamps;
+ const std::vector<Chunk *> &records;
+ bool writeRepro;
};
class CVDebugRecordChunk : public NonSectionChunk {
public:
size_t getSize() const override {
- return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1;
+ return sizeof(codeview::DebugInfo) + config->pdbAltPath.size() + 1;
}
- void writeTo(uint8_t *B) const override {
+ void writeTo(uint8_t *b) const override {
// Save off the DebugInfo entry to backfill the file signature (build id)
// in Writer::writeBuildId
- BuildId = reinterpret_cast<codeview::DebugInfo *>(B);
+ buildId = reinterpret_cast<codeview::DebugInfo *>(b);
// variable sized field (PDB Path)
- char *P = reinterpret_cast<char *>(B + sizeof(*BuildId));
- if (!Config->PDBAltPath.empty())
- memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size());
- P[Config->PDBAltPath.size()] = '\0';
+ char *p = reinterpret_cast<char *>(b + sizeof(*buildId));
+ if (!config->pdbAltPath.empty())
+ memcpy(p, config->pdbAltPath.data(), config->pdbAltPath.size());
+ p[config->pdbAltPath.size()] = '\0';
}
- mutable codeview::DebugInfo *BuildId = nullptr;
+ mutable codeview::DebugInfo *buildId = nullptr;
};
// PartialSection represents a group of chunks that contribute to an
// characteristics constitutes the OutputSection.
class PartialSectionKey {
public:
- StringRef Name;
- unsigned Characteristics;
+ StringRef name;
+ unsigned characteristics;
- bool operator<(const PartialSectionKey &Other) const {
- int C = Name.compare(Other.Name);
- if (C == 1)
+ bool operator<(const PartialSectionKey &other) const {
+ int c = name.compare(other.name);
+ if (c == 1)
return false;
- if (C == 0)
- return Characteristics < Other.Characteristics;
+ if (c == 0)
+ return characteristics < other.characteristics;
return true;
}
};
// The writer writes a SymbolTable result to a file.
class Writer {
public:
- Writer() : Buffer(errorHandler().OutputBuffer) {}
+ Writer() : buffer(errorHandler().outputBuffer) {}
void run();
private:
void removeEmptySections();
void assignOutputSectionIndices();
void createSymbolAndStringTable();
- void openFile(StringRef OutputPath);
+ void openFile(StringRef outputPath);
template <typename PEHeaderTy> void writeHeader();
void createSEHTable();
void createRuntimePseudoRelocs();
void insertCtorDtorSymbols();
void createGuardCFTables();
- void markSymbolsForRVATable(ObjFile *File,
- ArrayRef<SectionChunk *> SymIdxChunks,
- SymbolRVASet &TableSymbols);
- void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
- StringRef CountSym);
+ void markSymbolsForRVATable(ObjFile *file,
+ ArrayRef<SectionChunk *> symIdxChunks,
+ SymbolRVASet &tableSymbols);
+ void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
+ StringRef countSym);
void setSectionPermissions();
void writeSections();
void writeBuildId();
void sortExceptionTable();
- void sortCRTSectionChunks(std::vector<Chunk *> &Chunks);
+ void sortCRTSectionChunks(std::vector<Chunk *> &chunks);
void addSyntheticIdata();
- void fixPartialSectionChars(StringRef Name, uint32_t Chars);
+ void fixPartialSectionChars(StringRef name, uint32_t chars);
bool fixGnuImportChunks();
- PartialSection *createPartialSection(StringRef Name, uint32_t OutChars);
- PartialSection *findPartialSection(StringRef Name, uint32_t OutChars);
+ PartialSection *createPartialSection(StringRef name, uint32_t outChars);
+ PartialSection *findPartialSection(StringRef name, uint32_t outChars);
- llvm::Optional<coff_symbol16> createSymbol(Defined *D);
- size_t addEntryToStringTable(StringRef Str);
+ llvm::Optional<coff_symbol16> createSymbol(Defined *d);
+ size_t addEntryToStringTable(StringRef str);
- OutputSection *findSection(StringRef Name);
+ OutputSection *findSection(StringRef name);
void addBaserels();
- void addBaserelBlocks(std::vector<Baserel> &V);
+ void addBaserelBlocks(std::vector<Baserel> &v);
uint32_t getSizeOfInitializedData();
- std::unique_ptr<FileOutputBuffer> &Buffer;
- std::map<PartialSectionKey, PartialSection *> PartialSections;
- std::vector<char> Strtab;
- std::vector<llvm::object::coff_symbol16> OutputSymtab;
- IdataContents Idata;
- Chunk *ImportTableStart = nullptr;
- uint64_t ImportTableSize = 0;
- Chunk *IATStart = nullptr;
- uint64_t IATSize = 0;
- DelayLoadContents DelayIdata;
- EdataContents Edata;
- bool SetNoSEHCharacteristic = false;
-
- DebugDirectoryChunk *DebugDirectory = nullptr;
- std::vector<Chunk *> DebugRecords;
- CVDebugRecordChunk *BuildId = nullptr;
- ArrayRef<uint8_t> SectionTable;
-
- uint64_t FileSize;
- uint32_t PointerToSymbolTable = 0;
- uint64_t SizeOfImage;
- uint64_t SizeOfHeaders;
-
- OutputSection *TextSec;
- OutputSection *RdataSec;
- OutputSection *BuildidSec;
- OutputSection *DataSec;
- OutputSection *PdataSec;
- OutputSection *IdataSec;
- OutputSection *EdataSec;
- OutputSection *DidatSec;
- OutputSection *RsrcSec;
- OutputSection *RelocSec;
- OutputSection *CtorsSec;
- OutputSection *DtorsSec;
+ std::unique_ptr<FileOutputBuffer> &buffer;
+ std::map<PartialSectionKey, PartialSection *> partialSections;
+ std::vector<char> strtab;
+ std::vector<llvm::object::coff_symbol16> outputSymtab;
+ IdataContents idata;
+ Chunk *importTableStart = nullptr;
+ uint64_t importTableSize = 0;
+ Chunk *iatStart = nullptr;
+ uint64_t iatSize = 0;
+ DelayLoadContents delayIdata;
+ EdataContents edata;
+ bool setNoSEHCharacteristic = false;
+
+ DebugDirectoryChunk *debugDirectory = nullptr;
+ std::vector<Chunk *> debugRecords;
+ CVDebugRecordChunk *buildId = nullptr;
+ ArrayRef<uint8_t> sectionTable;
+
+ uint64_t fileSize;
+ uint32_t pointerToSymbolTable = 0;
+ uint64_t sizeOfImage;
+ uint64_t sizeOfHeaders;
+
+ OutputSection *textSec;
+ OutputSection *rdataSec;
+ OutputSection *buildidSec;
+ OutputSection *dataSec;
+ OutputSection *pdataSec;
+ OutputSection *idataSec;
+ OutputSection *edataSec;
+ OutputSection *didatSec;
+ OutputSection *rsrcSec;
+ OutputSection *relocSec;
+ OutputSection *ctorsSec;
+ OutputSection *dtorsSec;
// The first and last .pdata sections in the output file.
//
// are entirely linker-generated we can keep track of their locations using
// the chunks that the linker creates. All .pdata chunks come from input
// files, so we need to keep track of them separately.
- Chunk *FirstPdata = nullptr;
- Chunk *LastPdata;
+ Chunk *firstPdata = nullptr;
+ Chunk *lastPdata;
};
} // anonymous namespace
namespace lld {
namespace coff {
-static Timer CodeLayoutTimer("Code Layout", Timer::root());
-static Timer DiskCommitTimer("Commit Output File", Timer::root());
+static Timer codeLayoutTimer("Code Layout", Timer::root());
+static Timer diskCommitTimer("Commit Output File", Timer::root());
void writeResult() { Writer().run(); }
-void OutputSection::addChunk(Chunk *C) {
- Chunks.push_back(C);
+void OutputSection::addChunk(Chunk *c) {
+ chunks.push_back(c);
}
-void OutputSection::insertChunkAtStart(Chunk *C) {
- Chunks.insert(Chunks.begin(), C);
+void OutputSection::insertChunkAtStart(Chunk *c) {
+ chunks.insert(chunks.begin(), c);
}
-void OutputSection::setPermissions(uint32_t C) {
- Header.Characteristics &= ~PermMask;
- Header.Characteristics |= C;
+void OutputSection::setPermissions(uint32_t c) {
+ header.Characteristics &= ~permMask;
+ header.Characteristics |= c;
}
-void OutputSection::merge(OutputSection *Other) {
- Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end());
- Other->Chunks.clear();
- ContribSections.insert(ContribSections.end(), Other->ContribSections.begin(),
- Other->ContribSections.end());
- Other->ContribSections.clear();
+void OutputSection::merge(OutputSection *other) {
+ chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end());
+ other->chunks.clear();
+ contribSections.insert(contribSections.end(), other->contribSections.begin(),
+ other->contribSections.end());
+ other->contribSections.clear();
}
// Write the section header to a given buffer.
-void OutputSection::writeHeaderTo(uint8_t *Buf) {
- auto *Hdr = reinterpret_cast<coff_section *>(Buf);
- *Hdr = Header;
- if (StringTableOff) {
+void OutputSection::writeHeaderTo(uint8_t *buf) {
+ auto *hdr = reinterpret_cast<coff_section *>(buf);
+ *hdr = header;
+ if (stringTableOff) {
// If name is too long, write offset into the string table as a name.
- sprintf(Hdr->Name, "/%d", StringTableOff);
+ sprintf(hdr->Name, "/%d", stringTableOff);
} else {
- assert(!Config->Debug || Name.size() <= COFF::NameSize ||
- (Hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0);
- strncpy(Hdr->Name, Name.data(),
- std::min(Name.size(), (size_t)COFF::NameSize));
+ assert(!config->debug || name.size() <= COFF::NameSize ||
+ (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0);
+ strncpy(hdr->Name, name.data(),
+ std::min(name.size(), (size_t)COFF::NameSize));
}
}
-void OutputSection::addContributingPartialSection(PartialSection *Sec) {
- ContribSections.push_back(Sec);
+void OutputSection::addContributingPartialSection(PartialSection *sec) {
+ contribSections.push_back(sec);
}
} // namespace coff
// Check whether the target address S is in range from a relocation
// of type RelType at address P.
-static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) {
- if (Config->Machine == ARMNT) {
- int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
- switch (RelType) {
+static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) {
+ if (config->machine == ARMNT) {
+ int64_t diff = AbsoluteDifference(s, p + 4) + margin;
+ switch (relType) {
case IMAGE_REL_ARM_BRANCH20T:
- return isInt<21>(Diff);
+ return isInt<21>(diff);
case IMAGE_REL_ARM_BRANCH24T:
case IMAGE_REL_ARM_BLX23T:
- return isInt<25>(Diff);
+ return isInt<25>(diff);
default:
return true;
}
- } else if (Config->Machine == ARM64) {
- int64_t Diff = AbsoluteDifference(S, P) + Margin;
- switch (RelType) {
+ } else if (config->machine == ARM64) {
+ int64_t diff = AbsoluteDifference(s, p) + margin;
+ switch (relType) {
case IMAGE_REL_ARM64_BRANCH26:
- return isInt<28>(Diff);
+ return isInt<28>(diff);
case IMAGE_REL_ARM64_BRANCH19:
- return isInt<21>(Diff);
+ return isInt<21>(diff);
case IMAGE_REL_ARM64_BRANCH14:
- return isInt<16>(Diff);
+ return isInt<16>(diff);
default:
return true;
}
// Return the last thunk for the given target if it is in range,
// or create a new one.
static std::pair<Defined *, bool>
-getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P,
- uint16_t Type, int Margin) {
- Defined *&LastThunk = LastThunks[Target->getRVA()];
- if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin))
- return {LastThunk, false};
- Chunk *C;
- switch (Config->Machine) {
+getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target, uint64_t p,
+ uint16_t type, int margin) {
+ Defined *&lastThunk = lastThunks[target->getRVA()];
+ if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin))
+ return {lastThunk, false};
+ Chunk *c;
+ switch (config->machine) {
case ARMNT:
- C = make<RangeExtensionThunkARM>(Target);
+ c = make<RangeExtensionThunkARM>(target);
break;
case ARM64:
- C = make<RangeExtensionThunkARM64>(Target);
+ c = make<RangeExtensionThunkARM64>(target);
break;
default:
llvm_unreachable("Unexpected architecture");
}
- Defined *D = make<DefinedSynthetic>("", C);
- LastThunk = D;
- return {D, true};
+ Defined *d = make<DefinedSynthetic>("", c);
+ lastThunk = d;
+ return {d, true};
}
// This checks all relocations, and for any relocation which isn't in range
// After adding thunks, we verify that all relocations are in range (with
// no extra margin requirements). If this failed, we restart (throwing away
// the previously created thunks) and retry with a wider margin.
-static bool createThunks(OutputSection *OS, int Margin) {
- bool AddressesChanged = false;
- DenseMap<uint64_t, Defined *> LastThunks;
- DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> ThunkSymtabIndices;
- size_t ThunksSize = 0;
+static bool createThunks(OutputSection *os, int margin) {
+ bool addressesChanged = false;
+ DenseMap<uint64_t, Defined *> lastThunks;
+ DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> thunkSymtabIndices;
+ size_t thunksSize = 0;
// Recheck Chunks.size() each iteration, since we can insert more
// elements into it.
- for (size_t I = 0; I != OS->Chunks.size(); ++I) {
- SectionChunk *SC = dyn_cast_or_null<SectionChunk>(OS->Chunks[I]);
- if (!SC)
+ for (size_t i = 0; i != os->chunks.size(); ++i) {
+ SectionChunk *sc = dyn_cast_or_null<SectionChunk>(os->chunks[i]);
+ if (!sc)
continue;
- size_t ThunkInsertionSpot = I + 1;
+ size_t thunkInsertionSpot = i + 1;
// Try to get a good enough estimate of where new thunks will be placed.
// Offset this by the size of the new thunks added so far, to make the
// estimate slightly better.
- size_t ThunkInsertionRVA = SC->getRVA() + SC->getSize() + ThunksSize;
- ObjFile *File = SC->File;
- std::vector<std::pair<uint32_t, uint32_t>> RelocReplacements;
- ArrayRef<coff_relocation> OriginalRelocs =
- File->getCOFFObj()->getRelocations(SC->Header);
- for (size_t J = 0, E = OriginalRelocs.size(); J < E; ++J) {
- const coff_relocation &Rel = OriginalRelocs[J];
- Symbol *RelocTarget = File->getSymbol(Rel.SymbolTableIndex);
+ size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize;
+ ObjFile *file = sc->file;
+ std::vector<std::pair<uint32_t, uint32_t>> relocReplacements;
+ ArrayRef<coff_relocation> originalRelocs =
+ file->getCOFFObj()->getRelocations(sc->header);
+ for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) {
+ const coff_relocation &rel = originalRelocs[j];
+ Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex);
// The estimate of the source address P should be pretty accurate,
// but we don't know whether the target Symbol address should be
// offset by ThunkSize or not (or by some of ThunksSize but not all of
// it), giving us some uncertainty once we have added one thunk.
- uint64_t P = SC->getRVA() + Rel.VirtualAddress + ThunksSize;
+ uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize;
- Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
- if (!Sym)
+ Defined *sym = dyn_cast_or_null<Defined>(relocTarget);
+ if (!sym)
continue;
- uint64_t S = Sym->getRVA();
+ uint64_t s = sym->getRVA();
- if (isInRange(Rel.Type, S, P, Margin))
+ if (isInRange(rel.Type, s, p, margin))
continue;
// If the target isn't in range, hook it up to an existing or new
// thunk.
- Defined *Thunk;
- bool WasNew;
- std::tie(Thunk, WasNew) = getThunk(LastThunks, Sym, P, Rel.Type, Margin);
- if (WasNew) {
- Chunk *ThunkChunk = Thunk->getChunk();
- ThunkChunk->setRVA(
- ThunkInsertionRVA); // Estimate of where it will be located.
- OS->Chunks.insert(OS->Chunks.begin() + ThunkInsertionSpot, ThunkChunk);
- ThunkInsertionSpot++;
- ThunksSize += ThunkChunk->getSize();
- ThunkInsertionRVA += ThunkChunk->getSize();
- AddressesChanged = true;
+ Defined *thunk;
+ bool wasNew;
+ std::tie(thunk, wasNew) = getThunk(lastThunks, sym, p, rel.Type, margin);
+ if (wasNew) {
+ Chunk *thunkChunk = thunk->getChunk();
+ thunkChunk->setRVA(
+ thunkInsertionRVA); // Estimate of where it will be located.
+ os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk);
+ thunkInsertionSpot++;
+ thunksSize += thunkChunk->getSize();
+ thunkInsertionRVA += thunkChunk->getSize();
+ addressesChanged = true;
}
// To redirect the relocation, add a symbol to the parent object file's
// symbol table, and replace the relocation symbol table index with the
// new index.
- auto Insertion = ThunkSymtabIndices.insert({{File, Thunk}, ~0U});
- uint32_t &ThunkSymbolIndex = Insertion.first->second;
- if (Insertion.second)
- ThunkSymbolIndex = File->addRangeThunkSymbol(Thunk);
- RelocReplacements.push_back({J, ThunkSymbolIndex});
+ auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U});
+ uint32_t &thunkSymbolIndex = insertion.first->second;
+ if (insertion.second)
+ thunkSymbolIndex = file->addRangeThunkSymbol(thunk);
+ relocReplacements.push_back({j, thunkSymbolIndex});
}
// Get a writable copy of this section's relocations so they can be
// modified. If the relocations point into the object file, allocate new
// memory. Otherwise, this must be previously allocated memory that can be
// modified in place.
- ArrayRef<coff_relocation> CurRelocs = SC->getRelocs();
- MutableArrayRef<coff_relocation> NewRelocs;
- if (OriginalRelocs.data() == CurRelocs.data()) {
- NewRelocs = makeMutableArrayRef(
- BAlloc.Allocate<coff_relocation>(OriginalRelocs.size()),
- OriginalRelocs.size());
+ ArrayRef<coff_relocation> curRelocs = sc->getRelocs();
+ MutableArrayRef<coff_relocation> newRelocs;
+ if (originalRelocs.data() == curRelocs.data()) {
+ newRelocs = makeMutableArrayRef(
+ bAlloc.Allocate<coff_relocation>(originalRelocs.size()),
+ originalRelocs.size());
} else {
- NewRelocs = makeMutableArrayRef(
- const_cast<coff_relocation *>(CurRelocs.data()), CurRelocs.size());
+ newRelocs = makeMutableArrayRef(
+ const_cast<coff_relocation *>(curRelocs.data()), curRelocs.size());
}
// Copy each relocation, but replace the symbol table indices which need
// thunks.
- auto NextReplacement = RelocReplacements.begin();
- auto EndReplacement = RelocReplacements.end();
- for (size_t I = 0, E = OriginalRelocs.size(); I != E; ++I) {
- NewRelocs[I] = OriginalRelocs[I];
- if (NextReplacement != EndReplacement && NextReplacement->first == I) {
- NewRelocs[I].SymbolTableIndex = NextReplacement->second;
- ++NextReplacement;
+ auto nextReplacement = relocReplacements.begin();
+ auto endReplacement = relocReplacements.end();
+ for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) {
+ newRelocs[i] = originalRelocs[i];
+ if (nextReplacement != endReplacement && nextReplacement->first == i) {
+ newRelocs[i].SymbolTableIndex = nextReplacement->second;
+ ++nextReplacement;
}
}
- SC->setRelocs(NewRelocs);
+ sc->setRelocs(newRelocs);
}
- return AddressesChanged;
+ return addressesChanged;
}
// Verify that all relocations are in range, with no extra margin requirements.
-static bool verifyRanges(const std::vector<Chunk *> Chunks) {
- for (Chunk *C : Chunks) {
- SectionChunk *SC = dyn_cast_or_null<SectionChunk>(C);
- if (!SC)
+static bool verifyRanges(const std::vector<Chunk *> chunks) {
+ for (Chunk *c : chunks) {
+ SectionChunk *sc = dyn_cast_or_null<SectionChunk>(c);
+ if (!sc)
continue;
- ArrayRef<coff_relocation> Relocs = SC->getRelocs();
- for (size_t J = 0, E = Relocs.size(); J < E; ++J) {
- const coff_relocation &Rel = Relocs[J];
- Symbol *RelocTarget = SC->File->getSymbol(Rel.SymbolTableIndex);
+ ArrayRef<coff_relocation> relocs = sc->getRelocs();
+ for (size_t j = 0, e = relocs.size(); j < e; ++j) {
+ const coff_relocation &rel = relocs[j];
+ Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex);
- Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
- if (!Sym)
+ Defined *sym = dyn_cast_or_null<Defined>(relocTarget);
+ if (!sym)
continue;
- uint64_t P = SC->getRVA() + Rel.VirtualAddress;
- uint64_t S = Sym->getRVA();
+ uint64_t p = sc->getRVA() + rel.VirtualAddress;
+ uint64_t s = sym->getRVA();
- if (!isInRange(Rel.Type, S, P, 0))
+ if (!isInRange(rel.Type, s, p, 0))
return false;
}
}
// Assign addresses and add thunks if necessary.
void Writer::finalizeAddresses() {
assignAddresses();
- if (Config->Machine != ARMNT && Config->Machine != ARM64)
+ if (config->machine != ARMNT && config->machine != ARM64)
return;
- size_t OrigNumChunks = 0;
- for (OutputSection *Sec : OutputSections) {
- Sec->OrigChunks = Sec->Chunks;
- OrigNumChunks += Sec->Chunks.size();
+ size_t origNumChunks = 0;
+ for (OutputSection *sec : outputSections) {
+ sec->origChunks = sec->chunks;
+ origNumChunks += sec->chunks.size();
}
- int Pass = 0;
- int Margin = 1024 * 100;
+ int pass = 0;
+ int margin = 1024 * 100;
while (true) {
// First check whether we need thunks at all, or if the previous pass of
// adding them turned out ok.
- bool RangesOk = true;
- size_t NumChunks = 0;
- for (OutputSection *Sec : OutputSections) {
- if (!verifyRanges(Sec->Chunks)) {
- RangesOk = false;
+ bool rangesOk = true;
+ size_t numChunks = 0;
+ for (OutputSection *sec : outputSections) {
+ if (!verifyRanges(sec->chunks)) {
+ rangesOk = false;
break;
}
- NumChunks += Sec->Chunks.size();
+ numChunks += sec->chunks.size();
}
- if (RangesOk) {
- if (Pass > 0)
- log("Added " + Twine(NumChunks - OrigNumChunks) + " thunks with " +
- "margin " + Twine(Margin) + " in " + Twine(Pass) + " passes");
+ if (rangesOk) {
+ if (pass > 0)
+ log("Added " + Twine(numChunks - origNumChunks) + " thunks with " +
+ "margin " + Twine(margin) + " in " + Twine(pass) + " passes");
return;
}
- if (Pass >= 10)
- fatal("adding thunks hasn't converged after " + Twine(Pass) + " passes");
+ if (pass >= 10)
+ fatal("adding thunks hasn't converged after " + Twine(pass) + " passes");
- if (Pass > 0) {
+ if (pass > 0) {
// If the previous pass didn't work out, reset everything back to the
// original conditions before retrying with a wider margin. This should
// ideally never happen under real circumstances.
- for (OutputSection *Sec : OutputSections)
- Sec->Chunks = Sec->OrigChunks;
- Margin *= 2;
+ for (OutputSection *sec : outputSections)
+ sec->chunks = sec->origChunks;
+ margin *= 2;
}
// Try adding thunks everywhere where it is needed, with a margin
// to avoid things going out of range due to the added thunks.
- bool AddressesChanged = false;
- for (OutputSection *Sec : OutputSections)
- AddressesChanged |= createThunks(Sec, Margin);
+ bool addressesChanged = false;
+ for (OutputSection *sec : outputSections)
+ addressesChanged |= createThunks(sec, margin);
// If the verification above thought we needed thunks, we should have
// added some.
- assert(AddressesChanged);
+ assert(addressesChanged);
// Recalculate the layout for the whole image (and verify the ranges at
// the start of the next round).
assignAddresses();
- Pass++;
+ pass++;
}
}
// The main function of the writer.
void Writer::run() {
- ScopedTimer T1(CodeLayoutTimer);
+ ScopedTimer t1(codeLayoutTimer);
createImportTables();
createSections();
setSectionPermissions();
createSymbolAndStringTable();
- if (FileSize > UINT32_MAX)
- fatal("image size (" + Twine(FileSize) + ") " +
+ if (fileSize > UINT32_MAX)
+ fatal("image size (" + Twine(fileSize) + ") " +
"exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")");
- openFile(Config->OutputFile);
- if (Config->is64()) {
+ openFile(config->outputFile);
+ if (config->is64()) {
writeHeader<pe32plus_header>();
} else {
writeHeader<pe32_header>();
writeSections();
sortExceptionTable();
- T1.stop();
+ t1.stop();
- if (!Config->PDBPath.empty() && Config->Debug) {
- assert(BuildId);
- createPDB(Symtab, OutputSections, SectionTable, BuildId->BuildId);
+ if (!config->pdbPath.empty() && config->debug) {
+ assert(buildId);
+ createPDB(symtab, outputSections, sectionTable, buildId->buildId);
}
writeBuildId();
- writeMapFile(OutputSections);
+ writeMapFile(outputSections);
- ScopedTimer T2(DiskCommitTimer);
- if (auto E = Buffer->commit())
- fatal("failed to write the output file: " + toString(std::move(E)));
+ ScopedTimer t2(diskCommitTimer);
+ if (auto e = buffer->commit())
+ fatal("failed to write the output file: " + toString(std::move(e)));
}
-static StringRef getOutputSectionName(StringRef Name) {
- StringRef S = Name.split('$').first;
+static StringRef getOutputSectionName(StringRef name) {
+ StringRef s = name.split('$').first;
// Treat a later period as a separator for MinGW, for sections like
// ".ctors.01234".
- return S.substr(0, S.find('.', 1));
+ return s.substr(0, s.find('.', 1));
}
// For /order.
-static void sortBySectionOrder(std::vector<Chunk *> &Chunks) {
- auto GetPriority = [](const Chunk *C) {
- if (auto *Sec = dyn_cast<SectionChunk>(C))
- if (Sec->Sym)
- return Config->Order.lookup(Sec->Sym->getName());
+static void sortBySectionOrder(std::vector<Chunk *> &chunks) {
+ auto getPriority = [](const Chunk *c) {
+ if (auto *sec = dyn_cast<SectionChunk>(c))
+ if (sec->sym)
+ return config->order.lookup(sec->sym->getName());
return 0;
};
- llvm::stable_sort(Chunks, [=](const Chunk *A, const Chunk *B) {
- return GetPriority(A) < GetPriority(B);
+ llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) {
+ return getPriority(a) < getPriority(b);
});
}
// Change the characteristics of existing PartialSections that belong to the
// section Name to Chars.
-void Writer::fixPartialSectionChars(StringRef Name, uint32_t Chars) {
- for (auto It : PartialSections) {
- PartialSection *PSec = It.second;
- StringRef CurName = PSec->Name;
- if (!CurName.consume_front(Name) ||
- (!CurName.empty() && !CurName.startswith("$")))
+void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) {
+ for (auto it : partialSections) {
+ PartialSection *pSec = it.second;
+ StringRef curName = pSec->name;
+ if (!curName.consume_front(name) ||
+ (!curName.empty() && !curName.startswith("$")))
continue;
- if (PSec->Characteristics == Chars)
+ if (pSec->characteristics == chars)
continue;
- PartialSection *DestSec = createPartialSection(PSec->Name, Chars);
- DestSec->Chunks.insert(DestSec->Chunks.end(), PSec->Chunks.begin(),
- PSec->Chunks.end());
- PSec->Chunks.clear();
+ PartialSection *destSec = createPartialSection(pSec->name, chars);
+ destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(),
+ pSec->chunks.end());
+ pSec->chunks.clear();
}
}
// to be grouped by library, and sorted alphabetically within each library
// (which makes sure the header comes first and the trailer last).
bool Writer::fixGnuImportChunks() {
- uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+ uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
// Make sure all .idata$* section chunks are mapped as RDATA in order to
// be sorted into the same sections as our own synthesized .idata chunks.
- fixPartialSectionChars(".idata", RDATA);
+ fixPartialSectionChars(".idata", rdata);
- bool HasIdata = false;
+ bool hasIdata = false;
// Sort all .idata$* chunks, grouping chunks from the same library,
// with alphabetical ordering of the object fils within a library.
- for (auto It : PartialSections) {
- PartialSection *PSec = It.second;
- if (!PSec->Name.startswith(".idata"))
+ for (auto it : partialSections) {
+ PartialSection *pSec = it.second;
+ if (!pSec->name.startswith(".idata"))
continue;
- if (!PSec->Chunks.empty())
- HasIdata = true;
- llvm::stable_sort(PSec->Chunks, [&](Chunk *S, Chunk *T) {
- SectionChunk *SC1 = dyn_cast_or_null<SectionChunk>(S);
- SectionChunk *SC2 = dyn_cast_or_null<SectionChunk>(T);
- if (!SC1 || !SC2) {
+ if (!pSec->chunks.empty())
+ hasIdata = true;
+ llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) {
+ SectionChunk *sc1 = dyn_cast_or_null<SectionChunk>(s);
+ SectionChunk *sc2 = dyn_cast_or_null<SectionChunk>(t);
+ if (!sc1 || !sc2) {
// if SC1, order them ascending. If SC2 or both null,
// S is not less than T.
- return SC1 != nullptr;
+ return sc1 != nullptr;
}
// Make a string with "libraryname/objectfile" for sorting, achieving
// both grouping by library and sorting of objects within a library,
// at once.
- std::string Key1 =
- (SC1->File->ParentName + "/" + SC1->File->getName()).str();
- std::string Key2 =
- (SC2->File->ParentName + "/" + SC2->File->getName()).str();
- return Key1 < Key2;
+ std::string key1 =
+ (sc1->file->parentName + "/" + sc1->file->getName()).str();
+ std::string key2 =
+ (sc2->file->parentName + "/" + sc2->file->getName()).str();
+ return key1 < key2;
});
}
- return HasIdata;
+ return hasIdata;
}
// Add generated idata chunks, for imported symbols and DLLs, and a
// terminator in .idata$2.
void Writer::addSyntheticIdata() {
- uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
- Idata.create();
+ uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+ idata.create();
// Add the .idata content in the right section groups, to allow
// chunks from other linked in object files to be grouped together.
// See Microsoft PE/COFF spec 5.4 for details.
- auto Add = [&](StringRef N, std::vector<Chunk *> &V) {
- PartialSection *PSec = createPartialSection(N, RDATA);
- PSec->Chunks.insert(PSec->Chunks.end(), V.begin(), V.end());
+ auto add = [&](StringRef n, std::vector<Chunk *> &v) {
+ PartialSection *pSec = createPartialSection(n, rdata);
+ pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end());
};
// The loader assumes a specific order of data.
// Add each type in the correct order.
- Add(".idata$2", Idata.Dirs);
- Add(".idata$4", Idata.Lookups);
- Add(".idata$5", Idata.Addresses);
- Add(".idata$6", Idata.Hints);
- Add(".idata$7", Idata.DLLNames);
+ add(".idata$2", idata.dirs);
+ add(".idata$4", idata.lookups);
+ add(".idata$5", idata.addresses);
+ add(".idata$6", idata.hints);
+ add(".idata$7", idata.dllNames);
}
// Locate the first Chunk and size of the import directory list and the
// IAT.
void Writer::locateImportTables() {
- uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+ uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
- if (PartialSection *ImportDirs = findPartialSection(".idata$2", RDATA)) {
- if (!ImportDirs->Chunks.empty())
- ImportTableStart = ImportDirs->Chunks.front();
- for (Chunk *C : ImportDirs->Chunks)
- ImportTableSize += C->getSize();
+ if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) {
+ if (!importDirs->chunks.empty())
+ importTableStart = importDirs->chunks.front();
+ for (Chunk *c : importDirs->chunks)
+ importTableSize += c->getSize();
}
- if (PartialSection *ImportAddresses = findPartialSection(".idata$5", RDATA)) {
- if (!ImportAddresses->Chunks.empty())
- IATStart = ImportAddresses->Chunks.front();
- for (Chunk *C : ImportAddresses->Chunks)
- IATSize += C->getSize();
+ if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) {
+ if (!importAddresses->chunks.empty())
+ iatStart = importAddresses->chunks.front();
+ for (Chunk *c : importAddresses->chunks)
+ iatSize += c->getSize();
}
}
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
// First, create the builtin sections.
- const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
- const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
- const uint32_t CODE = IMAGE_SCN_CNT_CODE;
- const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
- const uint32_t R = IMAGE_SCN_MEM_READ;
- const uint32_t W = IMAGE_SCN_MEM_WRITE;
- const uint32_t X = IMAGE_SCN_MEM_EXECUTE;
-
- SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> Sections;
- auto CreateSection = [&](StringRef Name, uint32_t OutChars) {
- OutputSection *&Sec = Sections[{Name, OutChars}];
- if (!Sec) {
- Sec = make<OutputSection>(Name, OutChars);
- OutputSections.push_back(Sec);
+ const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA;
+ const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ const uint32_t code = IMAGE_SCN_CNT_CODE;
+ const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE;
+ const uint32_t r = IMAGE_SCN_MEM_READ;
+ const uint32_t w = IMAGE_SCN_MEM_WRITE;
+ const uint32_t x = IMAGE_SCN_MEM_EXECUTE;
+
+ SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> sections;
+ auto createSection = [&](StringRef name, uint32_t outChars) {
+ OutputSection *&sec = sections[{name, outChars}];
+ if (!sec) {
+ sec = make<OutputSection>(name, outChars);
+ outputSections.push_back(sec);
}
- return Sec;
+ return sec;
};
// Try to match the section order used by link.exe.
- TextSec = CreateSection(".text", CODE | R | X);
- CreateSection(".bss", BSS | R | W);
- RdataSec = CreateSection(".rdata", DATA | R);
- BuildidSec = CreateSection(".buildid", DATA | R);
- DataSec = CreateSection(".data", DATA | R | W);
- PdataSec = CreateSection(".pdata", DATA | R);
- IdataSec = CreateSection(".idata", DATA | R);
- EdataSec = CreateSection(".edata", DATA | R);
- DidatSec = CreateSection(".didat", DATA | R);
- RsrcSec = CreateSection(".rsrc", DATA | R);
- RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R);
- CtorsSec = CreateSection(".ctors", DATA | R | W);
- DtorsSec = CreateSection(".dtors", DATA | R | W);
+ textSec = createSection(".text", code | r | x);
+ createSection(".bss", bss | r | w);
+ rdataSec = createSection(".rdata", data | r);
+ buildidSec = createSection(".buildid", data | r);
+ dataSec = createSection(".data", data | r | w);
+ pdataSec = createSection(".pdata", data | r);
+ idataSec = createSection(".idata", data | r);
+ edataSec = createSection(".edata", data | r);
+ didatSec = createSection(".didat", data | r);
+ rsrcSec = createSection(".rsrc", data | r);
+ relocSec = createSection(".reloc", data | discardable | r);
+ ctorsSec = createSection(".ctors", data | r | w);
+ dtorsSec = createSection(".dtors", data | r | w);
// Then bin chunks by name and output characteristics.
- for (Chunk *C : Symtab->getChunks()) {
- auto *SC = dyn_cast<SectionChunk>(C);
- if (SC && !SC->Live) {
- if (Config->Verbose)
- SC->printDiscardedMessage();
+ for (Chunk *c : symtab->getChunks()) {
+ auto *sc = dyn_cast<SectionChunk>(c);
+ if (sc && !sc->live) {
+ if (config->verbose)
+ sc->printDiscardedMessage();
continue;
}
- StringRef Name = C->getSectionName();
+ StringRef name = c->getSectionName();
// On MinGW, comdat groups are formed by putting the comdat group name
// after the '$' in the section name. Such a section name suffix shouldn't
// imply separate alphabetical sorting of those section chunks though.
- if (Config->MinGW && SC && SC->isCOMDAT())
- Name = Name.split('$').first;
- PartialSection *PSec = createPartialSection(Name,
- C->getOutputCharacteristics());
- PSec->Chunks.push_back(C);
+ if (config->mingw && sc && sc->isCOMDAT())
+ name = name.split('$').first;
+ PartialSection *pSec = createPartialSection(name,
+ c->getOutputCharacteristics());
+ pSec->chunks.push_back(c);
}
- fixPartialSectionChars(".rsrc", DATA | R);
+ fixPartialSectionChars(".rsrc", data | r);
// Even in non MinGW cases, we might need to link against GNU import
// libraries.
- bool HasIdata = fixGnuImportChunks();
- if (!Idata.empty())
- HasIdata = true;
+ bool hasIdata = fixGnuImportChunks();
+ if (!idata.empty())
+ hasIdata = true;
- if (HasIdata)
+ if (hasIdata)
addSyntheticIdata();
// Process an /order option.
- if (!Config->Order.empty())
- for (auto It : PartialSections)
- sortBySectionOrder(It.second->Chunks);
+ if (!config->order.empty())
+ for (auto it : partialSections)
+ sortBySectionOrder(it.second->chunks);
- if (HasIdata)
+ if (hasIdata)
locateImportTables();
// Then create an OutputSection for each section.
// '$' and all following characters in input section names are
// discarded when determining output section. So, .text$foo
// contributes to .text, for example. See PE/COFF spec 3.2.
- for (auto It : PartialSections) {
- PartialSection *PSec = It.second;
- StringRef Name = getOutputSectionName(PSec->Name);
- uint32_t OutChars = PSec->Characteristics;
+ for (auto it : partialSections) {
+ PartialSection *pSec = it.second;
+ StringRef name = getOutputSectionName(pSec->name);
+ uint32_t outChars = pSec->characteristics;
- if (Name == ".CRT") {
+ if (name == ".CRT") {
// In link.exe, there is a special case for the I386 target where .CRT
// sections are treated as if they have output characteristics DATA | R if
// their characteristics are DATA | R | W. This implements the same
// special case for all architectures.
- OutChars = DATA | R;
+ outChars = data | r;
- log("Processing section " + PSec->Name + " -> " + Name);
+ log("Processing section " + pSec->name + " -> " + name);
- sortCRTSectionChunks(PSec->Chunks);
+ sortCRTSectionChunks(pSec->chunks);
}
- OutputSection *Sec = CreateSection(Name, OutChars);
- for (Chunk *C : PSec->Chunks)
- Sec->addChunk(C);
+ OutputSection *sec = createSection(name, outChars);
+ for (Chunk *c : pSec->chunks)
+ sec->addChunk(c);
- Sec->addContributingPartialSection(PSec);
+ sec->addContributingPartialSection(pSec);
}
// Finally, move some output sections to the end.
- auto SectionOrder = [&](const OutputSection *S) {
+ auto sectionOrder = [&](const OutputSection *s) {
// Move DISCARDABLE (or non-memory-mapped) sections to the end of file
// because the loader cannot handle holes. Stripping can remove other
// discardable ones than .reloc, which is first of them (created early).
- if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
return 2;
// .rsrc should come at the end of the non-discardable sections because its
// size may change by the Win32 UpdateResources() function, causing
// subsequent sections to move (see https://crbug.com/827082).
- if (S == RsrcSec)
+ if (s == rsrcSec)
return 1;
return 0;
};
- llvm::stable_sort(OutputSections,
- [&](const OutputSection *S, const OutputSection *T) {
- return SectionOrder(S) < SectionOrder(T);
+ llvm::stable_sort(outputSections,
+ [&](const OutputSection *s, const OutputSection *t) {
+ return sectionOrder(s) < sectionOrder(t);
});
}
void Writer::createMiscChunks() {
- for (MergeChunk *P : MergeChunk::Instances) {
- if (P) {
- P->finalizeContents();
- RdataSec->addChunk(P);
+ for (MergeChunk *p : MergeChunk::instances) {
+ if (p) {
+ p->finalizeContents();
+ rdataSec->addChunk(p);
}
}
// Create thunks for locally-dllimported symbols.
- if (!Symtab->LocalImportChunks.empty()) {
- for (Chunk *C : Symtab->LocalImportChunks)
- RdataSec->addChunk(C);
+ if (!symtab->localImportChunks.empty()) {
+ for (Chunk *c : symtab->localImportChunks)
+ rdataSec->addChunk(c);
}
// Create Debug Information Chunks
- OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec;
- if (Config->Debug || Config->Repro) {
- DebugDirectory = make<DebugDirectoryChunk>(DebugRecords, Config->Repro);
- DebugInfoSec->addChunk(DebugDirectory);
+ OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec;
+ if (config->debug || config->repro) {
+ debugDirectory = make<DebugDirectoryChunk>(debugRecords, config->repro);
+ debugInfoSec->addChunk(debugDirectory);
}
- if (Config->Debug) {
+ if (config->debug) {
// Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We
// output a PDB no matter what, and this chunk provides the only means of
// allowing a debugger to match a PDB and an executable. So we need it even
// if we're ultimately not going to write CodeView data to the PDB.
- BuildId = make<CVDebugRecordChunk>();
- DebugRecords.push_back(BuildId);
+ buildId = make<CVDebugRecordChunk>();
+ debugRecords.push_back(buildId);
- for (Chunk *C : DebugRecords)
- DebugInfoSec->addChunk(C);
+ for (Chunk *c : debugRecords)
+ debugInfoSec->addChunk(c);
}
// Create SEH table. x86-only.
- if (Config->Machine == I386)
+ if (config->machine == I386)
createSEHTable();
// Create /guard:cf tables if requested.
- if (Config->GuardCF != GuardCFLevel::Off)
+ if (config->guardCF != GuardCFLevel::Off)
createGuardCFTables();
- if (Config->MinGW) {
+ if (config->mingw) {
createRuntimePseudoRelocs();
insertCtorDtorSymbols();
// Initialize DLLOrder so that import entries are ordered in
// the same order as in the command line. (That affects DLL
// initialization order, and this ordering is MSVC-compatible.)
- for (ImportFile *File : ImportFile::Instances) {
- if (!File->Live)
+ for (ImportFile *file : ImportFile::instances) {
+ if (!file->live)
continue;
- std::string DLL = StringRef(File->DLLName).lower();
- if (Config->DLLOrder.count(DLL) == 0)
- Config->DLLOrder[DLL] = Config->DLLOrder.size();
-
- if (File->ImpSym && !isa<DefinedImportData>(File->ImpSym))
- fatal(toString(*File->ImpSym) + " was replaced");
- DefinedImportData *ImpSym = cast_or_null<DefinedImportData>(File->ImpSym);
- if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
- if (!File->ThunkSym)
- fatal("cannot delay-load " + toString(File) +
- " due to import of data: " + toString(*ImpSym));
- DelayIdata.add(ImpSym);
+ std::string dll = StringRef(file->dllName).lower();
+ if (config->dllOrder.count(dll) == 0)
+ config->dllOrder[dll] = config->dllOrder.size();
+
+ if (file->impSym && !isa<DefinedImportData>(file->impSym))
+ fatal(toString(*file->impSym) + " was replaced");
+ DefinedImportData *impSym = cast_or_null<DefinedImportData>(file->impSym);
+ if (config->delayLoads.count(StringRef(file->dllName).lower())) {
+ if (!file->thunkSym)
+ fatal("cannot delay-load " + toString(file) +
+ " due to import of data: " + toString(*impSym));
+ delayIdata.add(impSym);
} else {
- Idata.add(ImpSym);
+ idata.add(impSym);
}
}
}
void Writer::appendImportThunks() {
- if (ImportFile::Instances.empty())
+ if (ImportFile::instances.empty())
return;
- for (ImportFile *File : ImportFile::Instances) {
- if (!File->Live)
+ for (ImportFile *file : ImportFile::instances) {
+ if (!file->live)
continue;
- if (!File->ThunkSym)
+ if (!file->thunkSym)
continue;
- if (!isa<DefinedImportThunk>(File->ThunkSym))
- fatal(toString(*File->ThunkSym) + " was replaced");
- DefinedImportThunk *Thunk = cast<DefinedImportThunk>(File->ThunkSym);
- if (File->ThunkLive)
- TextSec->addChunk(Thunk->getChunk());
+ if (!isa<DefinedImportThunk>(file->thunkSym))
+ fatal(toString(*file->thunkSym) + " was replaced");
+ DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym);
+ if (file->thunkLive)
+ textSec->addChunk(thunk->getChunk());
}
- if (!DelayIdata.empty()) {
- Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
- DelayIdata.create(Helper);
- for (Chunk *C : DelayIdata.getChunks())
- DidatSec->addChunk(C);
- for (Chunk *C : DelayIdata.getDataChunks())
- DataSec->addChunk(C);
- for (Chunk *C : DelayIdata.getCodeChunks())
- TextSec->addChunk(C);
+ if (!delayIdata.empty()) {
+ Defined *helper = cast<Defined>(config->delayLoadHelper);
+ delayIdata.create(helper);
+ for (Chunk *c : delayIdata.getChunks())
+ didatSec->addChunk(c);
+ for (Chunk *c : delayIdata.getDataChunks())
+ dataSec->addChunk(c);
+ for (Chunk *c : delayIdata.getCodeChunks())
+ textSec->addChunk(c);
}
}
void Writer::createExportTable() {
- if (Config->Exports.empty())
+ if (config->exports.empty())
return;
- for (Chunk *C : Edata.Chunks)
- EdataSec->addChunk(C);
+ for (Chunk *c : edata.chunks)
+ edataSec->addChunk(c);
}
void Writer::removeUnusedSections() {
// Remove sections that we can be sure won't get content, to avoid
// allocating space for their section headers.
- auto IsUnused = [this](OutputSection *S) {
- if (S == RelocSec)
+ auto isUnused = [this](OutputSection *s) {
+ if (s == relocSec)
return false; // This section is populated later.
// MergeChunks have zero size at this point, as their size is finalized
// later. Only remove sections that have no Chunks at all.
- return S->Chunks.empty();
+ return s->chunks.empty();
};
- OutputSections.erase(
- std::remove_if(OutputSections.begin(), OutputSections.end(), IsUnused),
- OutputSections.end());
+ outputSections.erase(
+ std::remove_if(outputSections.begin(), outputSections.end(), isUnused),
+ outputSections.end());
}
// The Windows loader doesn't seem to like empty sections,
// so we remove them if any.
void Writer::removeEmptySections() {
- auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; };
- OutputSections.erase(
- std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty),
- OutputSections.end());
+ auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; };
+ outputSections.erase(
+ std::remove_if(outputSections.begin(), outputSections.end(), isEmpty),
+ outputSections.end());
}
void Writer::assignOutputSectionIndices() {
// Assign final output section indices, and assign each chunk to its output
// section.
- uint32_t Idx = 1;
- for (OutputSection *OS : OutputSections) {
- OS->SectionIndex = Idx;
- for (Chunk *C : OS->Chunks)
- C->setOutputSectionIdx(Idx);
- ++Idx;
+ uint32_t idx = 1;
+ for (OutputSection *os : outputSections) {
+ os->sectionIndex = idx;
+ for (Chunk *c : os->chunks)
+ c->setOutputSectionIdx(idx);
+ ++idx;
}
// Merge chunks are containers of chunks, so assign those an output section
// too.
- for (MergeChunk *MC : MergeChunk::Instances)
- if (MC)
- for (SectionChunk *SC : MC->Sections)
- if (SC && SC->Live)
- SC->setOutputSectionIdx(MC->getOutputSectionIdx());
+ for (MergeChunk *mc : MergeChunk::instances)
+ if (mc)
+ for (SectionChunk *sc : mc->sections)
+ if (sc && sc->live)
+ sc->setOutputSectionIdx(mc->getOutputSectionIdx());
}
-size_t Writer::addEntryToStringTable(StringRef Str) {
- assert(Str.size() > COFF::NameSize);
- size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field
- Strtab.insert(Strtab.end(), Str.begin(), Str.end());
- Strtab.push_back('\0');
- return OffsetOfEntry;
+size_t Writer::addEntryToStringTable(StringRef str) {
+ assert(str.size() > COFF::NameSize);
+ size_t offsetOfEntry = strtab.size() + 4; // +4 for the size field
+ strtab.insert(strtab.end(), str.begin(), str.end());
+ strtab.push_back('\0');
+ return offsetOfEntry;
}
-Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
- coff_symbol16 Sym;
- switch (Def->kind()) {
+Optional<coff_symbol16> Writer::createSymbol(Defined *def) {
+ coff_symbol16 sym;
+ switch (def->kind()) {
case Symbol::DefinedAbsoluteKind:
- Sym.Value = Def->getRVA();
- Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
+ sym.Value = def->getRVA();
+ sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
break;
case Symbol::DefinedSyntheticKind:
// Relative symbols are unrepresentable in a COFF symbol table.
default: {
// Don't write symbols that won't be written to the output to the symbol
// table.
- Chunk *C = Def->getChunk();
- if (!C)
+ Chunk *c = def->getChunk();
+ if (!c)
return None;
- OutputSection *OS = C->getOutputSection();
- if (!OS)
+ OutputSection *os = c->getOutputSection();
+ if (!os)
return None;
- Sym.Value = Def->getRVA() - OS->getRVA();
- Sym.SectionNumber = OS->SectionIndex;
+ sym.Value = def->getRVA() - os->getRVA();
+ sym.SectionNumber = os->sectionIndex;
break;
}
}
- StringRef Name = Def->getName();
- if (Name.size() > COFF::NameSize) {
- Sym.Name.Offset.Zeroes = 0;
- Sym.Name.Offset.Offset = addEntryToStringTable(Name);
+ StringRef name = def->getName();
+ if (name.size() > COFF::NameSize) {
+ sym.Name.Offset.Zeroes = 0;
+ sym.Name.Offset.Offset = addEntryToStringTable(name);
} else {
- memset(Sym.Name.ShortName, 0, COFF::NameSize);
- memcpy(Sym.Name.ShortName, Name.data(), Name.size());
+ memset(sym.Name.ShortName, 0, COFF::NameSize);
+ memcpy(sym.Name.ShortName, name.data(), name.size());
}
- if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
- COFFSymbolRef Ref = D->getCOFFSymbol();
- Sym.Type = Ref.getType();
- Sym.StorageClass = Ref.getStorageClass();
+ if (auto *d = dyn_cast<DefinedCOFF>(def)) {
+ COFFSymbolRef ref = d->getCOFFSymbol();
+ sym.Type = ref.getType();
+ sym.StorageClass = ref.getStorageClass();
} else {
- Sym.Type = IMAGE_SYM_TYPE_NULL;
- Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
+ sym.Type = IMAGE_SYM_TYPE_NULL;
+ sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
}
- Sym.NumberOfAuxSymbols = 0;
- return Sym;
+ sym.NumberOfAuxSymbols = 0;
+ return sym;
}
void Writer::createSymbolAndStringTable() {
// solution where discardable sections have long names preserved and
// non-discardable sections have their names truncated, to ensure that any
// section which is mapped at runtime also has its name mapped at runtime.
- for (OutputSection *Sec : OutputSections) {
- if (Sec->Name.size() <= COFF::NameSize)
+ for (OutputSection *sec : outputSections) {
+ if (sec->name.size() <= COFF::NameSize)
continue;
- if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
+ if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
continue;
- Sec->setStringTableOff(addEntryToStringTable(Sec->Name));
+ sec->setStringTableOff(addEntryToStringTable(sec->name));
}
- if (Config->DebugDwarf || Config->DebugSymtab) {
- for (ObjFile *File : ObjFile::Instances) {
- for (Symbol *B : File->getSymbols()) {
- auto *D = dyn_cast_or_null<Defined>(B);
- if (!D || D->WrittenToSymtab)
+ if (config->debugDwarf || config->debugSymtab) {
+ for (ObjFile *file : ObjFile::instances) {
+ for (Symbol *b : file->getSymbols()) {
+ auto *d = dyn_cast_or_null<Defined>(b);
+ if (!d || d->writtenToSymtab)
continue;
- D->WrittenToSymtab = true;
+ d->writtenToSymtab = true;
- if (Optional<coff_symbol16> Sym = createSymbol(D))
- OutputSymtab.push_back(*Sym);
+ if (Optional<coff_symbol16> sym = createSymbol(d))
+ outputSymtab.push_back(*sym);
}
}
}
- if (OutputSymtab.empty() && Strtab.empty())
+ if (outputSymtab.empty() && strtab.empty())
return;
// We position the symbol table to be adjacent to the end of the last section.
- uint64_t FileOff = FileSize;
- PointerToSymbolTable = FileOff;
- FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
- FileOff += 4 + Strtab.size();
- FileSize = alignTo(FileOff, Config->FileAlign);
+ uint64_t fileOff = fileSize;
+ pointerToSymbolTable = fileOff;
+ fileOff += outputSymtab.size() * sizeof(coff_symbol16);
+ fileOff += 4 + strtab.size();
+ fileSize = alignTo(fileOff, config->fileAlign);
}
void Writer::mergeSections() {
- if (!PdataSec->Chunks.empty()) {
- FirstPdata = PdataSec->Chunks.front();
- LastPdata = PdataSec->Chunks.back();
+ if (!pdataSec->chunks.empty()) {
+ firstPdata = pdataSec->chunks.front();
+ lastPdata = pdataSec->chunks.back();
}
- for (auto &P : Config->Merge) {
- StringRef ToName = P.second;
- if (P.first == ToName)
+ for (auto &p : config->merge) {
+ StringRef toName = p.second;
+ if (p.first == toName)
continue;
- StringSet<> Names;
+ StringSet<> names;
while (1) {
- if (!Names.insert(ToName).second)
- fatal("/merge: cycle found for section '" + P.first + "'");
- auto I = Config->Merge.find(ToName);
- if (I == Config->Merge.end())
+ if (!names.insert(toName).second)
+ fatal("/merge: cycle found for section '" + p.first + "'");
+ auto i = config->merge.find(toName);
+ if (i == config->merge.end())
break;
- ToName = I->second;
+ toName = i->second;
}
- OutputSection *From = findSection(P.first);
- OutputSection *To = findSection(ToName);
- if (!From)
+ OutputSection *from = findSection(p.first);
+ OutputSection *to = findSection(toName);
+ if (!from)
continue;
- if (!To) {
- From->Name = ToName;
+ if (!to) {
+ from->name = toName;
continue;
}
- To->merge(From);
+ to->merge(from);
}
}
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
void Writer::assignAddresses() {
- SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
- sizeof(data_directory) * NumberOfDataDirectory +
- sizeof(coff_section) * OutputSections.size();
- SizeOfHeaders +=
- Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
- SizeOfHeaders = alignTo(SizeOfHeaders, Config->FileAlign);
- uint64_t RVA = PageSize; // The first page is kept unmapped.
- FileSize = SizeOfHeaders;
-
- for (OutputSection *Sec : OutputSections) {
- if (Sec == RelocSec)
+ sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
+ sizeof(data_directory) * numberOfDataDirectory +
+ sizeof(coff_section) * outputSections.size();
+ sizeOfHeaders +=
+ config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
+ sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign);
+ uint64_t rva = pageSize; // The first page is kept unmapped.
+ fileSize = sizeOfHeaders;
+
+ for (OutputSection *sec : outputSections) {
+ if (sec == relocSec)
addBaserels();
- uint64_t RawSize = 0, VirtualSize = 0;
- Sec->Header.VirtualAddress = RVA;
+ uint64_t rawSize = 0, virtualSize = 0;
+ sec->header.VirtualAddress = rva;
// If /FUNCTIONPADMIN is used, functions are padded in order to create a
// hotpatchable image.
- const bool IsCodeSection =
- (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
- (Sec->Header.Characteristics & IMAGE_SCN_MEM_READ) &&
- (Sec->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE);
- uint32_t Padding = IsCodeSection ? Config->FunctionPadMin : 0;
-
- for (Chunk *C : Sec->Chunks) {
- if (Padding && C->isHotPatchable())
- VirtualSize += Padding;
- VirtualSize = alignTo(VirtualSize, C->getAlignment());
- C->setRVA(RVA + VirtualSize);
- VirtualSize += C->getSize();
- if (C->HasData)
- RawSize = alignTo(VirtualSize, Config->FileAlign);
+ const bool isCodeSection =
+ (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) &&
+ (sec->header.Characteristics & IMAGE_SCN_MEM_READ) &&
+ (sec->header.Characteristics & IMAGE_SCN_MEM_EXECUTE);
+ uint32_t padding = isCodeSection ? config->functionPadMin : 0;
+
+ for (Chunk *c : sec->chunks) {
+ if (padding && c->isHotPatchable())
+ virtualSize += padding;
+ virtualSize = alignTo(virtualSize, c->getAlignment());
+ c->setRVA(rva + virtualSize);
+ virtualSize += c->getSize();
+ if (c->hasData)
+ rawSize = alignTo(virtualSize, config->fileAlign);
}
- if (VirtualSize > UINT32_MAX)
- error("section larger than 4 GiB: " + Sec->Name);
- Sec->Header.VirtualSize = VirtualSize;
- Sec->Header.SizeOfRawData = RawSize;
- if (RawSize != 0)
- Sec->Header.PointerToRawData = FileSize;
- RVA += alignTo(VirtualSize, PageSize);
- FileSize += alignTo(RawSize, Config->FileAlign);
+ if (virtualSize > UINT32_MAX)
+ error("section larger than 4 GiB: " + sec->name);
+ sec->header.VirtualSize = virtualSize;
+ sec->header.SizeOfRawData = rawSize;
+ if (rawSize != 0)
+ sec->header.PointerToRawData = fileSize;
+ rva += alignTo(virtualSize, pageSize);
+ fileSize += alignTo(rawSize, config->fileAlign);
}
- SizeOfImage = alignTo(RVA, PageSize);
+ sizeOfImage = alignTo(rva, pageSize);
// Assign addresses to sections in MergeChunks.
- for (MergeChunk *MC : MergeChunk::Instances)
- if (MC)
- MC->assignSubsectionRVAs();
+ for (MergeChunk *mc : MergeChunk::instances)
+ if (mc)
+ mc->assignSubsectionRVAs();
}
template <typename PEHeaderTy> void Writer::writeHeader() {
// under DOS, that program gets run (usually to just print an error message).
// When run under Windows, the loader looks at AddressOfNewExeHeader and uses
// the PE header instead.
- uint8_t *Buf = Buffer->getBufferStart();
- auto *DOS = reinterpret_cast<dos_header *>(Buf);
- Buf += sizeof(dos_header);
- DOS->Magic[0] = 'M';
- DOS->Magic[1] = 'Z';
- DOS->UsedBytesInTheLastPage = DOSStubSize % 512;
- DOS->FileSizeInPages = divideCeil(DOSStubSize, 512);
- DOS->HeaderSizeInParagraphs = sizeof(dos_header) / 16;
-
- DOS->AddressOfRelocationTable = sizeof(dos_header);
- DOS->AddressOfNewExeHeader = DOSStubSize;
+ uint8_t *buf = buffer->getBufferStart();
+ auto *dos = reinterpret_cast<dos_header *>(buf);
+ buf += sizeof(dos_header);
+ dos->Magic[0] = 'M';
+ dos->Magic[1] = 'Z';
+ dos->UsedBytesInTheLastPage = dosStubSize % 512;
+ dos->FileSizeInPages = divideCeil(dosStubSize, 512);
+ dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16;
+
+ dos->AddressOfRelocationTable = sizeof(dos_header);
+ dos->AddressOfNewExeHeader = dosStubSize;
// Write DOS program.
- memcpy(Buf, DOSProgram, sizeof(DOSProgram));
- Buf += sizeof(DOSProgram);
+ memcpy(buf, dosProgram, sizeof(dosProgram));
+ buf += sizeof(dosProgram);
// Write PE magic
- memcpy(Buf, PEMagic, sizeof(PEMagic));
- Buf += sizeof(PEMagic);
+ memcpy(buf, PEMagic, sizeof(PEMagic));
+ buf += sizeof(PEMagic);
// Write COFF header
- auto *COFF = reinterpret_cast<coff_file_header *>(Buf);
- Buf += sizeof(*COFF);
- COFF->Machine = Config->Machine;
- COFF->NumberOfSections = OutputSections.size();
- COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
- if (Config->LargeAddressAware)
- COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
- if (!Config->is64())
- COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE;
- if (Config->DLL)
- COFF->Characteristics |= IMAGE_FILE_DLL;
- if (!Config->Relocatable)
- COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
- if (Config->SwaprunCD)
- COFF->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP;
- if (Config->SwaprunNet)
- COFF->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP;
- COFF->SizeOfOptionalHeader =
- sizeof(PEHeaderTy) + sizeof(data_directory) * NumberOfDataDirectory;
+ auto *coff = reinterpret_cast<coff_file_header *>(buf);
+ buf += sizeof(*coff);
+ coff->Machine = config->machine;
+ coff->NumberOfSections = outputSections.size();
+ coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
+ if (config->largeAddressAware)
+ coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+ if (!config->is64())
+ coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE;
+ if (config->dll)
+ coff->Characteristics |= IMAGE_FILE_DLL;
+ if (!config->relocatable)
+ coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
+ if (config->swaprunCD)
+ coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP;
+ if (config->swaprunNet)
+ coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP;
+ coff->SizeOfOptionalHeader =
+ sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory;
// Write PE header
- auto *PE = reinterpret_cast<PEHeaderTy *>(Buf);
- Buf += sizeof(*PE);
- PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;
+ auto *pe = reinterpret_cast<PEHeaderTy *>(buf);
+ buf += sizeof(*pe);
+ pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;
// If {Major,Minor}LinkerVersion is left at 0.0, then for some
// reason signing the resulting PE file with Authenticode produces a
// signature that fails to validate on Windows 7 (but is OK on 10).
// Set it to 14.0, which is what VS2015 outputs, and which avoids
// that problem.
- PE->MajorLinkerVersion = 14;
- PE->MinorLinkerVersion = 0;
-
- PE->ImageBase = Config->ImageBase;
- PE->SectionAlignment = PageSize;
- PE->FileAlignment = Config->FileAlign;
- PE->MajorImageVersion = Config->MajorImageVersion;
- PE->MinorImageVersion = Config->MinorImageVersion;
- PE->MajorOperatingSystemVersion = Config->MajorOSVersion;
- PE->MinorOperatingSystemVersion = Config->MinorOSVersion;
- PE->MajorSubsystemVersion = Config->MajorOSVersion;
- PE->MinorSubsystemVersion = Config->MinorOSVersion;
- PE->Subsystem = Config->Subsystem;
- PE->SizeOfImage = SizeOfImage;
- PE->SizeOfHeaders = SizeOfHeaders;
- if (!Config->NoEntry) {
- Defined *Entry = cast<Defined>(Config->Entry);
- PE->AddressOfEntryPoint = Entry->getRVA();
+ pe->MajorLinkerVersion = 14;
+ pe->MinorLinkerVersion = 0;
+
+ pe->ImageBase = config->imageBase;
+ pe->SectionAlignment = pageSize;
+ pe->FileAlignment = config->fileAlign;
+ pe->MajorImageVersion = config->majorImageVersion;
+ pe->MinorImageVersion = config->minorImageVersion;
+ pe->MajorOperatingSystemVersion = config->majorOSVersion;
+ pe->MinorOperatingSystemVersion = config->minorOSVersion;
+ pe->MajorSubsystemVersion = config->majorOSVersion;
+ pe->MinorSubsystemVersion = config->minorOSVersion;
+ pe->Subsystem = config->subsystem;
+ pe->SizeOfImage = sizeOfImage;
+ pe->SizeOfHeaders = sizeOfHeaders;
+ if (!config->noEntry) {
+ Defined *entry = cast<Defined>(config->entry);
+ pe->AddressOfEntryPoint = entry->getRVA();
// Pointer to thumb code must have the LSB set, so adjust it.
- if (Config->Machine == ARMNT)
- PE->AddressOfEntryPoint |= 1;
- }
- PE->SizeOfStackReserve = Config->StackReserve;
- PE->SizeOfStackCommit = Config->StackCommit;
- PE->SizeOfHeapReserve = Config->HeapReserve;
- PE->SizeOfHeapCommit = Config->HeapCommit;
- if (Config->AppContainer)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
- if (Config->DynamicBase)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
- if (Config->HighEntropyVA)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
- if (!Config->AllowBind)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;
- if (Config->NxCompat)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
- if (!Config->AllowIsolation)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
- if (Config->GuardCF != GuardCFLevel::Off)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;
- if (Config->IntegrityCheck)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY;
- if (SetNoSEHCharacteristic)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;
- if (Config->TerminalServerAware)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
- PE->NumberOfRvaAndSize = NumberOfDataDirectory;
- if (TextSec->getVirtualSize()) {
- PE->BaseOfCode = TextSec->getRVA();
- PE->SizeOfCode = TextSec->getRawSize();
- }
- PE->SizeOfInitializedData = getSizeOfInitializedData();
+ if (config->machine == ARMNT)
+ pe->AddressOfEntryPoint |= 1;
+ }
+ pe->SizeOfStackReserve = config->stackReserve;
+ pe->SizeOfStackCommit = config->stackCommit;
+ pe->SizeOfHeapReserve = config->heapReserve;
+ pe->SizeOfHeapCommit = config->heapCommit;
+ if (config->appContainer)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
+ if (config->dynamicBase)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
+ if (config->highEntropyVA)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
+ if (!config->allowBind)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;
+ if (config->nxCompat)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
+ if (!config->allowIsolation)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
+ if (config->guardCF != GuardCFLevel::Off)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF;
+ if (config->integrityCheck)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY;
+ if (setNoSEHCharacteristic)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;
+ if (config->terminalServerAware)
+ pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
+ pe->NumberOfRvaAndSize = numberOfDataDirectory;
+ if (textSec->getVirtualSize()) {
+ pe->BaseOfCode = textSec->getRVA();
+ pe->SizeOfCode = textSec->getRawSize();
+ }
+ pe->SizeOfInitializedData = getSizeOfInitializedData();
// Write data directory
- auto *Dir = reinterpret_cast<data_directory *>(Buf);
- Buf += sizeof(*Dir) * NumberOfDataDirectory;
- if (!Config->Exports.empty()) {
- Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA();
- Dir[EXPORT_TABLE].Size = Edata.getSize();
- }
- if (ImportTableStart) {
- Dir[IMPORT_TABLE].RelativeVirtualAddress = ImportTableStart->getRVA();
- Dir[IMPORT_TABLE].Size = ImportTableSize;
- }
- if (IATStart) {
- Dir[IAT].RelativeVirtualAddress = IATStart->getRVA();
- Dir[IAT].Size = IATSize;
- }
- if (RsrcSec->getVirtualSize()) {
- Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
- Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize();
- }
- if (FirstPdata) {
- Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA();
- Dir[EXCEPTION_TABLE].Size =
- LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA();
- }
- if (RelocSec->getVirtualSize()) {
- Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA();
- Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize();
- }
- if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
- if (Defined *B = dyn_cast<Defined>(Sym)) {
- Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA();
- Dir[TLS_TABLE].Size = Config->is64()
+ auto *dir = reinterpret_cast<data_directory *>(buf);
+ buf += sizeof(*dir) * numberOfDataDirectory;
+ if (!config->exports.empty()) {
+ dir[EXPORT_TABLE].RelativeVirtualAddress = edata.getRVA();
+ dir[EXPORT_TABLE].Size = edata.getSize();
+ }
+ if (importTableStart) {
+ dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA();
+ dir[IMPORT_TABLE].Size = importTableSize;
+ }
+ if (iatStart) {
+ dir[IAT].RelativeVirtualAddress = iatStart->getRVA();
+ dir[IAT].Size = iatSize;
+ }
+ if (rsrcSec->getVirtualSize()) {
+ dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA();
+ dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize();
+ }
+ if (firstPdata) {
+ dir[EXCEPTION_TABLE].RelativeVirtualAddress = firstPdata->getRVA();
+ dir[EXCEPTION_TABLE].Size =
+ lastPdata->getRVA() + lastPdata->getSize() - firstPdata->getRVA();
+ }
+ if (relocSec->getVirtualSize()) {
+ dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA();
+ dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize();
+ }
+ if (Symbol *sym = symtab->findUnderscore("_tls_used")) {
+ if (Defined *b = dyn_cast<Defined>(sym)) {
+ dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA();
+ dir[TLS_TABLE].Size = config->is64()
? sizeof(object::coff_tls_directory64)
: sizeof(object::coff_tls_directory32);
}
}
- if (DebugDirectory) {
- Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA();
- Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize();
+ if (debugDirectory) {
+ dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA();
+ dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize();
}
- if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) {
- if (auto *B = dyn_cast<DefinedRegular>(Sym)) {
- SectionChunk *SC = B->getChunk();
- assert(B->getRVA() >= SC->getRVA());
- uint64_t OffsetInChunk = B->getRVA() - SC->getRVA();
- if (!SC->HasData || OffsetInChunk + 4 > SC->getSize())
+ if (Symbol *sym = symtab->findUnderscore("_load_config_used")) {
+ if (auto *b = dyn_cast<DefinedRegular>(sym)) {
+ SectionChunk *sc = b->getChunk();
+ assert(b->getRVA() >= sc->getRVA());
+ uint64_t offsetInChunk = b->getRVA() - sc->getRVA();
+ if (!sc->hasData || offsetInChunk + 4 > sc->getSize())
fatal("_load_config_used is malformed");
- ArrayRef<uint8_t> SecContents = SC->getContents();
- uint32_t LoadConfigSize =
- *reinterpret_cast<const ulittle32_t *>(&SecContents[OffsetInChunk]);
- if (OffsetInChunk + LoadConfigSize > SC->getSize())
+ ArrayRef<uint8_t> secContents = sc->getContents();
+ uint32_t loadConfigSize =
+ *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]);
+ if (offsetInChunk + loadConfigSize > sc->getSize())
fatal("_load_config_used is too large");
- Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA();
- Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize;
+ dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA();
+ dir[LOAD_CONFIG_TABLE].Size = loadConfigSize;
}
}
- if (!DelayIdata.empty()) {
- Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
- DelayIdata.getDirRVA();
- Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize();
+ if (!delayIdata.empty()) {
+ dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
+ delayIdata.getDirRVA();
+ dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize();
}
// Write section table
- for (OutputSection *Sec : OutputSections) {
- Sec->writeHeaderTo(Buf);
- Buf += sizeof(coff_section);
+ for (OutputSection *sec : outputSections) {
+ sec->writeHeaderTo(buf);
+ buf += sizeof(coff_section);
}
- SectionTable = ArrayRef<uint8_t>(
- Buf - OutputSections.size() * sizeof(coff_section), Buf);
+ sectionTable = ArrayRef<uint8_t>(
+ buf - outputSections.size() * sizeof(coff_section), buf);
- if (OutputSymtab.empty() && Strtab.empty())
+ if (outputSymtab.empty() && strtab.empty())
return;
- COFF->PointerToSymbolTable = PointerToSymbolTable;
- uint32_t NumberOfSymbols = OutputSymtab.size();
- COFF->NumberOfSymbols = NumberOfSymbols;
- auto *SymbolTable = reinterpret_cast<coff_symbol16 *>(
- Buffer->getBufferStart() + COFF->PointerToSymbolTable);
- for (size_t I = 0; I != NumberOfSymbols; ++I)
- SymbolTable[I] = OutputSymtab[I];
+ coff->PointerToSymbolTable = pointerToSymbolTable;
+ uint32_t numberOfSymbols = outputSymtab.size();
+ coff->NumberOfSymbols = numberOfSymbols;
+ auto *symbolTable = reinterpret_cast<coff_symbol16 *>(
+ buffer->getBufferStart() + coff->PointerToSymbolTable);
+ for (size_t i = 0; i != numberOfSymbols; ++i)
+ symbolTable[i] = outputSymtab[i];
// Create the string table, it follows immediately after the symbol table.
// The first 4 bytes is length including itself.
- Buf = reinterpret_cast<uint8_t *>(&SymbolTable[NumberOfSymbols]);
- write32le(Buf, Strtab.size() + 4);
- if (!Strtab.empty())
- memcpy(Buf + 4, Strtab.data(), Strtab.size());
+ buf = reinterpret_cast<uint8_t *>(&symbolTable[numberOfSymbols]);
+ write32le(buf, strtab.size() + 4);
+ if (!strtab.empty())
+ memcpy(buf + 4, strtab.data(), strtab.size());
}
-void Writer::openFile(StringRef Path) {
- Buffer = CHECK(
- FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable),
- "failed to open " + Path);
+void Writer::openFile(StringRef path) {
+ buffer = CHECK(
+ FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable),
+ "failed to open " + path);
}
void Writer::createSEHTable() {
// Set the no SEH characteristic on x86 binaries unless we find exception
// handlers.
- SetNoSEHCharacteristic = true;
+ setNoSEHCharacteristic = true;
- SymbolRVASet Handlers;
- for (ObjFile *File : ObjFile::Instances) {
+ SymbolRVASet handlers;
+ for (ObjFile *file : ObjFile::instances) {
// FIXME: We should error here instead of earlier unless /safeseh:no was
// passed.
- if (!File->hasSafeSEH())
+ if (!file->hasSafeSEH())
return;
- markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers);
+ markSymbolsForRVATable(file, file->getSXDataChunks(), handlers);
}
// Remove the "no SEH" characteristic if all object files were built with
// safeseh, we found some exception handlers, and there is a load config in
// the object.
- SetNoSEHCharacteristic =
- Handlers.empty() || !Symtab->findUnderscore("_load_config_used");
+ setNoSEHCharacteristic =
+ handlers.empty() || !symtab->findUnderscore("_load_config_used");
- maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table",
+ maybeAddRVATable(std::move(handlers), "__safe_se_handler_table",
"__safe_se_handler_count");
}
// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set
// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the
// symbol's offset into that Chunk.
-static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) {
- Chunk *C = S->getChunk();
- if (auto *SC = dyn_cast<SectionChunk>(C))
- C = SC->Repl; // Look through ICF replacement.
- uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0);
- RVASet.insert({C, Off});
+static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) {
+ Chunk *c = s->getChunk();
+ if (auto *sc = dyn_cast<SectionChunk>(c))
+ c = sc->repl; // Look through ICF replacement.
+ uint32_t off = s->getRVA() - (c ? c->getRVA() : 0);
+ rvaSet.insert({c, off});
}
// Given a symbol, add it to the GFIDs table if it is a live, defined, function
// symbol in an executable section.
-static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms,
- Symbol *S) {
- if (!S)
+static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms,
+ Symbol *s) {
+ if (!s)
return;
- switch (S->kind()) {
+ switch (s->kind()) {
case Symbol::DefinedLocalImportKind:
case Symbol::DefinedImportDataKind:
// Defines an __imp_ pointer, so it is data, so it is ignored.
case Symbol::DefinedImportThunkKind:
// Thunks are always code, include them.
- addSymbolToRVASet(AddressTakenSyms, cast<Defined>(S));
+ addSymbolToRVASet(addressTakenSyms, cast<Defined>(s));
break;
case Symbol::DefinedRegularKind: {
// This is a regular, defined, symbol from a COFF file. Mark the symbol as
// address taken if the symbol type is function and it's in an executable
// section.
- auto *D = cast<DefinedRegular>(S);
- if (D->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) {
- SectionChunk *SC = dyn_cast<SectionChunk>(D->getChunk());
- if (SC && SC->Live &&
- SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)
- addSymbolToRVASet(AddressTakenSyms, D);
+ auto *d = cast<DefinedRegular>(s);
+ if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) {
+ SectionChunk *sc = dyn_cast<SectionChunk>(d->getChunk());
+ if (sc && sc->live &&
+ sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)
+ addSymbolToRVASet(addressTakenSyms, d);
}
break;
}
// Visit all relocations from all section contributions of this object file and
// mark the relocation target as address-taken.
-static void markSymbolsWithRelocations(ObjFile *File,
- SymbolRVASet &UsedSymbols) {
- for (Chunk *C : File->getChunks()) {
+static void markSymbolsWithRelocations(ObjFile *file,
+ SymbolRVASet &usedSymbols) {
+ for (Chunk *c : file->getChunks()) {
// We only care about live section chunks. Common chunks and other chunks
// don't generally contain relocations.
- SectionChunk *SC = dyn_cast<SectionChunk>(C);
- if (!SC || !SC->Live)
+ SectionChunk *sc = dyn_cast<SectionChunk>(c);
+ if (!sc || !sc->live)
continue;
- for (const coff_relocation &Reloc : SC->getRelocs()) {
- if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32)
+ for (const coff_relocation &reloc : sc->getRelocs()) {
+ if (config->machine == I386 && reloc.Type == COFF::IMAGE_REL_I386_REL32)
// Ignore relative relocations on x86. On x86_64 they can't be ignored
// since they're also used to compute absolute addresses.
continue;
- Symbol *Ref = SC->File->getSymbol(Reloc.SymbolTableIndex);
- maybeAddAddressTakenFunction(UsedSymbols, Ref);
+ Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex);
+ maybeAddAddressTakenFunction(usedSymbols, ref);
}
}
}
// address-taken functions. It is sorted and uniqued, just like the safe SEH
// table.
void Writer::createGuardCFTables() {
- SymbolRVASet AddressTakenSyms;
- SymbolRVASet LongJmpTargets;
- for (ObjFile *File : ObjFile::Instances) {
+ SymbolRVASet addressTakenSyms;
+ SymbolRVASet longJmpTargets;
+ for (ObjFile *file : ObjFile::instances) {
// If the object was compiled with /guard:cf, the address taken symbols
// are in .gfids$y sections, and the longjmp targets are in .gljmp$y
// sections. If the object was not compiled with /guard:cf, we assume there
// were no setjmp targets, and that all code symbols with relocations are
// possibly address-taken.
- if (File->hasGuardCF()) {
- markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms);
- markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets);
+ if (file->hasGuardCF()) {
+ markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms);
+ markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets);
} else {
- markSymbolsWithRelocations(File, AddressTakenSyms);
+ markSymbolsWithRelocations(file, addressTakenSyms);
}
}
// Mark the image entry as address-taken.
- if (Config->Entry)
- maybeAddAddressTakenFunction(AddressTakenSyms, Config->Entry);
+ if (config->entry)
+ maybeAddAddressTakenFunction(addressTakenSyms, config->entry);
// Mark exported symbols in executable sections as address-taken.
- for (Export &E : Config->Exports)
- maybeAddAddressTakenFunction(AddressTakenSyms, E.Sym);
+ for (Export &e : config->exports)
+ maybeAddAddressTakenFunction(addressTakenSyms, e.sym);
// Ensure sections referenced in the gfid table are 16-byte aligned.
- for (const ChunkAndOffset &C : AddressTakenSyms)
- if (C.InputChunk->getAlignment() < 16)
- C.InputChunk->setAlignment(16);
+ for (const ChunkAndOffset &c : addressTakenSyms)
+ if (c.inputChunk->getAlignment() < 16)
+ c.inputChunk->setAlignment(16);
- maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table",
+ maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table",
"__guard_fids_count");
// Add the longjmp target table unless the user told us not to.
- if (Config->GuardCF == GuardCFLevel::Full)
- maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table",
+ if (config->guardCF == GuardCFLevel::Full)
+ maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table",
"__guard_longjmp_count");
// Set __guard_flags, which will be used in the load config to indicate that
// /guard:cf was enabled.
- uint32_t GuardFlags = uint32_t(coff_guard_flags::CFInstrumented) |
+ uint32_t guardFlags = uint32_t(coff_guard_flags::CFInstrumented) |
uint32_t(coff_guard_flags::HasFidTable);
- if (Config->GuardCF == GuardCFLevel::Full)
- GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
- Symbol *FlagSym = Symtab->findUnderscore("__guard_flags");
- cast<DefinedAbsolute>(FlagSym)->setVA(GuardFlags);
+ if (config->guardCF == GuardCFLevel::Full)
+ guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable);
+ Symbol *flagSym = symtab->findUnderscore("__guard_flags");
+ cast<DefinedAbsolute>(flagSym)->setVA(guardFlags);
}
// Take a list of input sections containing symbol table indices and add those
// symbols to an RVA table. The challenge is that symbol RVAs are not known and
// depend on the table size, so we can't directly build a set of integers.
-void Writer::markSymbolsForRVATable(ObjFile *File,
- ArrayRef<SectionChunk *> SymIdxChunks,
- SymbolRVASet &TableSymbols) {
- for (SectionChunk *C : SymIdxChunks) {
+void Writer::markSymbolsForRVATable(ObjFile *file,
+ ArrayRef<SectionChunk *> symIdxChunks,
+ SymbolRVASet &tableSymbols) {
+ for (SectionChunk *c : symIdxChunks) {
// Skip sections discarded by linker GC. This comes up when a .gfids section
// is associated with something like a vtable and the vtable is discarded.
// In this case, the associated gfids section is discarded, and we don't
// mark the virtual member functions as address-taken by the vtable.
- if (!C->Live)
+ if (!c->live)
continue;
// Validate that the contents look like symbol table indices.
- ArrayRef<uint8_t> Data = C->getContents();
- if (Data.size() % 4 != 0) {
- warn("ignoring " + C->getSectionName() +
- " symbol table index section in object " + toString(File));
+ ArrayRef<uint8_t> data = c->getContents();
+ if (data.size() % 4 != 0) {
+ warn("ignoring " + c->getSectionName() +
+ " symbol table index section in object " + toString(file));
continue;
}
// Read each symbol table index and check if that symbol was included in the
// final link. If so, add it to the table symbol set.
- ArrayRef<ulittle32_t> SymIndices(
- reinterpret_cast<const ulittle32_t *>(Data.data()), Data.size() / 4);
- ArrayRef<Symbol *> ObjSymbols = File->getSymbols();
- for (uint32_t SymIndex : SymIndices) {
- if (SymIndex >= ObjSymbols.size()) {
+ ArrayRef<ulittle32_t> symIndices(
+ reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4);
+ ArrayRef<Symbol *> objSymbols = file->getSymbols();
+ for (uint32_t symIndex : symIndices) {
+ if (symIndex >= objSymbols.size()) {
warn("ignoring invalid symbol table index in section " +
- C->getSectionName() + " in object " + toString(File));
+ c->getSectionName() + " in object " + toString(file));
continue;
}
- if (Symbol *S = ObjSymbols[SymIndex]) {
- if (S->isLive())
- addSymbolToRVASet(TableSymbols, cast<Defined>(S));
+ if (Symbol *s = objSymbols[symIndex]) {
+ if (s->isLive())
+ addSymbolToRVASet(tableSymbols, cast<Defined>(s));
}
}
}
// Replace the absolute table symbol with a synthetic symbol pointing to
// TableChunk so that we can emit base relocations for it and resolve section
// relative relocations.
-void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
- StringRef CountSym) {
- if (TableSymbols.empty())
+void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym,
+ StringRef countSym) {
+ if (tableSymbols.empty())
return;
- RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols));
- RdataSec->addChunk(TableChunk);
+ RVATableChunk *tableChunk = make<RVATableChunk>(std::move(tableSymbols));
+ rdataSec->addChunk(tableChunk);
- Symbol *T = Symtab->findUnderscore(TableSym);
- Symbol *C = Symtab->findUnderscore(CountSym);
- replaceSymbol<DefinedSynthetic>(T, T->getName(), TableChunk);
- cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 4);
+ Symbol *t = symtab->findUnderscore(tableSym);
+ Symbol *c = symtab->findUnderscore(countSym);
+ replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk);
+ cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / 4);
}
// MinGW specific. Gather all relocations that are imported from a DLL even
// uses for fixing them up, and provide the synthetic symbols that the
// runtime uses for finding the table.
void Writer::createRuntimePseudoRelocs() {
- std::vector<RuntimePseudoReloc> Rels;
+ std::vector<RuntimePseudoReloc> rels;
- for (Chunk *C : Symtab->getChunks()) {
- auto *SC = dyn_cast<SectionChunk>(C);
- if (!SC || !SC->Live)
+ for (Chunk *c : symtab->getChunks()) {
+ auto *sc = dyn_cast<SectionChunk>(c);
+ if (!sc || !sc->live)
continue;
- SC->getRuntimePseudoRelocs(Rels);
+ sc->getRuntimePseudoRelocs(rels);
}
- if (!Rels.empty())
- log("Writing " + Twine(Rels.size()) + " runtime pseudo relocations");
- PseudoRelocTableChunk *Table = make<PseudoRelocTableChunk>(Rels);
- RdataSec->addChunk(Table);
- EmptyChunk *EndOfList = make<EmptyChunk>();
- RdataSec->addChunk(EndOfList);
+ if (!rels.empty())
+ log("Writing " + Twine(rels.size()) + " runtime pseudo relocations");
+ PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels);
+ rdataSec->addChunk(table);
+ EmptyChunk *endOfList = make<EmptyChunk>();
+ rdataSec->addChunk(endOfList);
- Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
- Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
- replaceSymbol<DefinedSynthetic>(HeadSym, HeadSym->getName(), Table);
- replaceSymbol<DefinedSynthetic>(EndSym, EndSym->getName(), EndOfList);
+ Symbol *headSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
+ Symbol *endSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
+ replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table);
+ replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList);
}
// MinGW specific.
// There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__
// and __DTOR_LIST__ respectively.
void Writer::insertCtorDtorSymbols() {
- AbsolutePointerChunk *CtorListHead = make<AbsolutePointerChunk>(-1);
- AbsolutePointerChunk *CtorListEnd = make<AbsolutePointerChunk>(0);
- AbsolutePointerChunk *DtorListHead = make<AbsolutePointerChunk>(-1);
- AbsolutePointerChunk *DtorListEnd = make<AbsolutePointerChunk>(0);
- CtorsSec->insertChunkAtStart(CtorListHead);
- CtorsSec->addChunk(CtorListEnd);
- DtorsSec->insertChunkAtStart(DtorListHead);
- DtorsSec->addChunk(DtorListEnd);
-
- Symbol *CtorListSym = Symtab->findUnderscore("__CTOR_LIST__");
- Symbol *DtorListSym = Symtab->findUnderscore("__DTOR_LIST__");
- replaceSymbol<DefinedSynthetic>(CtorListSym, CtorListSym->getName(),
- CtorListHead);
- replaceSymbol<DefinedSynthetic>(DtorListSym, DtorListSym->getName(),
- DtorListHead);
+ AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(-1);
+ AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(0);
+ AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(-1);
+ AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(0);
+ ctorsSec->insertChunkAtStart(ctorListHead);
+ ctorsSec->addChunk(ctorListEnd);
+ dtorsSec->insertChunkAtStart(dtorListHead);
+ dtorsSec->addChunk(dtorListEnd);
+
+ Symbol *ctorListSym = symtab->findUnderscore("__CTOR_LIST__");
+ Symbol *dtorListSym = symtab->findUnderscore("__DTOR_LIST__");
+ replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(),
+ ctorListHead);
+ replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(),
+ dtorListHead);
}
// Handles /section options to allow users to overwrite
// section attributes.
void Writer::setSectionPermissions() {
- for (auto &P : Config->Section) {
- StringRef Name = P.first;
- uint32_t Perm = P.second;
- for (OutputSection *Sec : OutputSections)
- if (Sec->Name == Name)
- Sec->setPermissions(Perm);
+ for (auto &p : config->section) {
+ StringRef name = p.first;
+ uint32_t perm = p.second;
+ for (OutputSection *sec : outputSections)
+ if (sec->name == name)
+ sec->setPermissions(perm);
}
}
void Writer::writeSections() {
// Record the number of sections to apply section index relocations
// against absolute symbols. See applySecIdx in Chunks.cpp..
- DefinedAbsolute::NumOutputSections = OutputSections.size();
+ DefinedAbsolute::numOutputSections = outputSections.size();
- uint8_t *Buf = Buffer->getBufferStart();
- for (OutputSection *Sec : OutputSections) {
- uint8_t *SecBuf = Buf + Sec->getFileOff();
+ uint8_t *buf = buffer->getBufferStart();
+ for (OutputSection *sec : outputSections) {
+ uint8_t *secBuf = buf + sec->getFileOff();
// Fill gaps between functions in .text with INT3 instructions
// instead of leaving as NUL bytes (which can be interpreted as
// ADD instructions).
- if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE)
- memset(SecBuf, 0xCC, Sec->getRawSize());
- parallelForEach(Sec->Chunks, [&](Chunk *C) {
- C->writeTo(SecBuf + C->getRVA() - Sec->getRVA());
+ if (sec->header.Characteristics & IMAGE_SCN_CNT_CODE)
+ memset(secBuf, 0xCC, sec->getRawSize());
+ parallelForEach(sec->chunks, [&](Chunk *c) {
+ c->writeTo(secBuf + c->getRVA() - sec->getRVA());
});
}
}
// 2) In all cases, the PE COFF file header also contains a timestamp.
// For reproducibility, instead of a timestamp we want to use a hash of the
// PE contents.
- if (Config->Debug) {
- assert(BuildId && "BuildId is not set!");
+ if (config->debug) {
+ assert(buildId && "BuildId is not set!");
// BuildId->BuildId was filled in when the PDB was written.
}
// "timestamp" in the COFF file header, and the ones in the coff debug
// directory. Now we can hash the file and write that hash to the various
// timestamp fields in the file.
- StringRef OutputFileData(
- reinterpret_cast<const char *>(Buffer->getBufferStart()),
- Buffer->getBufferSize());
+ StringRef outputFileData(
+ reinterpret_cast<const char *>(buffer->getBufferStart()),
+ buffer->getBufferSize());
- uint32_t Timestamp = Config->Timestamp;
- uint64_t Hash = 0;
- bool GenerateSyntheticBuildId =
- Config->MinGW && Config->Debug && Config->PDBPath.empty();
+ uint32_t timestamp = config->timestamp;
+ uint64_t hash = 0;
+ bool generateSyntheticBuildId =
+ config->mingw && config->debug && config->pdbPath.empty();
- if (Config->Repro || GenerateSyntheticBuildId)
- Hash = xxHash64(OutputFileData);
+ if (config->repro || generateSyntheticBuildId)
+ hash = xxHash64(outputFileData);
- if (Config->Repro)
- Timestamp = static_cast<uint32_t>(Hash);
+ if (config->repro)
+ timestamp = static_cast<uint32_t>(hash);
- if (GenerateSyntheticBuildId) {
+ if (generateSyntheticBuildId) {
// For MinGW builds without a PDB file, we still generate a build id
// to allow associating a crash dump to the executable.
- BuildId->BuildId->PDB70.CVSignature = OMF::Signature::PDB70;
- BuildId->BuildId->PDB70.Age = 1;
- memcpy(BuildId->BuildId->PDB70.Signature, &Hash, 8);
+ buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70;
+ buildId->buildId->PDB70.Age = 1;
+ memcpy(buildId->buildId->PDB70.Signature, &hash, 8);
// xxhash only gives us 8 bytes, so put some fixed data in the other half.
- memcpy(&BuildId->BuildId->PDB70.Signature[8], "LLD PDB.", 8);
+ memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8);
}
- if (DebugDirectory)
- DebugDirectory->setTimeDateStamp(Timestamp);
+ if (debugDirectory)
+ debugDirectory->setTimeDateStamp(timestamp);
- uint8_t *Buf = Buffer->getBufferStart();
- Buf += DOSStubSize + sizeof(PEMagic);
- object::coff_file_header *CoffHeader =
- reinterpret_cast<coff_file_header *>(Buf);
- CoffHeader->TimeDateStamp = Timestamp;
+ uint8_t *buf = buffer->getBufferStart();
+ buf += dosStubSize + sizeof(PEMagic);
+ object::coff_file_header *coffHeader =
+ reinterpret_cast<coff_file_header *>(buf);
+ coffHeader->TimeDateStamp = timestamp;
}
// Sort .pdata section contents according to PE/COFF spec 5.5.
void Writer::sortExceptionTable() {
- if (!FirstPdata)
+ if (!firstPdata)
return;
// We assume .pdata contains function table entries only.
- auto BufAddr = [&](Chunk *C) {
- OutputSection *OS = C->getOutputSection();
- return Buffer->getBufferStart() + OS->getFileOff() + C->getRVA() -
- OS->getRVA();
+ auto bufAddr = [&](Chunk *c) {
+ OutputSection *os = c->getOutputSection();
+ return buffer->getBufferStart() + os->getFileOff() + c->getRVA() -
+ os->getRVA();
};
- uint8_t *Begin = BufAddr(FirstPdata);
- uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize();
- if (Config->Machine == AMD64) {
- struct Entry { ulittle32_t Begin, End, Unwind; };
+ uint8_t *begin = bufAddr(firstPdata);
+ uint8_t *end = bufAddr(lastPdata) + lastPdata->getSize();
+ if (config->machine == AMD64) {
+ struct Entry { ulittle32_t begin, end, unwind; };
parallelSort(
- MutableArrayRef<Entry>((Entry *)Begin, (Entry *)End),
- [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ MutableArrayRef<Entry>((Entry *)begin, (Entry *)end),
+ [](const Entry &a, const Entry &b) { return a.begin < b.begin; });
return;
}
- if (Config->Machine == ARMNT || Config->Machine == ARM64) {
- struct Entry { ulittle32_t Begin, Unwind; };
+ if (config->machine == ARMNT || config->machine == ARM64) {
+ struct Entry { ulittle32_t begin, unwind; };
parallelSort(
- MutableArrayRef<Entry>((Entry *)Begin, (Entry *)End),
- [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ MutableArrayRef<Entry>((Entry *)begin, (Entry *)end),
+ [](const Entry &a, const Entry &b) { return a.begin < b.begin; });
return;
}
errs() << "warning: don't know how to handle .pdata.\n";
// pointers in the order that they are listed in the object file (top to
// bottom), otherwise global objects might not be initialized in the
// correct order.
-void Writer::sortCRTSectionChunks(std::vector<Chunk *> &Chunks) {
- auto SectionChunkOrder = [](const Chunk *A, const Chunk *B) {
- auto SA = dyn_cast<SectionChunk>(A);
- auto SB = dyn_cast<SectionChunk>(B);
- assert(SA && SB && "Non-section chunks in CRT section!");
+void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) {
+ auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) {
+ auto sa = dyn_cast<SectionChunk>(a);
+ auto sb = dyn_cast<SectionChunk>(b);
+ assert(sa && sb && "Non-section chunks in CRT section!");
- StringRef SAObj = SA->File->MB.getBufferIdentifier();
- StringRef SBObj = SB->File->MB.getBufferIdentifier();
+ StringRef sAObj = sa->file->mb.getBufferIdentifier();
+ StringRef sBObj = sb->file->mb.getBufferIdentifier();
- return SAObj == SBObj && SA->getSectionNumber() < SB->getSectionNumber();
+ return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber();
};
- llvm::stable_sort(Chunks, SectionChunkOrder);
+ llvm::stable_sort(chunks, sectionChunkOrder);
- if (Config->Verbose) {
- for (auto &C : Chunks) {
- auto SC = dyn_cast<SectionChunk>(C);
- log(" " + SC->File->MB.getBufferIdentifier().str() +
- ", SectionID: " + Twine(SC->getSectionNumber()));
+ if (config->verbose) {
+ for (auto &c : chunks) {
+ auto sc = dyn_cast<SectionChunk>(c);
+ log(" " + sc->file->mb.getBufferIdentifier().str() +
+ ", SectionID: " + Twine(sc->getSectionNumber()));
}
}
}
-OutputSection *Writer::findSection(StringRef Name) {
- for (OutputSection *Sec : OutputSections)
- if (Sec->Name == Name)
- return Sec;
+OutputSection *Writer::findSection(StringRef name) {
+ for (OutputSection *sec : outputSections)
+ if (sec->name == name)
+ return sec;
return nullptr;
}
uint32_t Writer::getSizeOfInitializedData() {
- uint32_t Res = 0;
- for (OutputSection *S : OutputSections)
- if (S->Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
- Res += S->getRawSize();
- return Res;
+ uint32_t res = 0;
+ for (OutputSection *s : outputSections)
+ if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
+ res += s->getRawSize();
+ return res;
}
// Add base relocations to .reloc section.
void Writer::addBaserels() {
- if (!Config->Relocatable)
+ if (!config->relocatable)
return;
- RelocSec->Chunks.clear();
- std::vector<Baserel> V;
- for (OutputSection *Sec : OutputSections) {
- if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ relocSec->chunks.clear();
+ std::vector<Baserel> v;
+ for (OutputSection *sec : outputSections) {
+ if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
continue;
// Collect all locations for base relocations.
- for (Chunk *C : Sec->Chunks)
- C->getBaserels(&V);
+ for (Chunk *c : sec->chunks)
+ c->getBaserels(&v);
// Add the addresses to .reloc section.
- if (!V.empty())
- addBaserelBlocks(V);
- V.clear();
+ if (!v.empty())
+ addBaserelBlocks(v);
+ v.clear();
}
}
// Add addresses to .reloc section. Note that addresses are grouped by page.
-void Writer::addBaserelBlocks(std::vector<Baserel> &V) {
- const uint32_t Mask = ~uint32_t(PageSize - 1);
- uint32_t Page = V[0].RVA & Mask;
- size_t I = 0, J = 1;
- for (size_t E = V.size(); J < E; ++J) {
- uint32_t P = V[J].RVA & Mask;
- if (P == Page)
+void Writer::addBaserelBlocks(std::vector<Baserel> &v) {
+ const uint32_t mask = ~uint32_t(pageSize - 1);
+ uint32_t page = v[0].rva & mask;
+ size_t i = 0, j = 1;
+ for (size_t e = v.size(); j < e; ++j) {
+ uint32_t p = v[j].rva & mask;
+ if (p == page)
continue;
- RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
- I = J;
- Page = P;
+ relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j));
+ i = j;
+ page = p;
}
- if (I == J)
+ if (i == j)
return;
- RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J));
+ relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j));
}
-PartialSection *Writer::createPartialSection(StringRef Name,
- uint32_t OutChars) {
- PartialSection *&PSec = PartialSections[{Name, OutChars}];
- if (PSec)
- return PSec;
- PSec = make<PartialSection>(Name, OutChars);
- return PSec;
+PartialSection *Writer::createPartialSection(StringRef name,
+ uint32_t outChars) {
+ PartialSection *&pSec = partialSections[{name, outChars}];
+ if (pSec)
+ return pSec;
+ pSec = make<PartialSection>(name, outChars);
+ return pSec;
}
-PartialSection *Writer::findPartialSection(StringRef Name, uint32_t OutChars) {
- auto It = PartialSections.find({Name, OutChars});
- if (It != PartialSections.end())
- return It->second;
+PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {
+ auto it = partialSections.find({name, outChars});
+ if (it != partialSections.end())
+ return it->second;
return nullptr;
}
namespace lld {
namespace coff {
-static const int PageSize = 4096;
+static const int pageSize = 4096;
void writeResult();
class PartialSection {
public:
- PartialSection(StringRef N, uint32_t Chars)
- : Name(N), Characteristics(Chars) {}
- StringRef Name;
- unsigned Characteristics;
- std::vector<Chunk *> Chunks;
+ PartialSection(StringRef n, uint32_t chars)
+ : name(n), characteristics(chars) {}
+ StringRef name;
+ unsigned characteristics;
+ std::vector<Chunk *> chunks;
};
// OutputSection represents a section in an output file. It's a
// non-overlapping file offsets and RVAs.
class OutputSection {
public:
- OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) {
- Header.Characteristics = Chars;
+ OutputSection(llvm::StringRef n, uint32_t chars) : name(n) {
+ header.Characteristics = chars;
}
- void addChunk(Chunk *C);
- void insertChunkAtStart(Chunk *C);
- void merge(OutputSection *Other);
- void setPermissions(uint32_t C);
- uint64_t getRVA() { return Header.VirtualAddress; }
- uint64_t getFileOff() { return Header.PointerToRawData; }
- void writeHeaderTo(uint8_t *Buf);
- void addContributingPartialSection(PartialSection *Sec);
+ void addChunk(Chunk *c);
+ void insertChunkAtStart(Chunk *c);
+ void merge(OutputSection *other);
+ void setPermissions(uint32_t c);
+ uint64_t getRVA() { return header.VirtualAddress; }
+ uint64_t getFileOff() { return header.PointerToRawData; }
+ void writeHeaderTo(uint8_t *buf);
+ void addContributingPartialSection(PartialSection *sec);
// Returns the size of this section in an executable memory image.
// This may be smaller than the raw size (the raw size is multiple
// of disk sector size, so there may be padding at end), or may be
// larger (if that's the case, the loader reserves spaces after end
// of raw data).
- uint64_t getVirtualSize() { return Header.VirtualSize; }
+ uint64_t getVirtualSize() { return header.VirtualSize; }
// Returns the size of the section in the output file.
- uint64_t getRawSize() { return Header.SizeOfRawData; }
+ uint64_t getRawSize() { return header.SizeOfRawData; }
// Set offset into the string table storing this section name.
// Used only when the name is longer than 8 bytes.
- void setStringTableOff(uint32_t V) { StringTableOff = V; }
+ void setStringTableOff(uint32_t v) { stringTableOff = v; }
// N.B. The section index is one based.
- uint32_t SectionIndex = 0;
+ uint32_t sectionIndex = 0;
- llvm::StringRef Name;
- llvm::object::coff_section Header = {};
+ llvm::StringRef name;
+ llvm::object::coff_section header = {};
- std::vector<Chunk *> Chunks;
- std::vector<Chunk *> OrigChunks;
+ std::vector<Chunk *> chunks;
+ std::vector<Chunk *> origChunks;
- std::vector<PartialSection *> ContribSections;
+ std::vector<PartialSection *> contribSections;
private:
- uint32_t StringTableOff = 0;
+ uint32_t stringTableOff = 0;
};
} // namespace coff
// TODO(sbc): Remove this once CGOptLevel can be set completely based on bitcode
// function metadata.
-CodeGenOpt::Level lld::args::getCGOptLevel(int OptLevelLTO) {
- if (OptLevelLTO == 3)
+CodeGenOpt::Level lld::args::getCGOptLevel(int optLevelLTO) {
+ if (optLevelLTO == 3)
return CodeGenOpt::Aggressive;
- assert(OptLevelLTO < 3);
+ assert(optLevelLTO < 3);
return CodeGenOpt::Default;
}
-int64_t lld::args::getInteger(opt::InputArgList &Args, unsigned Key,
+int64_t lld::args::getInteger(opt::InputArgList &args, unsigned key,
int64_t Default) {
- auto *A = Args.getLastArg(Key);
- if (!A)
+ auto *a = args.getLastArg(key);
+ if (!a)
return Default;
- int64_t V;
- if (to_integer(A->getValue(), V, 10))
- return V;
+ int64_t v;
+ if (to_integer(a->getValue(), v, 10))
+ return v;
- StringRef Spelling = Args.getArgString(A->getIndex());
- error(Spelling + ": number expected, but got '" + A->getValue() + "'");
+ StringRef spelling = args.getArgString(a->getIndex());
+ error(spelling + ": number expected, but got '" + a->getValue() + "'");
return 0;
}
-std::vector<StringRef> lld::args::getStrings(opt::InputArgList &Args, int Id) {
- std::vector<StringRef> V;
- for (auto *Arg : Args.filtered(Id))
- V.push_back(Arg->getValue());
- return V;
+std::vector<StringRef> lld::args::getStrings(opt::InputArgList &args, int id) {
+ std::vector<StringRef> v;
+ for (auto *arg : args.filtered(id))
+ v.push_back(arg->getValue());
+ return v;
}
-uint64_t lld::args::getZOptionValue(opt::InputArgList &Args, int Id,
- StringRef Key, uint64_t Default) {
- for (auto *Arg : Args.filtered_reverse(Id)) {
- std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('=');
- if (KV.first == Key) {
- uint64_t Result = Default;
- if (!to_integer(KV.second, Result))
- error("invalid " + Key + ": " + KV.second);
- return Result;
+uint64_t lld::args::getZOptionValue(opt::InputArgList &args, int id,
+ StringRef key, uint64_t Default) {
+ for (auto *arg : args.filtered_reverse(id)) {
+ std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('=');
+ if (kv.first == key) {
+ uint64_t result = Default;
+ if (!to_integer(kv.second, result))
+ error("invalid " + key + ": " + kv.second);
+ return result;
}
}
return Default;
}
-std::vector<StringRef> lld::args::getLines(MemoryBufferRef MB) {
- SmallVector<StringRef, 0> Arr;
- MB.getBuffer().split(Arr, '\n');
+std::vector<StringRef> lld::args::getLines(MemoryBufferRef mb) {
+ SmallVector<StringRef, 0> arr;
+ mb.getBuffer().split(arr, '\n');
- std::vector<StringRef> Ret;
- for (StringRef S : Arr) {
- S = S.trim();
- if (!S.empty() && S[0] != '#')
- Ret.push_back(S);
+ std::vector<StringRef> ret;
+ for (StringRef s : arr) {
+ s = s.trim();
+ if (!s.empty() && s[0] != '#')
+ ret.push_back(s);
}
- return Ret;
+ return ret;
}
-StringRef lld::args::getFilenameWithoutExe(StringRef Path) {
- if (Path.endswith_lower(".exe"))
- return sys::path::stem(Path);
- return sys::path::filename(Path);
+StringRef lld::args::getFilenameWithoutExe(StringRef path) {
+ if (path.endswith_lower(".exe"))
+ return sys::path::stem(path);
+ return sys::path::filename(path);
}
// The functions defined in this file can be called from multiple threads,
// but outs() or errs() are not thread-safe. We protect them using a mutex.
-static std::mutex Mu;
+static std::mutex mu;
// Prints "\n" or does nothing, depending on Msg contents of
// the previous call of this function.
-static void newline(raw_ostream *ErrorOS, const Twine &Msg) {
+static void newline(raw_ostream *errorOS, const Twine &msg) {
// True if the previous error message contained "\n".
// We want to separate multi-line error messages with a newline.
- static bool Flag;
+ static bool flag;
- if (Flag)
- *ErrorOS << "\n";
- Flag = StringRef(Msg.str()).contains('\n');
+ if (flag)
+ *errorOS << "\n";
+ flag = StringRef(msg.str()).contains('\n');
}
ErrorHandler &lld::errorHandler() {
- static ErrorHandler Handler;
- return Handler;
+ static ErrorHandler handler;
+ return handler;
}
-void lld::exitLld(int Val) {
+void lld::exitLld(int val) {
// Delete any temporary file, while keeping the memory mapping open.
- if (errorHandler().OutputBuffer)
- errorHandler().OutputBuffer->discard();
+ if (errorHandler().outputBuffer)
+ errorHandler().outputBuffer->discard();
// Dealloc/destroy ManagedStatic variables before calling
// _exit(). In a non-LTO build, this is a nop. In an LTO
outs().flush();
errs().flush();
- _exit(Val);
+ _exit(val);
}
-void lld::diagnosticHandler(const DiagnosticInfo &DI) {
- SmallString<128> S;
- raw_svector_ostream OS(S);
- DiagnosticPrinterRawOStream DP(OS);
- DI.print(DP);
- switch (DI.getSeverity()) {
+void lld::diagnosticHandler(const DiagnosticInfo &di) {
+ SmallString<128> s;
+ raw_svector_ostream os(s);
+ DiagnosticPrinterRawOStream dp(os);
+ di.print(dp);
+ switch (di.getSeverity()) {
case DS_Error:
- error(S);
+ error(s);
break;
case DS_Warning:
- warn(S);
+ warn(s);
break;
case DS_Remark:
case DS_Note:
- message(S);
+ message(s);
break;
}
}
-void lld::checkError(Error E) {
- handleAllErrors(std::move(E),
- [&](ErrorInfoBase &EIB) { error(EIB.message()); });
+void lld::checkError(Error e) {
+ handleAllErrors(std::move(e),
+ [&](ErrorInfoBase &eib) { error(eib.message()); });
}
-void ErrorHandler::print(StringRef S, raw_ostream::Colors C) {
- *ErrorOS << LogName << ": ";
- if (ColorDiagnostics) {
- ErrorOS->changeColor(C, true);
- *ErrorOS << S;
- ErrorOS->resetColor();
+void ErrorHandler::print(StringRef s, raw_ostream::Colors c) {
+ *errorOS << logName << ": ";
+ if (colorDiagnostics) {
+ errorOS->changeColor(c, true);
+ *errorOS << s;
+ errorOS->resetColor();
} else {
- *ErrorOS << S;
+ *errorOS << s;
}
}
-void ErrorHandler::log(const Twine &Msg) {
- if (Verbose) {
- std::lock_guard<std::mutex> Lock(Mu);
- *ErrorOS << LogName << ": " << Msg << "\n";
+void ErrorHandler::log(const Twine &msg) {
+ if (verbose) {
+ std::lock_guard<std::mutex> lock(mu);
+ *errorOS << logName << ": " << msg << "\n";
}
}
-void ErrorHandler::message(const Twine &Msg) {
- std::lock_guard<std::mutex> Lock(Mu);
- outs() << Msg << "\n";
+void ErrorHandler::message(const Twine &msg) {
+ std::lock_guard<std::mutex> lock(mu);
+ outs() << msg << "\n";
outs().flush();
}
-void ErrorHandler::warn(const Twine &Msg) {
- if (FatalWarnings) {
- error(Msg);
+void ErrorHandler::warn(const Twine &msg) {
+ if (fatalWarnings) {
+ error(msg);
return;
}
- std::lock_guard<std::mutex> Lock(Mu);
- newline(ErrorOS, Msg);
+ std::lock_guard<std::mutex> lock(mu);
+ newline(errorOS, msg);
print("warning: ", raw_ostream::MAGENTA);
- *ErrorOS << Msg << "\n";
+ *errorOS << msg << "\n";
}
-void ErrorHandler::error(const Twine &Msg) {
- std::lock_guard<std::mutex> Lock(Mu);
- newline(ErrorOS, Msg);
+void ErrorHandler::error(const Twine &msg) {
+ std::lock_guard<std::mutex> lock(mu);
+ newline(errorOS, msg);
- if (ErrorLimit == 0 || ErrorCount < ErrorLimit) {
+ if (errorLimit == 0 || errorCount < errorLimit) {
print("error: ", raw_ostream::RED);
- *ErrorOS << Msg << "\n";
- } else if (ErrorCount == ErrorLimit) {
+ *errorOS << msg << "\n";
+ } else if (errorCount == errorLimit) {
print("error: ", raw_ostream::RED);
- *ErrorOS << ErrorLimitExceededMsg << "\n";
- if (ExitEarly)
+ *errorOS << errorLimitExceededMsg << "\n";
+ if (exitEarly)
exitLld(1);
}
- ++ErrorCount;
+ ++errorCount;
}
-void ErrorHandler::fatal(const Twine &Msg) {
- error(Msg);
+void ErrorHandler::fatal(const Twine &msg) {
+ error(msg);
exitLld(1);
}
//
// This function spawns a background thread to remove the file.
// The calling thread returns almost immediately.
-void lld::unlinkAsync(StringRef Path) {
+void lld::unlinkAsync(StringRef path) {
// Removing a file is async on windows.
#if defined(_WIN32)
sys::fs::remove(Path);
#else
- if (!ThreadsEnabled || !sys::fs::exists(Path) ||
- !sys::fs::is_regular_file(Path))
+ if (!threadsEnabled || !sys::fs::exists(path) ||
+ !sys::fs::is_regular_file(path))
return;
// We cannot just remove path from a different thread because we are now going
// to create path as a new file.
// Instead we open the file and unlink it on this thread. The unlink is fast
// since the open fd guarantees that it is not removing the last reference.
- int FD;
- std::error_code EC = sys::fs::openFileForRead(Path, FD);
- sys::fs::remove(Path);
+ int fd;
+ std::error_code ec = sys::fs::openFileForRead(path, fd);
+ sys::fs::remove(path);
- if (EC)
+ if (ec)
return;
// close and therefore remove TempPath in background.
- std::mutex M;
- std::condition_variable CV;
- bool Started = false;
- std::thread([&, FD] {
+ std::mutex m;
+ std::condition_variable cv;
+ bool started = false;
+ std::thread([&, fd] {
{
- std::lock_guard<std::mutex> L(M);
- Started = true;
- CV.notify_all();
+ std::lock_guard<std::mutex> l(m);
+ started = true;
+ cv.notify_all();
}
- ::close(FD);
+ ::close(fd);
}).detach();
// GLIBC 2.26 and earlier have race condition that crashes an entire process
// if the main thread calls exit(2) while other thread is starting up.
- std::unique_lock<std::mutex> L(M);
- CV.wait(L, [&] { return Started; });
+ std::unique_lock<std::mutex> l(m);
+ cv.wait(l, [&] { return started; });
#endif
}
// FileOutputBuffer doesn't touch a desitnation file until commit()
// is called. We use that class without calling commit() to predict
// if the given file is writable.
-std::error_code lld::tryCreateFile(StringRef Path) {
- if (Path.empty())
+std::error_code lld::tryCreateFile(StringRef path) {
+ if (path.empty())
return std::error_code();
- if (Path == "-")
+ if (path == "-")
return std::error_code();
- return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError());
+ return errorToErrorCode(FileOutputBuffer::create(path, 1).takeError());
}
using namespace llvm;
using namespace lld;
-BumpPtrAllocator lld::BAlloc;
-StringSaver lld::Saver{BAlloc};
-std::vector<SpecificAllocBase *> lld::SpecificAllocBase::Instances;
+BumpPtrAllocator lld::bAlloc;
+StringSaver lld::saver{bAlloc};
+std::vector<SpecificAllocBase *> lld::SpecificAllocBase::instances;
void lld::freeArena() {
- for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances)
- Alloc->reset();
- BAlloc.Reset();
+ for (SpecificAllocBase *alloc : SpecificAllocBase::instances)
+ alloc->reset();
+ bAlloc.Reset();
}
// assuming that the current directory is "/home/john/bar".
// Returned string is a forward slash separated path even on Windows to avoid
// a mess with backslash-as-escape and backslash-as-path-separator.
-std::string lld::relativeToRoot(StringRef Path) {
- SmallString<128> Abs = Path;
- if (fs::make_absolute(Abs))
- return Path;
- path::remove_dots(Abs, /*remove_dot_dot=*/true);
+std::string lld::relativeToRoot(StringRef path) {
+ SmallString<128> abs = path;
+ if (fs::make_absolute(abs))
+ return path;
+ path::remove_dots(abs, /*remove_dot_dot=*/true);
// This is Windows specific. root_name() returns a drive letter
// (e.g. "c:") or a UNC name (//net). We want to keep it as part
// of the result.
- SmallString<128> Res;
- StringRef Root = path::root_name(Abs);
- if (Root.endswith(":"))
- Res = Root.drop_back();
- else if (Root.startswith("//"))
- Res = Root.substr(2);
+ SmallString<128> res;
+ StringRef root = path::root_name(abs);
+ if (root.endswith(":"))
+ res = root.drop_back();
+ else if (root.startswith("//"))
+ res = root.substr(2);
- path::append(Res, path::relative_path(Abs));
- return path::convert_to_slash(Res);
+ path::append(res, path::relative_path(abs));
+ return path::convert_to_slash(res);
}
// Quote a given string if it contains a space character.
-std::string lld::quote(StringRef S) {
- if (S.contains(' '))
- return ("\"" + S + "\"").str();
- return S;
+std::string lld::quote(StringRef s) {
+ if (s.contains(' '))
+ return ("\"" + s + "\"").str();
+ return s;
}
// Converts an Arg to a string representation suitable for a response file.
// To show an Arg in a diagnostic, use Arg::getAsString() instead.
-std::string lld::toString(const opt::Arg &Arg) {
- std::string K = Arg.getSpelling();
- if (Arg.getNumValues() == 0)
- return K;
- std::string V = quote(Arg.getValue());
- if (Arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
- return K + V;
- return K + " " + V;
+std::string lld::toString(const opt::Arg &arg) {
+ std::string k = arg.getSpelling();
+ if (arg.getNumValues() == 0)
+ return k;
+ std::string v = quote(arg.getValue());
+ if (arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
+ return k + v;
+ return k + " " + v;
}
using namespace lld;
// Returns the demangled C++ symbol name for Name.
-Optional<std::string> lld::demangleItanium(StringRef Name) {
+Optional<std::string> lld::demangleItanium(StringRef name) {
// itaniumDemangle can be used to demangle strings other than symbol
// names which do not necessarily start with "_Z". Name can be
// either a C or C++ symbol. Don't call itaniumDemangle if the name
// does not look like a C++ symbol name to avoid getting unexpected
// result for a C symbol that happens to match a mangled type name.
- if (!Name.startswith("_Z"))
+ if (!name.startswith("_Z"))
return None;
- char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
- if (!Buf)
+ char *buf = itaniumDemangle(name.str().c_str(), nullptr, nullptr, nullptr);
+ if (!buf)
return None;
- std::string S(Buf);
- free(Buf);
- return S;
+ std::string s(buf);
+ free(buf);
+ return s;
}
-Optional<std::string> lld::demangleMSVC(StringRef Name) {
- std::string Prefix;
- if (Name.consume_front("__imp_"))
- Prefix = "__declspec(dllimport) ";
+Optional<std::string> lld::demangleMSVC(StringRef name) {
+ std::string prefix;
+ if (name.consume_front("__imp_"))
+ prefix = "__declspec(dllimport) ";
// Demangle only C++ names.
- if (!Name.startswith("?"))
+ if (!name.startswith("?"))
return None;
- char *Buf = microsoftDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
- if (!Buf)
+ char *buf = microsoftDemangle(name.str().c_str(), nullptr, nullptr, nullptr);
+ if (!buf)
return None;
- std::string S(Buf);
- free(Buf);
- return Prefix + S;
+ std::string s(buf);
+ free(buf);
+ return prefix + s;
}
-StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
- for (StringRef S : Pat) {
- Expected<GlobPattern> Pat = GlobPattern::create(S);
- if (!Pat)
- error(toString(Pat.takeError()));
+StringMatcher::StringMatcher(ArrayRef<StringRef> pat) {
+ for (StringRef s : pat) {
+ Expected<GlobPattern> pat = GlobPattern::create(s);
+ if (!pat)
+ error(toString(pat.takeError()));
else
- Patterns.push_back(*Pat);
+ patterns.push_back(*pat);
}
}
-bool StringMatcher::match(StringRef S) const {
- for (const GlobPattern &Pat : Patterns)
- if (Pat.match(S))
+bool StringMatcher::match(StringRef s) const {
+ for (const GlobPattern &pat : patterns)
+ if (pat.match(s))
return true;
return false;
}
// Converts a hex string (e.g. "deadbeef") to a vector.
-std::vector<uint8_t> lld::parseHex(StringRef S) {
- std::vector<uint8_t> Hex;
- while (!S.empty()) {
- StringRef B = S.substr(0, 2);
- S = S.substr(2);
- uint8_t H;
- if (!to_integer(B, H, 16)) {
- error("not a hexadecimal value: " + B);
+std::vector<uint8_t> lld::parseHex(StringRef s) {
+ std::vector<uint8_t> hex;
+ while (!s.empty()) {
+ StringRef b = s.substr(0, 2);
+ s = s.substr(2);
+ uint8_t h;
+ if (!to_integer(b, h, 16)) {
+ error("not a hexadecimal value: " + b);
return {};
}
- Hex.push_back(H);
+ hex.push_back(h);
}
- return Hex;
+ return hex;
}
// Returns true if S is valid as a C language identifier.
-bool lld::isValidCIdentifier(StringRef S) {
- return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
- std::all_of(S.begin() + 1, S.end(),
- [](char C) { return C == '_' || isAlnum(C); });
+bool lld::isValidCIdentifier(StringRef s) {
+ return !s.empty() && (isAlpha(s[0]) || s[0] == '_') &&
+ std::all_of(s.begin() + 1, s.end(),
+ [](char c) { return c == '_' || isAlnum(c); });
}
// Write the contents of the a buffer to a file
-void lld::saveBuffer(StringRef Buffer, const Twine &Path) {
- std::error_code EC;
- raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
- if (EC)
- error("cannot create " + Path + ": " + EC.message());
- OS << Buffer;
+void lld::saveBuffer(StringRef buffer, const Twine &path) {
+ std::error_code ec;
+ raw_fd_ostream os(path.str(), ec, sys::fs::OpenFlags::F_None);
+ if (ec)
+ error("cannot create " + path + ": " + ec.message());
+ os << buffer;
}
#include "lld/Common/Threads.h"
-bool lld::ThreadsEnabled = true;
+bool lld::threadsEnabled = true;
using namespace lld;
using namespace llvm;
-ScopedTimer::ScopedTimer(Timer &T) : T(&T) { T.start(); }
+ScopedTimer::ScopedTimer(Timer &t) : t(&t) { t.start(); }
void ScopedTimer::stop() {
- if (!T)
+ if (!t)
return;
- T->stop();
- T = nullptr;
+ t->stop();
+ t = nullptr;
}
ScopedTimer::~ScopedTimer() { stop(); }
-Timer::Timer(llvm::StringRef Name) : Name(Name), Parent(nullptr) {}
-Timer::Timer(llvm::StringRef Name, Timer &Parent)
- : Name(Name), Parent(&Parent) {}
+Timer::Timer(llvm::StringRef name) : name(name), parent(nullptr) {}
+Timer::Timer(llvm::StringRef name, Timer &parent)
+ : name(name), parent(&parent) {}
void Timer::start() {
- if (Parent && Total.count() == 0)
- Parent->Children.push_back(this);
- StartTime = std::chrono::high_resolution_clock::now();
+ if (parent && total.count() == 0)
+ parent->children.push_back(this);
+ startTime = std::chrono::high_resolution_clock::now();
}
void Timer::stop() {
- Total += (std::chrono::high_resolution_clock::now() - StartTime);
+ total += (std::chrono::high_resolution_clock::now() - startTime);
}
Timer &Timer::root() {
- static Timer RootTimer("Total Link Time");
- return RootTimer;
+ static Timer rootTimer("Total Link Time");
+ return rootTimer;
}
void Timer::print() {
- double TotalDuration = static_cast<double>(root().millis());
+ double totalDuration = static_cast<double>(root().millis());
// We want to print the grand total under all the intermediate phases, so we
// print all children first, then print the total under that.
- for (const auto &Child : Children)
- Child->print(1, TotalDuration);
+ for (const auto &child : children)
+ child->print(1, totalDuration);
message(std::string(49, '-'));
double Timer::millis() const {
return std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(
- Total)
+ total)
.count();
}
-void Timer::print(int Depth, double TotalDuration, bool Recurse) const {
- double P = 100.0 * millis() / TotalDuration;
+void Timer::print(int depth, double totalDuration, bool recurse) const {
+ double p = 100.0 * millis() / totalDuration;
- SmallString<32> Str;
- llvm::raw_svector_ostream Stream(Str);
- std::string S = std::string(Depth * 2, ' ') + Name + std::string(":");
- Stream << format("%-30s%5d ms (%5.1f%%)", S.c_str(), (int)millis(), P);
+ SmallString<32> str;
+ llvm::raw_svector_ostream stream(str);
+ std::string s = std::string(depth * 2, ' ') + name + std::string(":");
+ stream << format("%-30s%5d ms (%5.1f%%)", s.c_str(), (int)millis(), p);
- message(Str);
+ message(str);
- if (Recurse) {
- for (const auto &Child : Children)
- Child->print(Depth + 1, TotalDuration);
+ if (recurse) {
+ for (const auto &child : children)
+ child->print(depth + 1, totalDuration);
}
}
patchee(p), patcheeOffset(off) {
this->parent = p->getParent();
patchSym = addSyntheticLocal(
- Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0,
+ saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0,
getSize(), *this);
- addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, *this);
+ addSyntheticLocal(saver.save("$x"), STT_NOTYPE, 0, 0, *this);
}
uint64_t lld::elf::Patch843419Section::getLDSTAddr() const {
void AArch64Err843419Patcher::insertPatches(
InputSectionDescription &isd, std::vector<Patch843419Section *> &patches) {
uint64_t isecLimit;
- uint64_t prevISLimit = isd.sections.front()->outSecOff;
- uint64_t patchUpperBound = prevISLimit + target->getThunkSectionSpacing();
+ uint64_t prevIsecLimit = isd.sections.front()->outSecOff;
+ uint64_t patchUpperBound = prevIsecLimit + target->getThunkSectionSpacing();
uint64_t outSecAddr = isd.sections.front()->getParent()->addr;
// Set the OutSecOff of patches to the place where we want to insert them.
isecLimit = isec->outSecOff + isec->getSize();
if (isecLimit > patchUpperBound) {
while (patchIt != patchEnd) {
- if ((*patchIt)->getLDSTAddr() - outSecAddr >= prevISLimit)
+ if ((*patchIt)->getLDSTAddr() - outSecAddr >= prevIsecLimit)
break;
- (*patchIt)->outSecOff = prevISLimit;
+ (*patchIt)->outSecOff = prevIsecLimit;
++patchIt;
}
- patchUpperBound = prevISLimit + target->getThunkSectionSpacing();
+ patchUpperBound = prevIsecLimit + target->getThunkSectionSpacing();
}
- prevISLimit = isecLimit;
+ prevIsecLimit = isecLimit;
}
for (; patchIt != patchEnd; ++patchIt) {
(*patchIt)->outSecOff = isecLimit;
bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
raw_ostream &error) {
- errorHandler().LogName = args::getFilenameWithoutExe(args[0]);
- errorHandler().ErrorLimitExceededMsg =
+ errorHandler().logName = args::getFilenameWithoutExe(args[0]);
+ errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
- errorHandler().ErrorOS = &error;
- errorHandler().ExitEarly = canExitEarly;
- errorHandler().ColorDiagnostics = error.has_colors();
+ errorHandler().errorOS = &error;
+ errorHandler().exitEarly = canExitEarly;
+ errorHandler().colorDiagnostics = error.has_colors();
inputSections.clear();
outputSections.clear();
opt::InputArgList args = parser.parse(argsArr.slice(1));
// Interpret this flag early because error() depends on them.
- errorHandler().ErrorLimit = args::getInteger(args, OPT_error_limit, 20);
+ errorHandler().errorLimit = args::getInteger(args, OPT_error_limit, 20);
checkZOptions(args);
// Handle -help
// Initializes Config members by the command line options.
static void readConfigs(opt::InputArgList &args) {
- errorHandler().Verbose = args.hasArg(OPT_verbose);
- errorHandler().FatalWarnings =
+ errorHandler().verbose = args.hasArg(OPT_verbose);
+ errorHandler().fatalWarnings =
args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
- ThreadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true);
+ threadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true);
config->allowMultipleDefinition =
args.hasFlag(OPT_allow_multiple_definition,
// Parse LTO options.
if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq))
- parseClangOption(Saver.save("-mcpu=" + StringRef(arg->getValue())),
+ parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())),
arg->getSpelling());
for (auto *arg : args.filtered(OPT_plugin_opt))
if (!sym)
continue;
- Symbol *real = addUndefined(Saver.save("__real_" + name));
- Symbol *wrap = addUndefined(Saver.save("__wrap_" + name));
+ Symbol *real = addUndefined(saver.save("__real_" + name));
+ Symbol *wrap = addUndefined(saver.save("__wrap_" + name));
v.push_back({sym, real, wrap});
// We want to tell LTO not to inline symbols to be overwritten
if (!arg)
return;
if (arg->getOption().getID() == OPT_color_diagnostics) {
- errorHandler().ColorDiagnostics = true;
+ errorHandler().colorDiagnostics = true;
} else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
- errorHandler().ColorDiagnostics = false;
+ errorHandler().colorDiagnostics = false;
} else {
StringRef s = arg->getValue();
if (s == "always")
- errorHandler().ColorDiagnostics = true;
+ errorHandler().colorDiagnostics = true;
else if (s == "never")
- errorHandler().ColorDiagnostics = false;
+ errorHandler().colorDiagnostics = false;
else if (s != "auto")
error("unknown option: --color-diagnostics=" + s);
}
for (size_t i = 0, e = args.size(); i != e; ++i) {
StringRef s = args[i];
if ((s == "-plugin-opt" || s == "--plugin-opt") && i + 1 != e) {
- v.push_back(Saver.save(s + "=" + args[i + 1]).data());
+ v.push_back(saver.save(s + "=" + args[i + 1]).data());
++i;
} else {
v.push_back(args[i]);
// Expand response files (arguments in the form of @<filename>)
// and then parse the argument again.
- cl::ExpandResponseFiles(Saver, getQuotingStyle(args), vec);
+ cl::ExpandResponseFiles(saver, getQuotingStyle(args), vec);
concatLTOPluginOptions(vec);
args = this->ParseArgs(vec, missingIndex, missingCount);
void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> fn) {
// If threading is disabled or the number of sections are
// too small to use threading, call Fn sequentially.
- if (!ThreadsEnabled || sections.size() < 1024) {
+ if (!threadsEnabled || sections.size() < 1024) {
forEachClassRange(0, sections.size(), fn);
++cnt;
return;
// The --chroot option changes our virtual root directory.
// This is useful when you are dealing with files created by --reproduce.
if (!config->chroot.empty() && path.startswith("/"))
- path = Saver.save(config->chroot + path);
+ path = saver.save(config->chroot + path);
log(path);
reinterpret_cast<const Elf_Verdef *>(verdefs[idx])->getAux()->vda_name;
versionedNameBuffer.clear();
name = (name + "@" + verName).toStringRef(versionedNameBuffer);
- symtab->addSymbol(SharedSymbol{*this, Saver.save(name), sym.getBinding(),
+ symtab->addSymbol(SharedSymbol{*this, saver.save(name), sym.getBinding(),
sym.st_other, sym.getType(), sym.st_value,
sym.st_size, alignment, idx});
}
// symbols later in the link stage). So we append file offset to make
// filename unique.
StringRef name = archiveName.empty()
- ? Saver.save(path)
- : Saver.save(archiveName + "(" + path + " at " +
+ ? saver.save(path)
+ : saver.save(archiveName + "(" + path + " at " +
utostr(offsetInArchive) + ")");
MemoryBufferRef mbref(mb.getBuffer(), name);
static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,
const lto::InputFile::Symbol &objSym,
BitcodeFile &f) {
- StringRef name = Saver.save(objSym.getName());
+ StringRef name = saver.save(objSym.getName());
uint8_t binding = objSym.isWeak() ? STB_WEAK : STB_GLOBAL;
uint8_t type = objSym.isTLS() ? STT_TLS : STT_NOTYPE;
uint8_t visibility = mapVisibility(objSym.getVisibility());
if (!isAlnum(s[i]))
s[i] = '_';
- symtab->addSymbol(Defined{nullptr, Saver.save(s + "_start"), STB_GLOBAL,
+ symtab->addSymbol(Defined{nullptr, saver.save(s + "_start"), STB_GLOBAL,
STV_DEFAULT, STT_OBJECT, 0, 0, section});
- symtab->addSymbol(Defined{nullptr, Saver.save(s + "_end"), STB_GLOBAL,
+ symtab->addSymbol(Defined{nullptr, saver.save(s + "_end"), STB_GLOBAL,
STV_DEFAULT, STT_OBJECT, data.size(), 0, section});
- symtab->addSymbol(Defined{nullptr, Saver.save(s + "_size"), STB_GLOBAL,
+ symtab->addSymbol(Defined{nullptr, saver.save(s + "_size"), STB_GLOBAL,
STV_DEFAULT, STT_OBJECT, data.size(), 0, nullptr});
}
for (const lto::InputFile::Symbol &sym : obj->symbols()) {
if (sym.isUndefined())
continue;
- symtab->addSymbol(LazyObject{*this, Saver.save(sym.getName())});
+ symtab->addSymbol(LazyObject{*this, saver.save(sym.getName())});
}
return;
}
{
static std::mutex mu;
std::lock_guard<std::mutex> lock(mu);
- uncompressedBuf = BAlloc.Allocate<char>(size);
+ uncompressedBuf = bAlloc.Allocate<char>(size);
}
if (Error e = zlib::uncompress(toStringRef(rawData), uncompressedBuf, size))
// Restore the original section name.
// (e.g. ".zdebug_info" -> ".debug_info")
- name = Saver.save("." + name.substr(2));
+ name = saver.save("." + name.substr(2));
return;
}
if (isReserved(sec) || script->shouldKeep(sec)) {
enqueue(sec, 0);
} else if (isValidCIdentifier(sec->name)) {
- cNamedSections[Saver.save("__start_" + sec->name)].push_back(sec);
- cNamedSections[Saver.save("__stop_" + sec->name)].push_back(sec);
+ cNamedSections[saver.save("__start_" + sec->name)].push_back(sec);
+ cNamedSections[saver.save("__stop_" + sec->name)].push_back(sec);
}
}
lastThunkLowerBound = isdEnd - thunkSectionSpacing;
uint32_t isecLimit;
- uint32_t prevISLimit = isdBegin;
+ uint32_t prevIsecLimit = isdBegin;
uint32_t thunkUpperBound = isdBegin + thunkSectionSpacing;
for (const InputSection *isec : isd->sections) {
isecLimit = isec->outSecOff + isec->getSize();
if (isecLimit > thunkUpperBound) {
- addThunkSection(os, isd, prevISLimit);
- thunkUpperBound = prevISLimit + thunkSectionSpacing;
+ addThunkSection(os, isd, prevIsecLimit);
+ thunkUpperBound = prevIsecLimit + thunkSectionSpacing;
}
if (isecLimit > lastThunkLowerBound)
break;
- prevISLimit = isecLimit;
+ prevIsecLimit = isecLimit;
}
addThunkSection(os, isd, isecLimit);
});
SmallString<128> pathData;
StringRef path = (config->sysroot + s).toStringRef(pathData);
if (sys::fs::exists(path)) {
- driver->addFile(Saver.save(path), /*WithLOption=*/false);
+ driver->addFile(saver.save(path), /*WithLOption=*/false);
return;
}
}
if (config->sysroot.empty())
driver->addFile(s.substr(1), /*WithLOption=*/false);
else
- driver->addFile(Saver.save(config->sysroot + "/" + s.substr(1)),
+ driver->addFile(saver.save(config->sysroot + "/" + s.substr(1)),
/*WithLOption=*/false);
} else if (s.startswith("-l")) {
driver->addLibrary(s.substr(2));
driver->addFile(s, /*WithLOption=*/false);
} else {
if (Optional<std::string> path = findFromSearchPaths(s))
- driver->addFile(Saver.save(*path), /*WithLOption=*/true);
+ driver->addFile(saver.save(*path), /*WithLOption=*/true);
else
setError("unable to find " + s);
}
// This is only for testing.
StringRef s = getenv("LLD_VERSION");
if (s.empty())
- s = Saver.save(Twine("Linker: ") + getLLDVersion());
+ s = saver.save(Twine("Linker: ") + getLLDVersion());
// +1 to include the terminating '\0'.
return {(const uint8_t *)s.data(), s.size() + 1};
InputSection *elf::createInterpSection() {
// StringSaver guarantees that the returned string ends with '\0'.
- StringRef s = Saver.save(config->dynamicLinker);
+ StringRef s = saver.save(config->dynamicLinker);
ArrayRef<uint8_t> contents = {(const uint8_t *)s.data(), s.size() + 1};
auto *sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents,
// speed it up.
size_t numShards = 32;
size_t concurrency = 1;
- if (ThreadsEnabled)
+ if (threadsEnabled)
concurrency =
std::min<size_t>(PowerOf2Floor(hardware_concurrency()), numShards);
// Concurrency level. Must be a power of 2 to avoid expensive modulo
// operations in the following tight loop.
size_t concurrency = 1;
- if (ThreadsEnabled)
+ if (threadsEnabled)
concurrency =
std::min<size_t>(PowerOf2Floor(hardware_concurrency()), numShards);
}
void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__AArch64AbsLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__AArch64AbsLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$x", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 8, isec);
}
void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC,
+ addSymbol(saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC,
0, isec);
addSymbol("$x", STT_NOTYPE, 0, isec);
}
}
void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
}
}
void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
}
}
void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC,
+ addSymbol(saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC,
0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
}
}
void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__ThumbV7PILongThunk_" + destination.getName()),
+ addSymbol(saver.save("__ThumbV7PILongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
}
}
void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__ARMv5ABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__ARMv5ABSLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 4, isec);
}
void ARMV5PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC,
+ addSymbol(saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC,
0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 12, isec);
}
void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 8, isec);
}
void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
+ addSymbol(saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 12, isec);
}
void MipsThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
isec);
}
void MicroMipsThunk::addSymbols(ThunkSection &isec) {
Defined *d = addSymbol(
- Saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
+ saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
d->stOther |= STO_MIPS_MICROMIPS;
}
void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
Defined *d = addSymbol(
- Saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
+ saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
d->stOther |= STO_MIPS_MICROMIPS;
}
else
os << ".plt_pic32.";
os << destination.getName();
- addSymbol(Saver.save(os.str()), STT_FUNC, 0, isec);
+ addSymbol(saver.save(os.str()), STT_FUNC, 0, isec);
}
bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
}
void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
- Defined *s = addSymbol(Saver.save("__plt_" + destination.getName()), STT_FUNC,
+ Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC,
0, isec);
s->needsTocRestore = true;
}
}
void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
- addSymbol(Saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0,
isec);
}
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
- Writer() : buffer(errorHandler().OutputBuffer) {}
+ Writer() : buffer(errorHandler().outputBuffer) {}
using Elf_Shdr = typename ELFT::Shdr;
using Elf_Ehdr = typename ELFT::Ehdr;
using Elf_Phdr = typename ELFT::Phdr;
if (InputSectionBase *rel = isec->getRelocatedSection()) {
OutputSection *out = rel->getOutputSection();
if (s->type == SHT_RELA)
- return Saver.save(".rela" + out->name);
- return Saver.save(".rel" + out->name);
+ return saver.save(".rela" + out->name);
+ return saver.save(".rel" + out->name);
}
}
StringRef s = sec->name;
if (!isValidCIdentifier(s))
return;
- addOptionalRegular(Saver.save("__start_" + s), sec, 0, STV_PROTECTED);
- addOptionalRegular(Saver.save("__stop_" + s), sec, -1, STV_PROTECTED);
+ addOptionalRegular(saver.save("__start_" + s), sec, 0, STV_PROTECTED);
+ addOptionalRegular(saver.save("__stop_" + s), sec, -1, STV_PROTECTED);
}
static bool needsPtLoad(OutputSection *sec) {
#undef PREFIX
// Create table mapping all options defined in Options.td
-static const opt::OptTable::Info InfoTable[] = {
+static const opt::OptTable::Info infoTable[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
{X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
namespace {
class MinGWOptTable : public opt::OptTable {
public:
- MinGWOptTable() : OptTable(InfoTable, false) {}
- opt::InputArgList parse(ArrayRef<const char *> Argv);
+ MinGWOptTable() : OptTable(infoTable, false) {}
+ opt::InputArgList parse(ArrayRef<const char *> argv);
};
} // namespace
-static void printHelp(const char *Argv0) {
+static void printHelp(const char *argv0) {
MinGWOptTable().PrintHelp(
- outs(), (std::string(Argv0) + " [options] file...").c_str(), "lld",
+ outs(), (std::string(argv0) + " [options] file...").c_str(), "lld",
false /*ShowHidden*/, true /*ShowAllAliases*/);
outs() << "\n";
}
return cl::TokenizeGNUCommandLine;
}
-opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> Argv) {
- unsigned MissingIndex;
- unsigned MissingCount;
+opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> argv) {
+ unsigned missingIndex;
+ unsigned missingCount;
- SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
- cl::ExpandResponseFiles(Saver, getQuotingStyle(), Vec);
- opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+ SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
+ cl::ExpandResponseFiles(saver, getQuotingStyle(), vec);
+ opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount);
- if (MissingCount)
- fatal(StringRef(Args.getArgString(MissingIndex)) + ": missing argument");
- for (auto *Arg : Args.filtered(OPT_UNKNOWN))
- fatal("unknown argument: " + Arg->getAsString(Args));
- return Args;
+ if (missingCount)
+ fatal(StringRef(args.getArgString(missingIndex)) + ": missing argument");
+ for (auto *arg : args.filtered(OPT_UNKNOWN))
+ fatal("unknown argument: " + arg->getAsString(args));
+ return args;
}
// Find a file by concatenating given paths.
-static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
- SmallString<128> S;
- sys::path::append(S, Path1, Path2);
- if (sys::fs::exists(S))
- return S.str().str();
+static Optional<std::string> findFile(StringRef path1, const Twine &path2) {
+ SmallString<128> s;
+ sys::path::append(s, path1, path2);
+ if (sys::fs::exists(s))
+ return s.str().str();
return None;
}
// This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths.
static std::string
-searchLibrary(StringRef Name, ArrayRef<StringRef> SearchPaths, bool BStatic) {
- if (Name.startswith(":")) {
- for (StringRef Dir : SearchPaths)
- if (Optional<std::string> S = findFile(Dir, Name.substr(1)))
- return *S;
- fatal("unable to find library -l" + Name);
+searchLibrary(StringRef name, ArrayRef<StringRef> searchPaths, bool bStatic) {
+ if (name.startswith(":")) {
+ for (StringRef dir : searchPaths)
+ if (Optional<std::string> s = findFile(dir, name.substr(1)))
+ return *s;
+ fatal("unable to find library -l" + name);
}
- for (StringRef Dir : SearchPaths) {
- if (!BStatic)
- if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".dll.a"))
- return *S;
- if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
- return *S;
+ for (StringRef dir : searchPaths) {
+ if (!bStatic)
+ if (Optional<std::string> s = findFile(dir, "lib" + name + ".dll.a"))
+ return *s;
+ if (Optional<std::string> s = findFile(dir, "lib" + name + ".a"))
+ return *s;
}
- fatal("unable to find library -l" + Name);
+ fatal("unable to find library -l" + name);
}
// Convert Unix-ish command line arguments to Windows-ish ones and
// then call coff::link.
-bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) {
- MinGWOptTable Parser;
- opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
+bool mingw::link(ArrayRef<const char *> argsArr, raw_ostream &diag) {
+ MinGWOptTable parser;
+ opt::InputArgList args = parser.parse(argsArr.slice(1));
- if (Args.hasArg(OPT_help)) {
- printHelp(ArgsArr[0]);
+ if (args.hasArg(OPT_help)) {
+ printHelp(argsArr[0]);
return true;
}
// still the newest version in March 2017) or earlier to recognize LLD as
// a GNU compatible linker. As long as an output for the -v option
// contains "GNU" or "with BFD", they recognize us as GNU-compatible.
- if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
+ if (args.hasArg(OPT_v) || args.hasArg(OPT_version))
message(getLLDVersion() + " (compatible with GNU linkers)");
// The behavior of -v or --version is a bit strange, but this is
// needed for compatibility with GNU linkers.
- if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT) && !Args.hasArg(OPT_l))
+ if (args.hasArg(OPT_v) && !args.hasArg(OPT_INPUT) && !args.hasArg(OPT_l))
return true;
- if (Args.hasArg(OPT_version))
+ if (args.hasArg(OPT_version))
return true;
- if (!Args.hasArg(OPT_INPUT) && !Args.hasArg(OPT_l))
+ if (!args.hasArg(OPT_INPUT) && !args.hasArg(OPT_l))
fatal("no input files");
- std::vector<std::string> LinkArgs;
- auto Add = [&](const Twine &S) { LinkArgs.push_back(S.str()); };
+ std::vector<std::string> linkArgs;
+ auto add = [&](const Twine &s) { linkArgs.push_back(s.str()); };
- Add("lld-link");
- Add("-lldmingw");
+ add("lld-link");
+ add("-lldmingw");
- if (auto *A = Args.getLastArg(OPT_entry)) {
- StringRef S = A->getValue();
- if (Args.getLastArgValue(OPT_m) == "i386pe" && S.startswith("_"))
- Add("-entry:" + S.substr(1));
+ if (auto *a = args.getLastArg(OPT_entry)) {
+ StringRef s = a->getValue();
+ if (args.getLastArgValue(OPT_m) == "i386pe" && s.startswith("_"))
+ add("-entry:" + s.substr(1));
else
- Add("-entry:" + S);
+ add("-entry:" + s);
}
- if (Args.hasArg(OPT_major_os_version, OPT_minor_os_version,
+ if (args.hasArg(OPT_major_os_version, OPT_minor_os_version,
OPT_major_subsystem_version, OPT_minor_subsystem_version)) {
- auto *MajOSVer = Args.getLastArg(OPT_major_os_version);
- auto *MinOSVer = Args.getLastArg(OPT_minor_os_version);
- auto *MajSubSysVer = Args.getLastArg(OPT_major_subsystem_version);
- auto *MinSubSysVer = Args.getLastArg(OPT_minor_subsystem_version);
- if (MajOSVer && MajSubSysVer &&
- StringRef(MajOSVer->getValue()) != StringRef(MajSubSysVer->getValue()))
+ auto *majOSVer = args.getLastArg(OPT_major_os_version);
+ auto *minOSVer = args.getLastArg(OPT_minor_os_version);
+ auto *majSubSysVer = args.getLastArg(OPT_major_subsystem_version);
+ auto *minSubSysVer = args.getLastArg(OPT_minor_subsystem_version);
+ if (majOSVer && majSubSysVer &&
+ StringRef(majOSVer->getValue()) != StringRef(majSubSysVer->getValue()))
warn("--major-os-version and --major-subsystem-version set to differing "
"versions, not supported");
- if (MinOSVer && MinSubSysVer &&
- StringRef(MinOSVer->getValue()) != StringRef(MinSubSysVer->getValue()))
+ if (minOSVer && minSubSysVer &&
+ StringRef(minOSVer->getValue()) != StringRef(minSubSysVer->getValue()))
warn("--minor-os-version and --minor-subsystem-version set to differing "
"versions, not supported");
- StringRef SubSys = Args.getLastArgValue(OPT_subs, "default");
- StringRef Major = MajOSVer ? MajOSVer->getValue()
- : MajSubSysVer ? MajSubSysVer->getValue() : "6";
- StringRef Minor = MinOSVer ? MinOSVer->getValue()
- : MinSubSysVer ? MinSubSysVer->getValue() : "";
- StringRef Sep = Minor.empty() ? "" : ".";
- Add("-subsystem:" + SubSys + "," + Major + Sep + Minor);
- } else if (auto *A = Args.getLastArg(OPT_subs)) {
- Add("-subsystem:" + StringRef(A->getValue()));
+ StringRef subSys = args.getLastArgValue(OPT_subs, "default");
+ StringRef major = majOSVer ? majOSVer->getValue()
+ : majSubSysVer ? majSubSysVer->getValue() : "6";
+ StringRef minor = minOSVer ? minOSVer->getValue()
+ : minSubSysVer ? minSubSysVer->getValue() : "";
+ StringRef sep = minor.empty() ? "" : ".";
+ add("-subsystem:" + subSys + "," + major + sep + minor);
+ } else if (auto *a = args.getLastArg(OPT_subs)) {
+ add("-subsystem:" + StringRef(a->getValue()));
}
- if (auto *A = Args.getLastArg(OPT_out_implib))
- Add("-implib:" + StringRef(A->getValue()));
- if (auto *A = Args.getLastArg(OPT_stack))
- Add("-stack:" + StringRef(A->getValue()));
- if (auto *A = Args.getLastArg(OPT_output_def))
- Add("-output-def:" + StringRef(A->getValue()));
- if (auto *A = Args.getLastArg(OPT_image_base))
- Add("-base:" + StringRef(A->getValue()));
- if (auto *A = Args.getLastArg(OPT_map))
- Add("-lldmap:" + StringRef(A->getValue()));
-
- if (auto *A = Args.getLastArg(OPT_o))
- Add("-out:" + StringRef(A->getValue()));
- else if (Args.hasArg(OPT_shared))
- Add("-out:a.dll");
+ if (auto *a = args.getLastArg(OPT_out_implib))
+ add("-implib:" + StringRef(a->getValue()));
+ if (auto *a = args.getLastArg(OPT_stack))
+ add("-stack:" + StringRef(a->getValue()));
+ if (auto *a = args.getLastArg(OPT_output_def))
+ add("-output-def:" + StringRef(a->getValue()));
+ if (auto *a = args.getLastArg(OPT_image_base))
+ add("-base:" + StringRef(a->getValue()));
+ if (auto *a = args.getLastArg(OPT_map))
+ add("-lldmap:" + StringRef(a->getValue()));
+
+ if (auto *a = args.getLastArg(OPT_o))
+ add("-out:" + StringRef(a->getValue()));
+ else if (args.hasArg(OPT_shared))
+ add("-out:a.dll");
else
- Add("-out:a.exe");
-
- if (auto *A = Args.getLastArg(OPT_pdb)) {
- Add("-debug");
- StringRef V = A->getValue();
- if (!V.empty())
- Add("-pdb:" + V);
- } else if (Args.hasArg(OPT_strip_debug)) {
- Add("-debug:symtab");
- } else if (!Args.hasArg(OPT_strip_all)) {
- Add("-debug:dwarf");
+ add("-out:a.exe");
+
+ if (auto *a = args.getLastArg(OPT_pdb)) {
+ add("-debug");
+ StringRef v = a->getValue();
+ if (!v.empty())
+ add("-pdb:" + v);
+ } else if (args.hasArg(OPT_strip_debug)) {
+ add("-debug:symtab");
+ } else if (!args.hasArg(OPT_strip_all)) {
+ add("-debug:dwarf");
}
- if (Args.hasArg(OPT_shared))
- Add("-dll");
- if (Args.hasArg(OPT_verbose))
- Add("-verbose");
- if (Args.hasArg(OPT_exclude_all_symbols))
- Add("-exclude-all-symbols");
- if (Args.hasArg(OPT_export_all_symbols))
- Add("-export-all-symbols");
- if (Args.hasArg(OPT_large_address_aware))
- Add("-largeaddressaware");
- if (Args.hasArg(OPT_kill_at))
- Add("-kill-at");
- if (Args.hasArg(OPT_appcontainer))
- Add("-appcontainer");
-
- if (Args.getLastArgValue(OPT_m) != "thumb2pe" &&
- Args.getLastArgValue(OPT_m) != "arm64pe" && !Args.hasArg(OPT_dynamicbase))
- Add("-dynamicbase:no");
-
- if (Args.hasFlag(OPT_no_insert_timestamp, OPT_insert_timestamp, false))
- Add("-timestamp:0");
-
- if (Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false))
- Add("-opt:ref");
+ if (args.hasArg(OPT_shared))
+ add("-dll");
+ if (args.hasArg(OPT_verbose))
+ add("-verbose");
+ if (args.hasArg(OPT_exclude_all_symbols))
+ add("-exclude-all-symbols");
+ if (args.hasArg(OPT_export_all_symbols))
+ add("-export-all-symbols");
+ if (args.hasArg(OPT_large_address_aware))
+ add("-largeaddressaware");
+ if (args.hasArg(OPT_kill_at))
+ add("-kill-at");
+ if (args.hasArg(OPT_appcontainer))
+ add("-appcontainer");
+
+ if (args.getLastArgValue(OPT_m) != "thumb2pe" &&
+ args.getLastArgValue(OPT_m) != "arm64pe" && !args.hasArg(OPT_dynamicbase))
+ add("-dynamicbase:no");
+
+ if (args.hasFlag(OPT_no_insert_timestamp, OPT_insert_timestamp, false))
+ add("-timestamp:0");
+
+ if (args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false))
+ add("-opt:ref");
else
- Add("-opt:noref");
-
- if (auto *A = Args.getLastArg(OPT_icf)) {
- StringRef S = A->getValue();
- if (S == "all")
- Add("-opt:icf");
- else if (S == "safe" || S == "none")
- Add("-opt:noicf");
+ add("-opt:noref");
+
+ if (auto *a = args.getLastArg(OPT_icf)) {
+ StringRef s = a->getValue();
+ if (s == "all")
+ add("-opt:icf");
+ else if (s == "safe" || s == "none")
+ add("-opt:noicf");
else
- fatal("unknown parameter: --icf=" + S);
+ fatal("unknown parameter: --icf=" + s);
} else {
- Add("-opt:noicf");
+ add("-opt:noicf");
}
- if (auto *A = Args.getLastArg(OPT_m)) {
- StringRef S = A->getValue();
- if (S == "i386pe")
- Add("-machine:x86");
- else if (S == "i386pep")
- Add("-machine:x64");
- else if (S == "thumb2pe")
- Add("-machine:arm");
- else if (S == "arm64pe")
- Add("-machine:arm64");
+ if (auto *a = args.getLastArg(OPT_m)) {
+ StringRef s = a->getValue();
+ if (s == "i386pe")
+ add("-machine:x86");
+ else if (s == "i386pep")
+ add("-machine:x64");
+ else if (s == "thumb2pe")
+ add("-machine:arm");
+ else if (s == "arm64pe")
+ add("-machine:arm64");
else
- fatal("unknown parameter: -m" + S);
+ fatal("unknown parameter: -m" + s);
}
- for (auto *A : Args.filtered(OPT_mllvm))
- Add("-mllvm:" + StringRef(A->getValue()));
+ for (auto *a : args.filtered(OPT_mllvm))
+ add("-mllvm:" + StringRef(a->getValue()));
- for (auto *A : Args.filtered(OPT_Xlink))
- Add(A->getValue());
+ for (auto *a : args.filtered(OPT_Xlink))
+ add(a->getValue());
- if (Args.getLastArgValue(OPT_m) == "i386pe")
- Add("-alternatename:__image_base__=___ImageBase");
+ if (args.getLastArgValue(OPT_m) == "i386pe")
+ add("-alternatename:__image_base__=___ImageBase");
else
- Add("-alternatename:__image_base__=__ImageBase");
+ add("-alternatename:__image_base__=__ImageBase");
- for (auto *A : Args.filtered(OPT_require_defined))
- Add("-include:" + StringRef(A->getValue()));
- for (auto *A : Args.filtered(OPT_undefined))
- Add("-includeoptional:" + StringRef(A->getValue()));
+ for (auto *a : args.filtered(OPT_require_defined))
+ add("-include:" + StringRef(a->getValue()));
+ for (auto *a : args.filtered(OPT_undefined))
+ add("-includeoptional:" + StringRef(a->getValue()));
- std::vector<StringRef> SearchPaths;
- for (auto *A : Args.filtered(OPT_L)) {
- SearchPaths.push_back(A->getValue());
- Add("-libpath:" + StringRef(A->getValue()));
+ std::vector<StringRef> searchPaths;
+ for (auto *a : args.filtered(OPT_L)) {
+ searchPaths.push_back(a->getValue());
+ add("-libpath:" + StringRef(a->getValue()));
}
- StringRef Prefix = "";
- bool Static = false;
- for (auto *A : Args) {
- switch (A->getOption().getID()) {
+ StringRef prefix = "";
+ bool isStatic = false;
+ for (auto *a : args) {
+ switch (a->getOption().getID()) {
case OPT_INPUT:
- if (StringRef(A->getValue()).endswith_lower(".def"))
- Add("-def:" + StringRef(A->getValue()));
+ if (StringRef(a->getValue()).endswith_lower(".def"))
+ add("-def:" + StringRef(a->getValue()));
else
- Add(Prefix + StringRef(A->getValue()));
+ add(prefix + StringRef(a->getValue()));
break;
case OPT_l:
- Add(Prefix + searchLibrary(A->getValue(), SearchPaths, Static));
+ add(prefix + searchLibrary(a->getValue(), searchPaths, isStatic));
break;
case OPT_whole_archive:
- Prefix = "-wholearchive:";
+ prefix = "-wholearchive:";
break;
case OPT_no_whole_archive:
- Prefix = "";
+ prefix = "";
break;
case OPT_Bstatic:
- Static = true;
+ isStatic = true;
break;
case OPT_Bdynamic:
- Static = false;
+ isStatic = false;
break;
}
}
- if (Args.hasArg(OPT_verbose) || Args.hasArg(OPT__HASH_HASH_HASH))
- outs() << llvm::join(LinkArgs, " ") << "\n";
+ if (args.hasArg(OPT_verbose) || args.hasArg(OPT__HASH_HASH_HASH))
+ outs() << llvm::join(linkArgs, " ") << "\n";
- if (Args.hasArg(OPT__HASH_HASH_HASH))
+ if (args.hasArg(OPT__HASH_HASH_HASH))
return true;
// Repack vector of strings to vector of const char pointers for coff::link.
- std::vector<const char *> Vec;
- for (const std::string &S : LinkArgs)
- Vec.push_back(S.c_str());
- return coff::link(Vec, true);
+ std::vector<const char *> vec;
+ for (const std::string &s : linkArgs)
+ vec.push_back(s.c_str());
+ return coff::link(vec, true);
}
namespace lld {
namespace args {
-llvm::CodeGenOpt::Level getCGOptLevel(int OptLevelLTO);
+llvm::CodeGenOpt::Level getCGOptLevel(int optLevelLTO);
-int64_t getInteger(llvm::opt::InputArgList &Args, unsigned Key,
+int64_t getInteger(llvm::opt::InputArgList &args, unsigned key,
int64_t Default);
-std::vector<StringRef> getStrings(llvm::opt::InputArgList &Args, int Id);
+std::vector<StringRef> getStrings(llvm::opt::InputArgList &args, int id);
-uint64_t getZOptionValue(llvm::opt::InputArgList &Args, int Id, StringRef Key,
+uint64_t getZOptionValue(llvm::opt::InputArgList &args, int id, StringRef key,
uint64_t Default);
-std::vector<StringRef> getLines(MemoryBufferRef MB);
+std::vector<StringRef> getLines(MemoryBufferRef mb);
-StringRef getFilenameWithoutExe(StringRef Path);
+StringRef getFilenameWithoutExe(StringRef path);
} // namespace args
} // namespace lld
namespace lld {
namespace coff {
-bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
- llvm::raw_ostream &Diag = llvm::errs());
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &diag = llvm::errs());
}
namespace mingw {
-bool link(llvm::ArrayRef<const char *> Args,
- llvm::raw_ostream &Diag = llvm::errs());
+bool link(llvm::ArrayRef<const char *> args,
+ llvm::raw_ostream &diag = llvm::errs());
}
namespace elf {
-bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
- llvm::raw_ostream &Diag = llvm::errs());
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &diag = llvm::errs());
}
namespace mach_o {
-bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
- llvm::raw_ostream &Diag = llvm::errs());
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &diag = llvm::errs());
}
namespace wasm {
-bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
- llvm::raw_ostream &Diag = llvm::errs());
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &diag = llvm::errs());
}
}
class ErrorHandler {
public:
- uint64_t ErrorCount = 0;
- uint64_t ErrorLimit = 20;
- StringRef ErrorLimitExceededMsg = "too many errors emitted, stopping now";
- StringRef LogName = "lld";
- llvm::raw_ostream *ErrorOS = &llvm::errs();
- bool ColorDiagnostics = llvm::errs().has_colors();
- bool ExitEarly = true;
- bool FatalWarnings = false;
- bool Verbose = false;
-
- void error(const Twine &Msg);
- LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
- void log(const Twine &Msg);
- void message(const Twine &Msg);
- void warn(const Twine &Msg);
-
- std::unique_ptr<llvm::FileOutputBuffer> OutputBuffer;
+ uint64_t errorCount = 0;
+ uint64_t errorLimit = 20;
+ StringRef errorLimitExceededMsg = "too many errors emitted, stopping now";
+ StringRef logName = "lld";
+ llvm::raw_ostream *errorOS = &llvm::errs();
+ bool colorDiagnostics = llvm::errs().has_colors();
+ bool exitEarly = true;
+ bool fatalWarnings = false;
+ bool verbose = false;
+
+ void error(const Twine &msg);
+ LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &msg);
+ void log(const Twine &msg);
+ void message(const Twine &msg);
+ void warn(const Twine &msg);
+
+ std::unique_ptr<llvm::FileOutputBuffer> outputBuffer;
private:
- void print(StringRef S, raw_ostream::Colors C);
+ void print(StringRef s, raw_ostream::Colors c);
};
/// Returns the default error handler.
ErrorHandler &errorHandler();
-inline void error(const Twine &Msg) { errorHandler().error(Msg); }
-inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg) {
- errorHandler().fatal(Msg);
+inline void error(const Twine &msg) { errorHandler().error(msg); }
+inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &msg) {
+ errorHandler().fatal(msg);
}
-inline void log(const Twine &Msg) { errorHandler().log(Msg); }
-inline void message(const Twine &Msg) { errorHandler().message(Msg); }
-inline void warn(const Twine &Msg) { errorHandler().warn(Msg); }
-inline uint64_t errorCount() { return errorHandler().ErrorCount; }
+inline void log(const Twine &msg) { errorHandler().log(msg); }
+inline void message(const Twine &msg) { errorHandler().message(msg); }
+inline void warn(const Twine &msg) { errorHandler().warn(msg); }
+inline uint64_t errorCount() { return errorHandler().errorCount; }
-LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
+LLVM_ATTRIBUTE_NORETURN void exitLld(int val);
-void diagnosticHandler(const llvm::DiagnosticInfo &DI);
-void checkError(Error E);
+void diagnosticHandler(const llvm::DiagnosticInfo &di);
+void checkError(Error e);
// check functions are convenient functions to strip errors
// from error-or-value objects.
-template <class T> T check(ErrorOr<T> E) {
- if (auto EC = E.getError())
- fatal(EC.message());
- return std::move(*E);
+template <class T> T check(ErrorOr<T> e) {
+ if (auto ec = e.getError())
+ fatal(ec.message());
+ return std::move(*e);
}
-template <class T> T check(Expected<T> E) {
- if (!E)
- fatal(llvm::toString(E.takeError()));
- return std::move(*E);
+template <class T> T check(Expected<T> e) {
+ if (!e)
+ fatal(llvm::toString(e.takeError()));
+ return std::move(*e);
}
template <class T>
-T check2(ErrorOr<T> E, llvm::function_ref<std::string()> Prefix) {
- if (auto EC = E.getError())
- fatal(Prefix() + ": " + EC.message());
- return std::move(*E);
+T check2(ErrorOr<T> e, llvm::function_ref<std::string()> prefix) {
+ if (auto ec = e.getError())
+ fatal(prefix() + ": " + ec.message());
+ return std::move(*e);
}
template <class T>
-T check2(Expected<T> E, llvm::function_ref<std::string()> Prefix) {
- if (!E)
- fatal(Prefix() + ": " + toString(E.takeError()));
- return std::move(*E);
+T check2(Expected<T> e, llvm::function_ref<std::string()> prefix) {
+ if (!e)
+ fatal(prefix() + ": " + toString(e.takeError()));
+ return std::move(*e);
}
-inline std::string toString(const Twine &S) { return S.str(); }
+inline std::string toString(const Twine &s) { return s.str(); }
// To evaluate the second argument lazily, we use C macro.
#define CHECK(E, S) check2((E), [&] { return toString(S); })
#include <system_error>
namespace lld {
-void unlinkAsync(StringRef Path);
-std::error_code tryCreateFile(StringRef Path);
+void unlinkAsync(StringRef path);
+std::error_code tryCreateFile(StringRef path);
} // namespace lld
#endif
namespace lld {
// Use this arena if your object doesn't have a destructor.
-extern llvm::BumpPtrAllocator BAlloc;
-extern llvm::StringSaver Saver;
+extern llvm::BumpPtrAllocator bAlloc;
+extern llvm::StringSaver saver;
void freeArena();
// These two classes are hack to keep track of all
// SpecificBumpPtrAllocator instances.
struct SpecificAllocBase {
- SpecificAllocBase() { Instances.push_back(this); }
+ SpecificAllocBase() { instances.push_back(this); }
virtual ~SpecificAllocBase() = default;
virtual void reset() = 0;
- static std::vector<SpecificAllocBase *> Instances;
+ static std::vector<SpecificAllocBase *> instances;
};
template <class T> struct SpecificAlloc : public SpecificAllocBase {
- void reset() override { Alloc.DestroyAll(); }
- llvm::SpecificBumpPtrAllocator<T> Alloc;
+ void reset() override { alloc.DestroyAll(); }
+ llvm::SpecificBumpPtrAllocator<T> alloc;
};
// Use this arena if your object has a destructor.
// Your destructor will be invoked from freeArena().
-template <typename T, typename... U> T *make(U &&... Args) {
- static SpecificAlloc<T> Alloc;
- return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...);
+template <typename T, typename... U> T *make(U &&... args) {
+ static SpecificAlloc<T> alloc;
+ return new (alloc.alloc.Allocate()) T(std::forward<U>(args)...);
}
} // namespace lld
// Makes a given pathname an absolute path first, and then remove
// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
// assuming that the current directory is "/home/john/bar".
-std::string relativeToRoot(StringRef Path);
+std::string relativeToRoot(StringRef path);
// Quote a given string if it contains a space character.
-std::string quote(StringRef S);
+std::string quote(StringRef s);
// Returns the string form of the given argument.
-std::string toString(const llvm::opt::Arg &Arg);
+std::string toString(const llvm::opt::Arg &arg);
}
#endif
namespace lld {
// Returns a demangled C++ symbol name. If Name is not a mangled
// name, it returns Optional::None.
-llvm::Optional<std::string> demangleItanium(llvm::StringRef Name);
-llvm::Optional<std::string> demangleMSVC(llvm::StringRef S);
+llvm::Optional<std::string> demangleItanium(llvm::StringRef name);
+llvm::Optional<std::string> demangleMSVC(llvm::StringRef s);
-std::vector<uint8_t> parseHex(llvm::StringRef S);
-bool isValidCIdentifier(llvm::StringRef S);
+std::vector<uint8_t> parseHex(llvm::StringRef s);
+bool isValidCIdentifier(llvm::StringRef s);
// Write the contents of the a buffer to a file
-void saveBuffer(llvm::StringRef Buffer, const llvm::Twine &Path);
+void saveBuffer(llvm::StringRef buffer, const llvm::Twine &path);
// This class represents multiple glob patterns.
class StringMatcher {
public:
StringMatcher() = default;
- explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> Pat);
+ explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> pat);
- bool match(llvm::StringRef S) const;
+ bool match(llvm::StringRef s) const;
private:
- std::vector<llvm::GlobPattern> Patterns;
+ std::vector<llvm::GlobPattern> patterns;
};
} // namespace lld
namespace lld {
-extern bool ThreadsEnabled;
+extern bool threadsEnabled;
-template <typename R, class FuncTy> void parallelForEach(R &&Range, FuncTy Fn) {
- if (ThreadsEnabled)
- for_each(llvm::parallel::par, std::begin(Range), std::end(Range), Fn);
+template <typename R, class FuncTy> void parallelForEach(R &&range, FuncTy fn) {
+ if (threadsEnabled)
+ for_each(llvm::parallel::par, std::begin(range), std::end(range), fn);
else
- for_each(llvm::parallel::seq, std::begin(Range), std::end(Range), Fn);
+ for_each(llvm::parallel::seq, std::begin(range), std::end(range), fn);
}
-inline void parallelForEachN(size_t Begin, size_t End,
- llvm::function_ref<void(size_t)> Fn) {
- if (ThreadsEnabled)
- for_each_n(llvm::parallel::par, Begin, End, Fn);
+inline void parallelForEachN(size_t begin, size_t end,
+ llvm::function_ref<void(size_t)> fn) {
+ if (threadsEnabled)
+ for_each_n(llvm::parallel::par, begin, end, fn);
else
- for_each_n(llvm::parallel::seq, Begin, End, Fn);
+ for_each_n(llvm::parallel::seq, begin, end, fn);
}
-template <typename R, class FuncTy> void parallelSort(R &&Range, FuncTy Fn) {
- if (ThreadsEnabled)
- sort(llvm::parallel::par, std::begin(Range), std::end(Range), Fn);
+template <typename R, class FuncTy> void parallelSort(R &&range, FuncTy fn) {
+ if (threadsEnabled)
+ sort(llvm::parallel::par, std::begin(range), std::end(range), fn);
else
- sort(llvm::parallel::seq, std::begin(Range), std::end(Range), Fn);
+ sort(llvm::parallel::seq, std::begin(range), std::end(range), fn);
}
} // namespace lld
class Timer;
struct ScopedTimer {
- explicit ScopedTimer(Timer &T);
+ explicit ScopedTimer(Timer &t);
~ScopedTimer();
void stop();
- Timer *T = nullptr;
+ Timer *t = nullptr;
};
class Timer {
public:
- Timer(llvm::StringRef Name, Timer &Parent);
+ Timer(llvm::StringRef name, Timer &parent);
static Timer &root();
double millis() const;
private:
- explicit Timer(llvm::StringRef Name);
- void print(int Depth, double TotalDuration, bool Recurse = true) const;
-
- std::chrono::time_point<std::chrono::high_resolution_clock> StartTime;
- std::chrono::nanoseconds Total;
- std::vector<Timer *> Children;
- std::string Name;
- Timer *Parent;
+ explicit Timer(llvm::StringRef name);
+ void print(int depth, double totalDuration, bool recurse = true) const;
+
+ std::chrono::time_point<std::chrono::high_resolution_clock> startTime;
+ std::chrono::nanoseconds total;
+ std::vector<Timer *> children;
+ std::string name;
+ Timer *parent;
};
} // namespace lld
Twine(unknownArg->getAsString(parsedArgs)));
}
- errorHandler().Verbose = parsedArgs.hasArg(OPT_v);
- errorHandler().ErrorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20);
+ errorHandler().verbose = parsedArgs.hasArg(OPT_v);
+ errorHandler().errorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20);
// Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE;
// Now that we've constructed the final set of search paths, print out those
// search paths in verbose mode.
- if (errorHandler().Verbose) {
+ if (errorHandler().verbose) {
message("Library search paths:");
for (auto path : ctx.searchDirs()) {
message(" " + path);
/// This is where the link is actually performed.
bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
raw_ostream &Error) {
- errorHandler().LogName = args::getFilenameWithoutExe(args[0]);
- errorHandler().ErrorLimitExceededMsg =
+ errorHandler().logName = args::getFilenameWithoutExe(args[0]);
+ errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"'-error-limit 0' to see all errors)";
- errorHandler().ErrorOS = &Error;
- errorHandler().ExitEarly = CanExitEarly;
- errorHandler().ColorDiagnostics = Error.has_colors();
+ errorHandler().errorOS = &Error;
+ errorHandler().exitEarly = CanExitEarly;
+ errorHandler().colorDiagnostics = Error.has_colors();
MachOLinkingContext ctx;
if (!parse(args, ctx))
if (auto ec = pm.runOnFile(*merged)) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
- *errorHandler().ErrorOS << "Failed to run passes on file '"
+ *errorHandler().errorOS << "Failed to run passes on file '"
<< ctx.outputPath() << "': ";
- logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
+ logAllUnhandledErrors(std::move(ec), *errorHandler().errorOS,
std::string());
return false;
}
if (auto ec = ctx.writeFile(*merged)) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
- *errorHandler().ErrorOS << "Failed to write file '" << ctx.outputPath()
+ *errorHandler().errorOS << "Failed to write file '" << ctx.outputPath()
<< "': ";
- logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS,
+ logAllUnhandledErrors(std::move(ec), *errorHandler().errorOS,
std::string());
return false;
}
Wasm, // -flavor wasm
};
-LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
- errs() << S << "\n";
+LLVM_ATTRIBUTE_NORETURN static void die(const Twine &s) {
+ errs() << s << "\n";
exit(1);
}
-static Flavor getFlavor(StringRef S) {
- return StringSwitch<Flavor>(S)
+static Flavor getFlavor(StringRef s) {
+ return StringSwitch<Flavor>(s)
.CasesLower("ld", "ld.lld", "gnu", Gnu)
.CasesLower("wasm", "ld-wasm", Wasm)
.CaseLower("link", WinLink)
return cl::TokenizeGNUCommandLine;
}
-static bool isPETargetName(StringRef S) {
- return S == "i386pe" || S == "i386pep" || S == "thumb2pe" || S == "arm64pe";
+static bool isPETargetName(StringRef s) {
+ return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe";
}
-static bool isPETarget(std::vector<const char *> &V) {
- for (auto It = V.begin(); It + 1 != V.end(); ++It) {
- if (StringRef(*It) != "-m")
+static bool isPETarget(std::vector<const char *> &v) {
+ for (auto it = v.begin(); it + 1 != v.end(); ++it) {
+ if (StringRef(*it) != "-m")
continue;
- return isPETargetName(*(It + 1));
+ return isPETargetName(*(it + 1));
}
// Expand response files (arguments in the form of @<filename>)
// to allow detecting the -m argument from arguments in them.
- SmallVector<const char *, 256> ExpandedArgs(V.data(), V.data() + V.size());
- cl::ExpandResponseFiles(Saver, getDefaultQuotingStyle(), ExpandedArgs);
- for (auto It = ExpandedArgs.begin(); It + 1 != ExpandedArgs.end(); ++It) {
- if (StringRef(*It) != "-m")
+ SmallVector<const char *, 256> expandedArgs(v.data(), v.data() + v.size());
+ cl::ExpandResponseFiles(saver, getDefaultQuotingStyle(), expandedArgs);
+ for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) {
+ if (StringRef(*it) != "-m")
continue;
- return isPETargetName(*(It + 1));
+ return isPETargetName(*(it + 1));
}
return false;
}
-static Flavor parseProgname(StringRef Progname) {
+static Flavor parseProgname(StringRef progname) {
#if __APPLE__
// Use Darwin driver for "ld" on Darwin.
if (Progname == "ld")
#if LLVM_ON_UNIX
// Use GNU driver for "ld" on other Unix-like system.
- if (Progname == "ld")
+ if (progname == "ld")
return Gnu;
#endif
// Progname may be something like "lld-gnu". Parse it.
- SmallVector<StringRef, 3> V;
- Progname.split(V, "-");
- for (StringRef S : V)
- if (Flavor F = getFlavor(S))
- return F;
+ SmallVector<StringRef, 3> v;
+ progname.split(v, "-");
+ for (StringRef s : v)
+ if (Flavor f = getFlavor(s))
+ return f;
return Invalid;
}
-static Flavor parseFlavor(std::vector<const char *> &V) {
+static Flavor parseFlavor(std::vector<const char *> &v) {
// Parse -flavor option.
- if (V.size() > 1 && V[1] == StringRef("-flavor")) {
- if (V.size() <= 2)
+ if (v.size() > 1 && v[1] == StringRef("-flavor")) {
+ if (v.size() <= 2)
die("missing arg value for '-flavor'");
- Flavor F = getFlavor(V[2]);
- if (F == Invalid)
- die("Unknown flavor: " + StringRef(V[2]));
- V.erase(V.begin() + 1, V.begin() + 3);
- return F;
+ Flavor f = getFlavor(v[2]);
+ if (f == Invalid)
+ die("Unknown flavor: " + StringRef(v[2]));
+ v.erase(v.begin() + 1, v.begin() + 3);
+ return f;
}
// Deduct the flavor from argv[0].
- StringRef Arg0 = path::filename(V[0]);
- if (Arg0.endswith_lower(".exe"))
- Arg0 = Arg0.drop_back(4);
- return parseProgname(Arg0);
+ StringRef arg0 = path::filename(v[0]);
+ if (arg0.endswith_lower(".exe"))
+ arg0 = arg0.drop_back(4);
+ return parseProgname(arg0);
}
// If this function returns true, lld calls _exit() so that it quickly
/// Universal linker main(). This linker emulates the gnu, darwin, or
/// windows linker based on the argv[0] or -flavor option.
-int main(int Argc, const char **Argv) {
- InitLLVM X(Argc, Argv);
+int main(int argc, const char **argv) {
+ InitLLVM x(argc, argv);
- std::vector<const char *> Args(Argv, Argv + Argc);
- switch (parseFlavor(Args)) {
+ std::vector<const char *> args(argv, argv + argc);
+ switch (parseFlavor(args)) {
case Gnu:
- if (isPETarget(Args))
- return !mingw::link(Args);
- return !elf::link(Args, canExitEarly());
+ if (isPETarget(args))
+ return !mingw::link(args);
+ return !elf::link(args, canExitEarly());
case WinLink:
- return !coff::link(Args, canExitEarly());
+ return !coff::link(args, canExitEarly());
case Darwin:
- return !mach_o::link(Args, canExitEarly());
+ return !mach_o::link(args, canExitEarly());
case Wasm:
- return !wasm::link(Args, canExitEarly());
+ return !wasm::link(args, canExitEarly());
default:
die("lld is a generic driver.\n"
"Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"
// and such fields have the same name as the corresponding options.
// Most fields are initialized by the driver.
struct Configuration {
- bool AllowUndefined;
- bool CheckFeatures;
- bool CompressRelocations;
- bool Demangle;
- bool DisableVerify;
- bool EmitRelocs;
- bool ExportAll;
- bool ExportDynamic;
- bool ExportTable;
- bool GcSections;
- bool ImportMemory;
- bool SharedMemory;
- bool PassiveSegments;
- bool ImportTable;
- bool MergeDataSegments;
- bool Pie;
- bool PrintGcSections;
- bool Relocatable;
- bool SaveTemps;
- bool Shared;
- bool StripAll;
- bool StripDebug;
- bool StackFirst;
- bool Trace;
- uint32_t GlobalBase;
- uint32_t InitialMemory;
- uint32_t MaxMemory;
- uint32_t ZStackSize;
- unsigned LTOPartitions;
- unsigned LTOO;
- unsigned Optimize;
- unsigned ThinLTOJobs;
+ bool allowUndefined;
+ bool checkFeatures;
+ bool compressRelocations;
+ bool demangle;
+ bool disableVerify;
+ bool emitRelocs;
+ bool exportAll;
+ bool exportDynamic;
+ bool exportTable;
+ bool gcSections;
+ bool importMemory;
+ bool sharedMemory;
+ bool passiveSegments;
+ bool importTable;
+ bool mergeDataSegments;
+ bool pie;
+ bool printGcSections;
+ bool relocatable;
+ bool saveTemps;
+ bool shared;
+ bool stripAll;
+ bool stripDebug;
+ bool stackFirst;
+ bool trace;
+ uint32_t globalBase;
+ uint32_t initialMemory;
+ uint32_t maxMemory;
+ uint32_t zStackSize;
+ unsigned ltoPartitions;
+ unsigned ltoo;
+ unsigned optimize;
+ unsigned thinLTOJobs;
- llvm::StringRef Entry;
- llvm::StringRef OutputFile;
- llvm::StringRef ThinLTOCacheDir;
+ llvm::StringRef entry;
+ llvm::StringRef outputFile;
+ llvm::StringRef thinLTOCacheDir;
- llvm::StringSet<> AllowUndefinedSymbols;
- llvm::StringSet<> ExportedSymbols;
- std::vector<llvm::StringRef> SearchPaths;
- llvm::CachePruningPolicy ThinLTOCachePolicy;
- llvm::Optional<std::vector<std::string>> Features;
+ llvm::StringSet<> allowUndefinedSymbols;
+ llvm::StringSet<> exportedSymbols;
+ std::vector<llvm::StringRef> searchPaths;
+ llvm::CachePruningPolicy thinLTOCachePolicy;
+ llvm::Optional<std::vector<std::string>> features;
// The following config options do not directly correspond to any
// particualr command line options.
// True if we are creating position-independent code.
- bool Pic;
+ bool isPic;
};
// The only instance of Configuration struct.
-extern Configuration *Config;
+extern Configuration *config;
} // namespace wasm
} // namespace lld
using namespace lld;
using namespace lld::wasm;
-Configuration *lld::wasm::Config;
+Configuration *lld::wasm::config;
namespace {
class LinkerDriver {
public:
- void link(ArrayRef<const char *> ArgsArr);
+ void link(ArrayRef<const char *> argsArr);
private:
- void createFiles(opt::InputArgList &Args);
- void addFile(StringRef Path);
- void addLibrary(StringRef Name);
+ void createFiles(opt::InputArgList &args);
+ void addFile(StringRef path);
+ void addLibrary(StringRef name);
// True if we are in --whole-archive and --no-whole-archive.
- bool InWholeArchive = false;
+ bool inWholeArchive = false;
- std::vector<InputFile *> Files;
+ std::vector<InputFile *> files;
};
} // anonymous namespace
-bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly,
- raw_ostream &Error) {
- errorHandler().LogName = args::getFilenameWithoutExe(Args[0]);
- errorHandler().ErrorOS = &Error;
- errorHandler().ColorDiagnostics = Error.has_colors();
- errorHandler().ErrorLimitExceededMsg =
+bool lld::wasm::link(ArrayRef<const char *> args, bool canExitEarly,
+ raw_ostream &error) {
+ errorHandler().logName = args::getFilenameWithoutExe(args[0]);
+ errorHandler().errorOS = &error;
+ errorHandler().colorDiagnostics = error.has_colors();
+ errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
- Config = make<Configuration>();
- Symtab = make<SymbolTable>();
+ config = make<Configuration>();
+ symtab = make<SymbolTable>();
initLLVM();
- LinkerDriver().link(Args);
+ LinkerDriver().link(args);
// Exit immediately if we don't need to return to the caller.
// This saves time because the overhead of calling destructors
// for all globally-allocated objects is not negligible.
- if (CanExitEarly)
+ if (canExitEarly)
exitLld(errorCount() ? 1 : 0);
freeArena();
#undef PREFIX
// Create table mapping all options defined in Options.td
-static const opt::OptTable::Info OptInfo[] = {
+static const opt::OptTable::Info optInfo[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
{X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \
X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12},
namespace {
class WasmOptTable : public llvm::opt::OptTable {
public:
- WasmOptTable() : OptTable(OptInfo) {}
- opt::InputArgList parse(ArrayRef<const char *> Argv);
+ WasmOptTable() : OptTable(optInfo) {}
+ opt::InputArgList parse(ArrayRef<const char *> argv);
};
} // namespace
// Set color diagnostics according to -color-diagnostics={auto,always,never}
// or -no-color-diagnostics flags.
-static void handleColorDiagnostics(opt::InputArgList &Args) {
- auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+static void handleColorDiagnostics(opt::InputArgList &args) {
+ auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
OPT_no_color_diagnostics);
- if (!Arg)
+ if (!arg)
return;
- if (Arg->getOption().getID() == OPT_color_diagnostics) {
- errorHandler().ColorDiagnostics = true;
- } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) {
- errorHandler().ColorDiagnostics = false;
+ if (arg->getOption().getID() == OPT_color_diagnostics) {
+ errorHandler().colorDiagnostics = true;
+ } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
+ errorHandler().colorDiagnostics = false;
} else {
- StringRef S = Arg->getValue();
- if (S == "always")
- errorHandler().ColorDiagnostics = true;
- else if (S == "never")
- errorHandler().ColorDiagnostics = false;
- else if (S != "auto")
- error("unknown option: --color-diagnostics=" + S);
+ StringRef s = arg->getValue();
+ if (s == "always")
+ errorHandler().colorDiagnostics = true;
+ else if (s == "never")
+ errorHandler().colorDiagnostics = false;
+ else if (s != "auto")
+ error("unknown option: --color-diagnostics=" + s);
}
}
// Find a file by concatenating given paths.
-static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
- SmallString<128> S;
- path::append(S, Path1, Path2);
- if (fs::exists(S))
- return S.str().str();
+static Optional<std::string> findFile(StringRef path1, const Twine &path2) {
+ SmallString<128> s;
+ path::append(s, path1, path2);
+ if (fs::exists(s))
+ return s.str().str();
return None;
}
-opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) {
- SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
+opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> argv) {
+ SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
- unsigned MissingIndex;
- unsigned MissingCount;
+ unsigned missingIndex;
+ unsigned missingCount;
// Expand response files (arguments in the form of @<filename>)
- cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Vec);
+ cl::ExpandResponseFiles(saver, cl::TokenizeGNUCommandLine, vec);
- opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+ opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount);
- handleColorDiagnostics(Args);
- for (auto *Arg : Args.filtered(OPT_UNKNOWN))
- error("unknown argument: " + Arg->getAsString(Args));
- return Args;
+ handleColorDiagnostics(args);
+ for (auto *arg : args.filtered(OPT_UNKNOWN))
+ error("unknown argument: " + arg->getAsString(args));
+ return args;
}
// Currently we allow a ".imports" to live alongside a library. This can
// In the long run this information would be better stored as a symbol
// attribute/flag in the object file itself.
// See: https://github.com/WebAssembly/tool-conventions/issues/35
-static void readImportFile(StringRef Filename) {
- if (Optional<MemoryBufferRef> Buf = readFile(Filename))
- for (StringRef Sym : args::getLines(*Buf))
- Config->AllowUndefinedSymbols.insert(Sym);
+static void readImportFile(StringRef filename) {
+ if (Optional<MemoryBufferRef> buf = readFile(filename))
+ for (StringRef sym : args::getLines(*buf))
+ config->allowUndefinedSymbols.insert(sym);
}
// Returns slices of MB by parsing MB as an archive file.
// Each slice consists of a member file in the archive.
-std::vector<MemoryBufferRef> static getArchiveMembers(MemoryBufferRef MB) {
- std::unique_ptr<Archive> File =
- CHECK(Archive::create(MB),
- MB.getBufferIdentifier() + ": failed to parse archive");
-
- std::vector<MemoryBufferRef> V;
- Error Err = Error::success();
- for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
- Archive::Child C =
- CHECK(COrErr, MB.getBufferIdentifier() +
+std::vector<MemoryBufferRef> static getArchiveMembers(MemoryBufferRef mb) {
+ std::unique_ptr<Archive> file =
+ CHECK(Archive::create(mb),
+ mb.getBufferIdentifier() + ": failed to parse archive");
+
+ std::vector<MemoryBufferRef> v;
+ Error err = Error::success();
+ for (const ErrorOr<Archive::Child> &cOrErr : file->children(err)) {
+ Archive::Child c =
+ CHECK(cOrErr, mb.getBufferIdentifier() +
": could not get the child of the archive");
- MemoryBufferRef MBRef =
- CHECK(C.getMemoryBufferRef(),
- MB.getBufferIdentifier() +
+ MemoryBufferRef mbref =
+ CHECK(c.getMemoryBufferRef(),
+ mb.getBufferIdentifier() +
": could not get the buffer for a child of the archive");
- V.push_back(MBRef);
+ v.push_back(mbref);
}
- if (Err)
- fatal(MB.getBufferIdentifier() +
- ": Archive::children failed: " + toString(std::move(Err)));
+ if (err)
+ fatal(mb.getBufferIdentifier() +
+ ": Archive::children failed: " + toString(std::move(err)));
// Take ownership of memory buffers created for members of thin archives.
- for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers())
- make<std::unique_ptr<MemoryBuffer>>(std::move(MB));
+ for (std::unique_ptr<MemoryBuffer> &mb : file->takeThinBuffers())
+ make<std::unique_ptr<MemoryBuffer>>(std::move(mb));
- return V;
+ return v;
}
-void LinkerDriver::addFile(StringRef Path) {
- Optional<MemoryBufferRef> Buffer = readFile(Path);
- if (!Buffer.hasValue())
+void LinkerDriver::addFile(StringRef path) {
+ Optional<MemoryBufferRef> buffer = readFile(path);
+ if (!buffer.hasValue())
return;
- MemoryBufferRef MBRef = *Buffer;
+ MemoryBufferRef mbref = *buffer;
- switch (identify_magic(MBRef.getBuffer())) {
+ switch (identify_magic(mbref.getBuffer())) {
case file_magic::archive: {
- SmallString<128> ImportFile = Path;
- path::replace_extension(ImportFile, ".imports");
- if (fs::exists(ImportFile))
- readImportFile(ImportFile.str());
+ SmallString<128> importFile = path;
+ path::replace_extension(importFile, ".imports");
+ if (fs::exists(importFile))
+ readImportFile(importFile.str());
// Handle -whole-archive.
- if (InWholeArchive) {
- for (MemoryBufferRef &M : getArchiveMembers(MBRef))
- Files.push_back(createObjectFile(M, Path));
+ if (inWholeArchive) {
+ for (MemoryBufferRef &m : getArchiveMembers(mbref))
+ files.push_back(createObjectFile(m, path));
return;
}
- std::unique_ptr<Archive> File =
- CHECK(Archive::create(MBRef), Path + ": failed to parse archive");
+ std::unique_ptr<Archive> file =
+ CHECK(Archive::create(mbref), path + ": failed to parse archive");
- if (!File->isEmpty() && !File->hasSymbolTable()) {
- error(MBRef.getBufferIdentifier() +
+ if (!file->isEmpty() && !file->hasSymbolTable()) {
+ error(mbref.getBufferIdentifier() +
": archive has no index; run ranlib to add one");
}
- Files.push_back(make<ArchiveFile>(MBRef));
+ files.push_back(make<ArchiveFile>(mbref));
return;
}
case file_magic::bitcode:
case file_magic::wasm_object:
- Files.push_back(createObjectFile(MBRef));
+ files.push_back(createObjectFile(mbref));
break;
default:
- error("unknown file type: " + MBRef.getBufferIdentifier());
+ error("unknown file type: " + mbref.getBufferIdentifier());
}
}
// Add a given library by searching it from input search paths.
-void LinkerDriver::addLibrary(StringRef Name) {
- for (StringRef Dir : Config->SearchPaths) {
- if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) {
- addFile(*S);
+void LinkerDriver::addLibrary(StringRef name) {
+ for (StringRef dir : config->searchPaths) {
+ if (Optional<std::string> s = findFile(dir, "lib" + name + ".a")) {
+ addFile(*s);
return;
}
}
- error("unable to find library -l" + Name);
+ error("unable to find library -l" + name);
}
-void LinkerDriver::createFiles(opt::InputArgList &Args) {
- for (auto *Arg : Args) {
- switch (Arg->getOption().getID()) {
+void LinkerDriver::createFiles(opt::InputArgList &args) {
+ for (auto *arg : args) {
+ switch (arg->getOption().getID()) {
case OPT_l:
- addLibrary(Arg->getValue());
+ addLibrary(arg->getValue());
break;
case OPT_INPUT:
- addFile(Arg->getValue());
+ addFile(arg->getValue());
break;
case OPT_whole_archive:
- InWholeArchive = true;
+ inWholeArchive = true;
break;
case OPT_no_whole_archive:
- InWholeArchive = false;
+ inWholeArchive = false;
break;
}
}
}
-static StringRef getEntry(opt::InputArgList &Args) {
- auto *Arg = Args.getLastArg(OPT_entry, OPT_no_entry);
- if (!Arg) {
- if (Args.hasArg(OPT_relocatable))
+static StringRef getEntry(opt::InputArgList &args) {
+ auto *arg = args.getLastArg(OPT_entry, OPT_no_entry);
+ if (!arg) {
+ if (args.hasArg(OPT_relocatable))
return "";
- if (Args.hasArg(OPT_shared))
+ if (args.hasArg(OPT_shared))
return "__wasm_call_ctors";
return "_start";
}
- if (Arg->getOption().getID() == OPT_no_entry)
+ if (arg->getOption().getID() == OPT_no_entry)
return "";
- return Arg->getValue();
+ return arg->getValue();
}
// Initializes Config members by the command line options.
-static void readConfigs(opt::InputArgList &Args) {
- Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
- Config->CheckFeatures =
- Args.hasFlag(OPT_check_features, OPT_no_check_features, true);
- Config->CompressRelocations = Args.hasArg(OPT_compress_relocations);
- Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
- Config->DisableVerify = Args.hasArg(OPT_disable_verify);
- Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
- Config->Entry = getEntry(Args);
- Config->ExportAll = Args.hasArg(OPT_export_all);
- Config->ExportDynamic = Args.hasFlag(OPT_export_dynamic,
+static void readConfigs(opt::InputArgList &args) {
+ config->allowUndefined = args.hasArg(OPT_allow_undefined);
+ config->checkFeatures =
+ args.hasFlag(OPT_check_features, OPT_no_check_features, true);
+ config->compressRelocations = args.hasArg(OPT_compress_relocations);
+ config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true);
+ config->disableVerify = args.hasArg(OPT_disable_verify);
+ config->emitRelocs = args.hasArg(OPT_emit_relocs);
+ config->entry = getEntry(args);
+ config->exportAll = args.hasArg(OPT_export_all);
+ config->exportDynamic = args.hasFlag(OPT_export_dynamic,
OPT_no_export_dynamic, false);
- Config->ExportTable = Args.hasArg(OPT_export_table);
- errorHandler().FatalWarnings =
- Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
- Config->ImportMemory = Args.hasArg(OPT_import_memory);
- Config->SharedMemory = Args.hasArg(OPT_shared_memory);
+ config->exportTable = args.hasArg(OPT_export_table);
+ errorHandler().fatalWarnings =
+ args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+ config->importMemory = args.hasArg(OPT_import_memory);
+ config->sharedMemory = args.hasArg(OPT_shared_memory);
// TODO: Make passive segments the default with shared memory
- Config->PassiveSegments =
- Args.hasFlag(OPT_passive_segments, OPT_active_segments, false);
- Config->ImportTable = Args.hasArg(OPT_import_table);
- Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
- Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
- Config->Optimize = args::getInteger(Args, OPT_O, 0);
- Config->OutputFile = Args.getLastArgValue(OPT_o);
- Config->Relocatable = Args.hasArg(OPT_relocatable);
- Config->GcSections =
- Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !Config->Relocatable);
- Config->MergeDataSegments =
- Args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
- !Config->Relocatable);
- Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false);
- Config->PrintGcSections =
- Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
- Config->SaveTemps = Args.hasArg(OPT_save_temps);
- Config->SearchPaths = args::getStrings(Args, OPT_L);
- Config->Shared = Args.hasArg(OPT_shared);
- Config->StripAll = Args.hasArg(OPT_strip_all);
- Config->StripDebug = Args.hasArg(OPT_strip_debug);
- Config->StackFirst = Args.hasArg(OPT_stack_first);
- Config->Trace = Args.hasArg(OPT_trace);
- Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
- Config->ThinLTOCachePolicy = CHECK(
- parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)),
+ config->passiveSegments =
+ args.hasFlag(OPT_passive_segments, OPT_active_segments, false);
+ config->importTable = args.hasArg(OPT_import_table);
+ config->ltoo = args::getInteger(args, OPT_lto_O, 2);
+ config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);
+ config->optimize = args::getInteger(args, OPT_O, 0);
+ config->outputFile = args.getLastArgValue(OPT_o);
+ config->relocatable = args.hasArg(OPT_relocatable);
+ config->gcSections =
+ args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !config->relocatable);
+ config->mergeDataSegments =
+ args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
+ !config->relocatable);
+ config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false);
+ config->printGcSections =
+ args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
+ config->saveTemps = args.hasArg(OPT_save_temps);
+ config->searchPaths = args::getStrings(args, OPT_L);
+ config->shared = args.hasArg(OPT_shared);
+ config->stripAll = args.hasArg(OPT_strip_all);
+ config->stripDebug = args.hasArg(OPT_strip_debug);
+ config->stackFirst = args.hasArg(OPT_stack_first);
+ config->trace = args.hasArg(OPT_trace);
+ config->thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir);
+ config->thinLTOCachePolicy = CHECK(
+ parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)),
"--thinlto-cache-policy: invalid cache policy");
- Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u);
- errorHandler().Verbose = Args.hasArg(OPT_verbose);
- LLVM_DEBUG(errorHandler().Verbose = true);
- ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
-
- Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0);
- Config->GlobalBase = args::getInteger(Args, OPT_global_base, 1024);
- Config->MaxMemory = args::getInteger(Args, OPT_max_memory, 0);
- Config->ZStackSize =
- args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize);
-
- if (auto *Arg = Args.getLastArg(OPT_features)) {
- Config->Features =
+ config->thinLTOJobs = args::getInteger(args, OPT_thinlto_jobs, -1u);
+ errorHandler().verbose = args.hasArg(OPT_verbose);
+ LLVM_DEBUG(errorHandler().verbose = true);
+ threadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true);
+
+ config->initialMemory = args::getInteger(args, OPT_initial_memory, 0);
+ config->globalBase = args::getInteger(args, OPT_global_base, 1024);
+ config->maxMemory = args::getInteger(args, OPT_max_memory, 0);
+ config->zStackSize =
+ args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize);
+
+ if (auto *arg = args.getLastArg(OPT_features)) {
+ config->features =
llvm::Optional<std::vector<std::string>>(std::vector<std::string>());
- for (StringRef S : Arg->getValues())
- Config->Features->push_back(S);
+ for (StringRef s : arg->getValues())
+ config->features->push_back(s);
}
}
// This function initialize such members. See Config.h for the details
// of these values.
static void setConfigs() {
- Config->Pic = Config->Pie || Config->Shared;
+ config->isPic = config->pie || config->shared;
- if (Config->Pic) {
- if (Config->ExportTable)
+ if (config->isPic) {
+ if (config->exportTable)
error("-shared/-pie is incompatible with --export-table");
- Config->ImportTable = true;
+ config->importTable = true;
}
- if (Config->Shared) {
- Config->ImportMemory = true;
- Config->ExportDynamic = true;
- Config->AllowUndefined = true;
+ if (config->shared) {
+ config->importMemory = true;
+ config->exportDynamic = true;
+ config->allowUndefined = true;
}
}
// Some command line options or some combinations of them are not allowed.
// This function checks for such errors.
-static void checkOptions(opt::InputArgList &Args) {
- if (!Config->StripDebug && !Config->StripAll && Config->CompressRelocations)
+static void checkOptions(opt::InputArgList &args) {
+ if (!config->stripDebug && !config->stripAll && config->compressRelocations)
error("--compress-relocations is incompatible with output debug"
" information. Please pass --strip-debug or --strip-all");
- if (Config->LTOO > 3)
- error("invalid optimization level for LTO: " + Twine(Config->LTOO));
- if (Config->LTOPartitions == 0)
+ if (config->ltoo > 3)
+ error("invalid optimization level for LTO: " + Twine(config->ltoo));
+ if (config->ltoPartitions == 0)
error("--lto-partitions: number of threads must be > 0");
- if (Config->ThinLTOJobs == 0)
+ if (config->thinLTOJobs == 0)
error("--thinlto-jobs: number of threads must be > 0");
- if (Config->Pie && Config->Shared)
+ if (config->pie && config->shared)
error("-shared and -pie may not be used together");
- if (Config->OutputFile.empty())
+ if (config->outputFile.empty())
error("no output file specified");
- if (Config->ImportTable && Config->ExportTable)
+ if (config->importTable && config->exportTable)
error("--import-table and --export-table may not be used together");
- if (Config->Relocatable) {
- if (!Config->Entry.empty())
+ if (config->relocatable) {
+ if (!config->entry.empty())
error("entry point specified for relocatable output file");
- if (Config->GcSections)
+ if (config->gcSections)
error("-r and --gc-sections may not be used together");
- if (Config->CompressRelocations)
+ if (config->compressRelocations)
error("-r -and --compress-relocations may not be used together");
- if (Args.hasArg(OPT_undefined))
+ if (args.hasArg(OPT_undefined))
error("-r -and --undefined may not be used together");
- if (Config->Pie)
+ if (config->pie)
error("-r and -pie may not be used together");
}
}
// Force Sym to be entered in the output. Used for -u or equivalent.
-static Symbol *handleUndefined(StringRef Name) {
- Symbol *Sym = Symtab->find(Name);
- if (!Sym)
+static Symbol *handleUndefined(StringRef name) {
+ Symbol *sym = symtab->find(name);
+ if (!sym)
return nullptr;
// Since symbol S may not be used inside the program, LTO may
// eliminate it. Mark the symbol as "used" to prevent it.
- Sym->IsUsedInRegularObj = true;
+ sym->isUsedInRegularObj = true;
- if (auto *LazySym = dyn_cast<LazySymbol>(Sym))
- LazySym->fetch();
+ if (auto *lazySym = dyn_cast<LazySymbol>(sym))
+ lazySym->fetch();
- return Sym;
+ return sym;
}
static UndefinedGlobal *
-createUndefinedGlobal(StringRef Name, llvm::wasm::WasmGlobalType *Type) {
- auto *Sym =
- cast<UndefinedGlobal>(Symtab->addUndefinedGlobal(Name, Name,
- DefaultModule, 0,
- nullptr, Type));
- Config->AllowUndefinedSymbols.insert(Sym->getName());
- Sym->IsUsedInRegularObj = true;
- return Sym;
+createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) {
+ auto *sym =
+ cast<UndefinedGlobal>(symtab->addUndefinedGlobal(name, name,
+ defaultModule, 0,
+ nullptr, type));
+ config->allowUndefinedSymbols.insert(sym->getName());
+ sym->isUsedInRegularObj = true;
+ return sym;
}
// Create ABI-defined synthetic symbols
static void createSyntheticSymbols() {
- static WasmSignature NullSignature = {{}, {}};
- static llvm::wasm::WasmGlobalType GlobalTypeI32 = {WASM_TYPE_I32, false};
- static llvm::wasm::WasmGlobalType MutableGlobalTypeI32 = {WASM_TYPE_I32,
+ static WasmSignature nullSignature = {{}, {}};
+ static llvm::wasm::WasmGlobalType globalTypeI32 = {WASM_TYPE_I32, false};
+ static llvm::wasm::WasmGlobalType mutableGlobalTypeI32 = {WASM_TYPE_I32,
true};
- if (!Config->Relocatable) {
- WasmSym::CallCtors = Symtab->addSyntheticFunction(
+ if (!config->relocatable) {
+ WasmSym::callCtors = symtab->addSyntheticFunction(
"__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
- make<SyntheticFunction>(NullSignature, "__wasm_call_ctors"));
+ make<SyntheticFunction>(nullSignature, "__wasm_call_ctors"));
- if (Config->PassiveSegments) {
+ if (config->passiveSegments) {
// Passive segments are used to avoid memory being reinitialized on each
// thread's instantiation. These passive segments are initialized and
// dropped in __wasm_init_memory, which is the first function called from
// __wasm_call_ctors.
- WasmSym::InitMemory = Symtab->addSyntheticFunction(
+ WasmSym::initMemory = symtab->addSyntheticFunction(
"__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN,
- make<SyntheticFunction>(NullSignature, "__wasm_init_memory"));
+ make<SyntheticFunction>(nullSignature, "__wasm_init_memory"));
}
- if (Config->Pic) {
+ if (config->isPic) {
// For PIC code we create a synthetic function __wasm_apply_relocs which
// is called from __wasm_call_ctors before the user-level constructors.
- WasmSym::ApplyRelocs = Symtab->addSyntheticFunction(
+ WasmSym::applyRelocs = symtab->addSyntheticFunction(
"__wasm_apply_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
- make<SyntheticFunction>(NullSignature, "__wasm_apply_relocs"));
+ make<SyntheticFunction>(nullSignature, "__wasm_apply_relocs"));
}
}
// The __stack_pointer is imported in the shared library case, and exported
// in the non-shared (executable) case.
- if (Config->Shared) {
- WasmSym::StackPointer =
- createUndefinedGlobal("__stack_pointer", &MutableGlobalTypeI32);
+ if (config->shared) {
+ WasmSym::stackPointer =
+ createUndefinedGlobal("__stack_pointer", &mutableGlobalTypeI32);
} else {
- llvm::wasm::WasmGlobal Global;
- Global.Type = {WASM_TYPE_I32, true};
- Global.InitExpr.Value.Int32 = 0;
- Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- Global.SymbolName = "__stack_pointer";
- auto *StackPointer = make<InputGlobal>(Global, nullptr);
- StackPointer->Live = true;
+ llvm::wasm::WasmGlobal global;
+ global.Type = {WASM_TYPE_I32, true};
+ global.InitExpr.Value.Int32 = 0;
+ global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+ global.SymbolName = "__stack_pointer";
+ auto *stackPointer = make<InputGlobal>(global, nullptr);
+ stackPointer->live = true;
// For non-PIC code
// TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN when the mutable global
// spec proposal is implemented in all major browsers.
// See: https://github.com/WebAssembly/mutable-global
- WasmSym::StackPointer = Symtab->addSyntheticGlobal(
- "__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, StackPointer);
- WasmSym::DataEnd = Symtab->addOptionalDataSymbol("__data_end");
- WasmSym::GlobalBase = Symtab->addOptionalDataSymbol("__global_base");
- WasmSym::HeapBase = Symtab->addOptionalDataSymbol("__heap_base");
+ WasmSym::stackPointer = symtab->addSyntheticGlobal(
+ "__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, stackPointer);
+ WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end");
+ WasmSym::globalBase = symtab->addOptionalDataSymbol("__global_base");
+ WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base");
}
- if (Config->Pic) {
+ if (config->isPic) {
// For PIC code, we import two global variables (__memory_base and
// __table_base) from the environment and use these as the offset at
// which to load our static data and function table.
// See:
// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
- WasmSym::MemoryBase =
- createUndefinedGlobal("__memory_base", &GlobalTypeI32);
- WasmSym::TableBase = createUndefinedGlobal("__table_base", &GlobalTypeI32);
- WasmSym::MemoryBase->markLive();
- WasmSym::TableBase->markLive();
+ WasmSym::memoryBase =
+ createUndefinedGlobal("__memory_base", &globalTypeI32);
+ WasmSym::tableBase = createUndefinedGlobal("__table_base", &globalTypeI32);
+ WasmSym::memoryBase->markLive();
+ WasmSym::tableBase->markLive();
}
- WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol(
+ WasmSym::dsoHandle = symtab->addSyntheticDataSymbol(
"__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);
}
// Reconstructs command line arguments so that so that you can re-run
// the same command with the same inputs. This is for --reproduce.
-static std::string createResponseFile(const opt::InputArgList &Args) {
- SmallString<0> Data;
- raw_svector_ostream OS(Data);
+static std::string createResponseFile(const opt::InputArgList &args) {
+ SmallString<0> data;
+ raw_svector_ostream os(data);
// Copy the command line to the output while rewriting paths.
- for (auto *Arg : Args) {
- switch (Arg->getOption().getID()) {
+ for (auto *arg : args) {
+ switch (arg->getOption().getID()) {
case OPT_reproduce:
break;
case OPT_INPUT:
- OS << quote(relativeToRoot(Arg->getValue())) << "\n";
+ os << quote(relativeToRoot(arg->getValue())) << "\n";
break;
case OPT_o:
// If -o path contains directories, "lld @response.txt" will likely
// fail because the archive we are creating doesn't contain empty
// directories for the output path (-o doesn't create directories).
// Strip directories to prevent the issue.
- OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
+ os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n";
break;
default:
- OS << toString(*Arg) << "\n";
+ os << toString(*arg) << "\n";
}
}
- return Data.str();
+ return data.str();
}
// The --wrap option is a feature to rename symbols so that you can write
//
// This data structure is instantiated for each -wrap option.
struct WrappedSymbol {
- Symbol *Sym;
- Symbol *Real;
- Symbol *Wrap;
+ Symbol *sym;
+ Symbol *real;
+ Symbol *wrap;
};
-static Symbol *addUndefined(StringRef Name) {
- return Symtab->addUndefinedFunction(Name, "", "", 0, nullptr, nullptr, false);
+static Symbol *addUndefined(StringRef name) {
+ return symtab->addUndefinedFunction(name, "", "", 0, nullptr, nullptr, false);
}
// Handles -wrap option.
// This function instantiates wrapper symbols. At this point, they seem
// like they are not being used at all, so we explicitly set some flags so
// that LTO won't eliminate them.
-static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &Args) {
- std::vector<WrappedSymbol> V;
- DenseSet<StringRef> Seen;
+static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) {
+ std::vector<WrappedSymbol> v;
+ DenseSet<StringRef> seen;
- for (auto *Arg : Args.filtered(OPT_wrap)) {
- StringRef Name = Arg->getValue();
- if (!Seen.insert(Name).second)
+ for (auto *arg : args.filtered(OPT_wrap)) {
+ StringRef name = arg->getValue();
+ if (!seen.insert(name).second)
continue;
- Symbol *Sym = Symtab->find(Name);
- if (!Sym)
+ Symbol *sym = symtab->find(name);
+ if (!sym)
continue;
- Symbol *Real = addUndefined(Saver.save("__real_" + Name));
- Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
- V.push_back({Sym, Real, Wrap});
+ Symbol *real = addUndefined(saver.save("__real_" + name));
+ Symbol *wrap = addUndefined(saver.save("__wrap_" + name));
+ v.push_back({sym, real, wrap});
// We want to tell LTO not to inline symbols to be overwritten
// because LTO doesn't know the final symbol contents after renaming.
- Real->CanInline = false;
- Sym->CanInline = false;
+ real->canInline = false;
+ sym->canInline = false;
// Tell LTO not to eliminate these symbols.
- Sym->IsUsedInRegularObj = true;
- Wrap->IsUsedInRegularObj = true;
- Real->IsUsedInRegularObj = false;
+ sym->isUsedInRegularObj = true;
+ wrap->isUsedInRegularObj = true;
+ real->isUsedInRegularObj = false;
}
- return V;
+ return v;
}
// Do renaming for -wrap by updating pointers to symbols.
// When this function is executed, only InputFiles and symbol table
// contain pointers to symbol objects. We visit them to replace pointers,
// so that wrapped symbols are swapped as instructed by the command line.
-static void wrapSymbols(ArrayRef<WrappedSymbol> Wrapped) {
- DenseMap<Symbol *, Symbol *> Map;
- for (const WrappedSymbol &W : Wrapped) {
- Map[W.Sym] = W.Wrap;
- Map[W.Real] = W.Sym;
+static void wrapSymbols(ArrayRef<WrappedSymbol> wrapped) {
+ DenseMap<Symbol *, Symbol *> map;
+ for (const WrappedSymbol &w : wrapped) {
+ map[w.sym] = w.wrap;
+ map[w.real] = w.sym;
}
// Update pointers in input files.
- parallelForEach(Symtab->ObjectFiles, [&](InputFile *File) {
- MutableArrayRef<Symbol *> Syms = File->getMutableSymbols();
- for (size_t I = 0, E = Syms.size(); I != E; ++I)
- if (Symbol *S = Map.lookup(Syms[I]))
- Syms[I] = S;
+ parallelForEach(symtab->objectFiles, [&](InputFile *file) {
+ MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
+ for (size_t i = 0, e = syms.size(); i != e; ++i)
+ if (Symbol *s = map.lookup(syms[i]))
+ syms[i] = s;
});
// Update pointers in the symbol table.
- for (const WrappedSymbol &W : Wrapped)
- Symtab->wrap(W.Sym, W.Real, W.Wrap);
+ for (const WrappedSymbol &w : wrapped)
+ symtab->wrap(w.sym, w.real, w.wrap);
}
-void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
- WasmOptTable Parser;
- opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
+void LinkerDriver::link(ArrayRef<const char *> argsArr) {
+ WasmOptTable parser;
+ opt::InputArgList args = parser.parse(argsArr.slice(1));
// Handle --help
- if (Args.hasArg(OPT_help)) {
- Parser.PrintHelp(outs(),
- (std::string(ArgsArr[0]) + " [options] file...").c_str(),
+ if (args.hasArg(OPT_help)) {
+ parser.PrintHelp(outs(),
+ (std::string(argsArr[0]) + " [options] file...").c_str(),
"LLVM Linker", false);
return;
}
// Handle --version
- if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) {
+ if (args.hasArg(OPT_version) || args.hasArg(OPT_v)) {
outs() << getLLDVersion() << "\n";
return;
}
// Handle --reproduce
- if (auto *Arg = Args.getLastArg(OPT_reproduce)) {
- StringRef Path = Arg->getValue();
- Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
- TarWriter::create(Path, path::stem(Path));
- if (ErrOrWriter) {
- Tar = std::move(*ErrOrWriter);
- Tar->append("response.txt", createResponseFile(Args));
- Tar->append("version.txt", getLLDVersion() + "\n");
+ if (auto *arg = args.getLastArg(OPT_reproduce)) {
+ StringRef path = arg->getValue();
+ Expected<std::unique_ptr<TarWriter>> errOrWriter =
+ TarWriter::create(path, path::stem(path));
+ if (errOrWriter) {
+ tar = std::move(*errOrWriter);
+ tar->append("response.txt", createResponseFile(args));
+ tar->append("version.txt", getLLDVersion() + "\n");
} else {
- error("--reproduce: " + toString(ErrOrWriter.takeError()));
+ error("--reproduce: " + toString(errOrWriter.takeError()));
}
}
// Parse and evaluate -mllvm options.
- std::vector<const char *> V;
- V.push_back("wasm-ld (LLVM option parsing)");
- for (auto *Arg : Args.filtered(OPT_mllvm))
- V.push_back(Arg->getValue());
- cl::ParseCommandLineOptions(V.size(), V.data());
+ std::vector<const char *> v;
+ v.push_back("wasm-ld (LLVM option parsing)");
+ for (auto *arg : args.filtered(OPT_mllvm))
+ v.push_back(arg->getValue());
+ cl::ParseCommandLineOptions(v.size(), v.data());
- errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20);
+ errorHandler().errorLimit = args::getInteger(args, OPT_error_limit, 20);
- readConfigs(Args);
+ readConfigs(args);
setConfigs();
- checkOptions(Args);
+ checkOptions(args);
- if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file))
- readImportFile(Arg->getValue());
+ if (auto *arg = args.getLastArg(OPT_allow_undefined_file))
+ readImportFile(arg->getValue());
- if (!Args.hasArg(OPT_INPUT)) {
+ if (!args.hasArg(OPT_INPUT)) {
error("no input files");
return;
}
// Handle --trace-symbol.
- for (auto *Arg : Args.filtered(OPT_trace_symbol))
- Symtab->trace(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_trace_symbol))
+ symtab->trace(arg->getValue());
- for (auto *Arg : Args.filtered(OPT_export))
- Config->ExportedSymbols.insert(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_export))
+ config->exportedSymbols.insert(arg->getValue());
- if (!Config->Relocatable)
+ if (!config->relocatable)
createSyntheticSymbols();
- createFiles(Args);
+ createFiles(args);
if (errorCount())
return;
// Add all files to the symbol table. This will add almost all
// symbols that we need to the symbol table.
- for (InputFile *F : Files)
- Symtab->addFile(F);
+ for (InputFile *f : files)
+ symtab->addFile(f);
if (errorCount())
return;
// Handle the `--undefined <sym>` options.
- for (auto *Arg : Args.filtered(OPT_undefined))
- handleUndefined(Arg->getValue());
+ for (auto *arg : args.filtered(OPT_undefined))
+ handleUndefined(arg->getValue());
// Handle the `--export <sym>` options
// This works like --undefined but also exports the symbol if its found
- for (auto *Arg : Args.filtered(OPT_export))
- handleUndefined(Arg->getValue());
-
- Symbol *EntrySym = nullptr;
- if (!Config->Relocatable && !Config->Entry.empty()) {
- EntrySym = handleUndefined(Config->Entry);
- if (EntrySym && EntrySym->isDefined())
- EntrySym->ForceExport = true;
+ for (auto *arg : args.filtered(OPT_export))
+ handleUndefined(arg->getValue());
+
+ Symbol *entrySym = nullptr;
+ if (!config->relocatable && !config->entry.empty()) {
+ entrySym = handleUndefined(config->entry);
+ if (entrySym && entrySym->isDefined())
+ entrySym->forceExport = true;
else
error("entry symbol not defined (pass --no-entry to supress): " +
- Config->Entry);
+ config->entry);
}
if (errorCount())
return;
// Create wrapped symbols for -wrap option.
- std::vector<WrappedSymbol> Wrapped = addWrappedSymbols(Args);
+ std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);
// Do link-time optimization if given files are LLVM bitcode files.
// This compiles bitcode files into real object files.
- Symtab->addCombinedLTOObject();
+ symtab->addCombinedLTOObject();
if (errorCount())
return;
// Resolve any variant symbols that were created due to signature
// mismatchs.
- Symtab->handleSymbolVariants();
+ symtab->handleSymbolVariants();
if (errorCount())
return;
// Apply symbol renames for -wrap.
- if (!Wrapped.empty())
- wrapSymbols(Wrapped);
-
- for (auto *Arg : Args.filtered(OPT_export)) {
- Symbol *Sym = Symtab->find(Arg->getValue());
- if (Sym && Sym->isDefined())
- Sym->ForceExport = true;
- else if (!Config->AllowUndefined)
+ if (!wrapped.empty())
+ wrapSymbols(wrapped);
+
+ for (auto *arg : args.filtered(OPT_export)) {
+ Symbol *sym = symtab->find(arg->getValue());
+ if (sym && sym->isDefined())
+ sym->forceExport = true;
+ else if (!config->allowUndefined)
error(Twine("symbol exported via --export not found: ") +
- Arg->getValue());
+ arg->getValue());
}
- if (!Config->Relocatable) {
+ if (!config->relocatable) {
// Add synthetic dummies for weak undefined functions. Must happen
// after LTO otherwise functions may not yet have signatures.
- Symtab->handleWeakUndefines();
+ symtab->handleWeakUndefines();
}
- if (EntrySym)
- EntrySym->setHidden(false);
+ if (entrySym)
+ entrySym->setHidden(false);
if (errorCount())
return;
using namespace lld;
using namespace lld::wasm;
-StringRef lld::relocTypeToString(uint8_t RelocType) {
- switch (RelocType) {
+StringRef lld::relocTypeToString(uint8_t relocType) {
+ switch (relocType) {
#define WASM_RELOC(NAME, REL) \
case REL: \
return #NAME;
llvm_unreachable("unknown reloc type");
}
-std::string lld::toString(const InputChunk *C) {
- return (toString(C->File) + ":(" + C->getName() + ")").str();
+std::string lld::toString(const InputChunk *c) {
+ return (toString(c->file) + ":(" + c->getName() + ")").str();
}
StringRef InputChunk::getComdatName() const {
- uint32_t Index = getComdat();
- if (Index == UINT32_MAX)
+ uint32_t index = getComdat();
+ if (index == UINT32_MAX)
return StringRef();
- return File->getWasmObj()->linkingData().Comdats[Index];
+ return file->getWasmObj()->linkingData().Comdats[index];
}
void InputChunk::verifyRelocTargets() const {
- for (const WasmRelocation &Rel : Relocations) {
- uint32_t ExistingValue;
- unsigned BytesRead = 0;
- uint32_t Offset = Rel.Offset - getInputSectionOffset();
- const uint8_t *Loc = data().data() + Offset;
- switch (Rel.Type) {
+ for (const WasmRelocation &rel : relocations) {
+ uint32_t existingValue;
+ unsigned bytesRead = 0;
+ uint32_t offset = rel.Offset - getInputSectionOffset();
+ const uint8_t *loc = data().data() + offset;
+ switch (rel.Type) {
case R_WASM_TYPE_INDEX_LEB:
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
- ExistingValue = decodeULEB128(Loc, &BytesRead);
+ existingValue = decodeULEB128(loc, &bytesRead);
break;
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_REL_SLEB:
- ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc, &BytesRead));
+ existingValue = static_cast<uint32_t>(decodeSLEB128(loc, &bytesRead));
break;
case R_WASM_TABLE_INDEX_I32:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_FUNCTION_OFFSET_I32:
case R_WASM_SECTION_OFFSET_I32:
- ExistingValue = static_cast<uint32_t>(read32le(Loc));
+ existingValue = static_cast<uint32_t>(read32le(loc));
break;
default:
llvm_unreachable("unknown relocation type");
}
- if (BytesRead && BytesRead != 5)
+ if (bytesRead && bytesRead != 5)
warn("expected LEB at relocation site be 5-byte padded");
- if (Rel.Type != R_WASM_GLOBAL_INDEX_LEB) {
- uint32_t ExpectedValue = File->calcExpectedValue(Rel);
- if (ExpectedValue != ExistingValue)
- warn("unexpected existing value for " + relocTypeToString(Rel.Type) +
- ": existing=" + Twine(ExistingValue) +
- " expected=" + Twine(ExpectedValue));
+ if (rel.Type != R_WASM_GLOBAL_INDEX_LEB) {
+ uint32_t expectedValue = file->calcExpectedValue(rel);
+ if (expectedValue != existingValue)
+ warn("unexpected existing value for " + relocTypeToString(rel.Type) +
+ ": existing=" + Twine(existingValue) +
+ " expected=" + Twine(expectedValue));
}
}
}
// Copy this input chunk to an mmap'ed output file and apply relocations.
-void InputChunk::writeTo(uint8_t *Buf) const {
+void InputChunk::writeTo(uint8_t *buf) const {
// Copy contents
- memcpy(Buf + OutputOffset, data().data(), data().size());
+ memcpy(buf + outputOffset, data().data(), data().size());
// Apply relocations
- if (Relocations.empty())
+ if (relocations.empty())
return;
#ifndef NDEBUG
#endif
LLVM_DEBUG(dbgs() << "applying relocations: " << getName()
- << " count=" << Relocations.size() << "\n");
- int32_t Off = OutputOffset - getInputSectionOffset();
-
- for (const WasmRelocation &Rel : Relocations) {
- uint8_t *Loc = Buf + Rel.Offset + Off;
- uint32_t Value = File->calcNewValue(Rel);
- LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(Rel.Type));
- if (Rel.Type != R_WASM_TYPE_INDEX_LEB)
- LLVM_DEBUG(dbgs() << " sym=" << File->getSymbols()[Rel.Index]->getName());
- LLVM_DEBUG(dbgs() << " addend=" << Rel.Addend << " index=" << Rel.Index
- << " value=" << Value << " offset=" << Rel.Offset
+ << " count=" << relocations.size() << "\n");
+ int32_t off = outputOffset - getInputSectionOffset();
+
+ for (const WasmRelocation &rel : relocations) {
+ uint8_t *loc = buf + rel.Offset + off;
+ uint32_t value = file->calcNewValue(rel);
+ LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(rel.Type));
+ if (rel.Type != R_WASM_TYPE_INDEX_LEB)
+ LLVM_DEBUG(dbgs() << " sym=" << file->getSymbols()[rel.Index]->getName());
+ LLVM_DEBUG(dbgs() << " addend=" << rel.Addend << " index=" << rel.Index
+ << " value=" << value << " offset=" << rel.Offset
<< "\n");
- switch (Rel.Type) {
+ switch (rel.Type) {
case R_WASM_TYPE_INDEX_LEB:
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
- encodeULEB128(Value, Loc, 5);
+ encodeULEB128(value, loc, 5);
break;
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_REL_SLEB:
- encodeSLEB128(static_cast<int32_t>(Value), Loc, 5);
+ encodeSLEB128(static_cast<int32_t>(value), loc, 5);
break;
case R_WASM_TABLE_INDEX_I32:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_FUNCTION_OFFSET_I32:
case R_WASM_SECTION_OFFSET_I32:
- write32le(Loc, Value);
+ write32le(loc, value);
break;
default:
llvm_unreachable("unknown relocation type");
// Copy relocation entries to a given output stream.
// This function is used only when a user passes "-r". For a regular link,
// we consume relocations instead of copying them to an output file.
-void InputChunk::writeRelocations(raw_ostream &OS) const {
- if (Relocations.empty())
+void InputChunk::writeRelocations(raw_ostream &os) const {
+ if (relocations.empty())
return;
- int32_t Off = OutputOffset - getInputSectionOffset();
- LLVM_DEBUG(dbgs() << "writeRelocations: " << File->getName()
- << " offset=" << Twine(Off) << "\n");
+ int32_t off = outputOffset - getInputSectionOffset();
+ LLVM_DEBUG(dbgs() << "writeRelocations: " << file->getName()
+ << " offset=" << Twine(off) << "\n");
- for (const WasmRelocation &Rel : Relocations) {
- writeUleb128(OS, Rel.Type, "reloc type");
- writeUleb128(OS, Rel.Offset + Off, "reloc offset");
- writeUleb128(OS, File->calcNewIndex(Rel), "reloc index");
+ for (const WasmRelocation &rel : relocations) {
+ writeUleb128(os, rel.Type, "reloc type");
+ writeUleb128(os, rel.Offset + off, "reloc offset");
+ writeUleb128(os, file->calcNewIndex(rel), "reloc index");
- if (relocTypeHasAddend(Rel.Type))
- writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend");
+ if (relocTypeHasAddend(rel.Type))
+ writeSleb128(os, file->calcNewAddend(rel), "reloc addend");
}
}
-void InputFunction::setFunctionIndex(uint32_t Index) {
+void InputFunction::setFunctionIndex(uint32_t index) {
LLVM_DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName()
- << " -> " << Index << "\n");
+ << " -> " << index << "\n");
assert(!hasFunctionIndex());
- FunctionIndex = Index;
+ functionIndex = index;
}
-void InputFunction::setTableIndex(uint32_t Index) {
+void InputFunction::setTableIndex(uint32_t index) {
LLVM_DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> "
- << Index << "\n");
+ << index << "\n");
assert(!hasTableIndex());
- TableIndex = Index;
+ tableIndex = index;
}
// Write a relocation value without padding and return the number of bytes
// witten.
-static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel,
- uint32_t Value) {
- switch (Rel.Type) {
+static unsigned writeCompressedReloc(uint8_t *buf, const WasmRelocation &rel,
+ uint32_t value) {
+ switch (rel.Type) {
case R_WASM_TYPE_INDEX_LEB:
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
- return encodeULEB128(Value, Buf);
+ return encodeULEB128(value, buf);
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
- return encodeSLEB128(static_cast<int32_t>(Value), Buf);
+ return encodeSLEB128(static_cast<int32_t>(value), buf);
default:
llvm_unreachable("unexpected relocation type");
}
}
-static unsigned getRelocWidthPadded(const WasmRelocation &Rel) {
- switch (Rel.Type) {
+static unsigned getRelocWidthPadded(const WasmRelocation &rel) {
+ switch (rel.Type) {
case R_WASM_TYPE_INDEX_LEB:
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
}
}
-static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) {
- uint8_t Buf[5];
- return writeCompressedReloc(Buf, Rel, Value);
+static unsigned getRelocWidth(const WasmRelocation &rel, uint32_t value) {
+ uint8_t buf[5];
+ return writeCompressedReloc(buf, rel, value);
}
// Relocations of type LEB and SLEB in the code section are padded to 5 bytes
// This function only computes the final output size. It must be called
// before getSize() is used to calculate of layout of the code section.
void InputFunction::calculateSize() {
- if (!File || !Config->CompressRelocations)
+ if (!file || !config->compressRelocations)
return;
LLVM_DEBUG(dbgs() << "calculateSize: " << getName() << "\n");
- const uint8_t *SecStart = File->CodeSection->Content.data();
- const uint8_t *FuncStart = SecStart + getInputSectionOffset();
- uint32_t FunctionSizeLength;
- decodeULEB128(FuncStart, &FunctionSizeLength);
+ const uint8_t *secStart = file->codeSection->Content.data();
+ const uint8_t *funcStart = secStart + getInputSectionOffset();
+ uint32_t functionSizeLength;
+ decodeULEB128(funcStart, &functionSizeLength);
- uint32_t Start = getInputSectionOffset();
- uint32_t End = Start + Function->Size;
+ uint32_t start = getInputSectionOffset();
+ uint32_t end = start + function->Size;
- uint32_t LastRelocEnd = Start + FunctionSizeLength;
- for (const WasmRelocation &Rel : Relocations) {
- LLVM_DEBUG(dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n");
- CompressedFuncSize += Rel.Offset - LastRelocEnd;
- CompressedFuncSize += getRelocWidth(Rel, File->calcNewValue(Rel));
- LastRelocEnd = Rel.Offset + getRelocWidthPadded(Rel);
+ uint32_t lastRelocEnd = start + functionSizeLength;
+ for (const WasmRelocation &rel : relocations) {
+ LLVM_DEBUG(dbgs() << " region: " << (rel.Offset - lastRelocEnd) << "\n");
+ compressedFuncSize += rel.Offset - lastRelocEnd;
+ compressedFuncSize += getRelocWidth(rel, file->calcNewValue(rel));
+ lastRelocEnd = rel.Offset + getRelocWidthPadded(rel);
}
- LLVM_DEBUG(dbgs() << " final region: " << (End - LastRelocEnd) << "\n");
- CompressedFuncSize += End - LastRelocEnd;
+ LLVM_DEBUG(dbgs() << " final region: " << (end - lastRelocEnd) << "\n");
+ compressedFuncSize += end - lastRelocEnd;
// Now we know how long the resulting function is we can add the encoding
// of its length
- uint8_t Buf[5];
- CompressedSize = CompressedFuncSize + encodeULEB128(CompressedFuncSize, Buf);
+ uint8_t buf[5];
+ compressedSize = compressedFuncSize + encodeULEB128(compressedFuncSize, buf);
- LLVM_DEBUG(dbgs() << " calculateSize orig: " << Function->Size << "\n");
- LLVM_DEBUG(dbgs() << " calculateSize new: " << CompressedSize << "\n");
+ LLVM_DEBUG(dbgs() << " calculateSize orig: " << function->Size << "\n");
+ LLVM_DEBUG(dbgs() << " calculateSize new: " << compressedSize << "\n");
}
// Override the default writeTo method so that we can (optionally) write the
// compressed version of the function.
-void InputFunction::writeTo(uint8_t *Buf) const {
- if (!File || !Config->CompressRelocations)
- return InputChunk::writeTo(Buf);
+void InputFunction::writeTo(uint8_t *buf) const {
+ if (!file || !config->compressRelocations)
+ return InputChunk::writeTo(buf);
- Buf += OutputOffset;
- uint8_t *Orig = Buf;
- (void)Orig;
+ buf += outputOffset;
+ uint8_t *orig = buf;
+ (void)orig;
- const uint8_t *SecStart = File->CodeSection->Content.data();
- const uint8_t *FuncStart = SecStart + getInputSectionOffset();
- const uint8_t *End = FuncStart + Function->Size;
- uint32_t Count;
- decodeULEB128(FuncStart, &Count);
- FuncStart += Count;
+ const uint8_t *secStart = file->codeSection->Content.data();
+ const uint8_t *funcStart = secStart + getInputSectionOffset();
+ const uint8_t *end = funcStart + function->Size;
+ uint32_t count;
+ decodeULEB128(funcStart, &count);
+ funcStart += count;
LLVM_DEBUG(dbgs() << "write func: " << getName() << "\n");
- Buf += encodeULEB128(CompressedFuncSize, Buf);
- const uint8_t *LastRelocEnd = FuncStart;
- for (const WasmRelocation &Rel : Relocations) {
- unsigned ChunkSize = (SecStart + Rel.Offset) - LastRelocEnd;
- LLVM_DEBUG(dbgs() << " write chunk: " << ChunkSize << "\n");
- memcpy(Buf, LastRelocEnd, ChunkSize);
- Buf += ChunkSize;
- Buf += writeCompressedReloc(Buf, Rel, File->calcNewValue(Rel));
- LastRelocEnd = SecStart + Rel.Offset + getRelocWidthPadded(Rel);
+ buf += encodeULEB128(compressedFuncSize, buf);
+ const uint8_t *lastRelocEnd = funcStart;
+ for (const WasmRelocation &rel : relocations) {
+ unsigned chunkSize = (secStart + rel.Offset) - lastRelocEnd;
+ LLVM_DEBUG(dbgs() << " write chunk: " << chunkSize << "\n");
+ memcpy(buf, lastRelocEnd, chunkSize);
+ buf += chunkSize;
+ buf += writeCompressedReloc(buf, rel, file->calcNewValue(rel));
+ lastRelocEnd = secStart + rel.Offset + getRelocWidthPadded(rel);
}
- unsigned ChunkSize = End - LastRelocEnd;
- LLVM_DEBUG(dbgs() << " write final chunk: " << ChunkSize << "\n");
- memcpy(Buf, LastRelocEnd, ChunkSize);
- LLVM_DEBUG(dbgs() << " total: " << (Buf + ChunkSize - Orig) << "\n");
+ unsigned chunkSize = end - lastRelocEnd;
+ LLVM_DEBUG(dbgs() << " write final chunk: " << chunkSize << "\n");
+ memcpy(buf, lastRelocEnd, chunkSize);
+ LLVM_DEBUG(dbgs() << " total: " << (buf + chunkSize - orig) << "\n");
}
// Generate code to apply relocations to the data section at runtime.
// This is only called when generating shared libaries (PIC) where address are
// not known at static link time.
-void InputSegment::generateRelocationCode(raw_ostream &OS) const {
+void InputSegment::generateRelocationCode(raw_ostream &os) const {
LLVM_DEBUG(dbgs() << "generating runtime relocations: " << getName()
- << " count=" << Relocations.size() << "\n");
+ << " count=" << relocations.size() << "\n");
// TODO(sbc): Encode the relocations in the data section and write a loop
// here to apply them.
- uint32_t SegmentVA = OutputSeg->StartVA + OutputSegmentOffset;
- for (const WasmRelocation &Rel : Relocations) {
- uint32_t Offset = Rel.Offset - getInputSectionOffset();
- uint32_t OutputOffset = SegmentVA + Offset;
+ uint32_t segmentVA = outputSeg->startVA + outputSegmentOffset;
+ for (const WasmRelocation &rel : relocations) {
+ uint32_t offset = rel.Offset - getInputSectionOffset();
+ uint32_t outputOffset = segmentVA + offset;
- LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(Rel.Type)
- << " addend=" << Rel.Addend << " index=" << Rel.Index
- << " output offset=" << OutputOffset << "\n");
+ LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(rel.Type)
+ << " addend=" << rel.Addend << " index=" << rel.Index
+ << " output offset=" << outputOffset << "\n");
// Get __memory_base
- writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
- writeUleb128(OS, WasmSym::MemoryBase->getGlobalIndex(), "memory_base");
+ writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
+ writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
// Add the offset of the relocation
- writeU8(OS, WASM_OPCODE_I32_CONST, "I32_CONST");
- writeSleb128(OS, OutputOffset, "offset");
- writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
+ writeU8(os, WASM_OPCODE_I32_CONST, "I32_CONST");
+ writeSleb128(os, outputOffset, "offset");
+ writeU8(os, WASM_OPCODE_I32_ADD, "ADD");
- Symbol *Sym = File->getSymbol(Rel);
+ Symbol *sym = file->getSymbol(rel);
// Now figure out what we want to store
- if (Sym->hasGOTIndex()) {
- writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
- writeUleb128(OS, Sym->getGOTIndex(), "global index");
- if (Rel.Addend) {
- writeU8(OS, WASM_OPCODE_I32_CONST, "CONST");
- writeSleb128(OS, Rel.Addend, "addend");
- writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
+ if (sym->hasGOTIndex()) {
+ writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
+ writeUleb128(os, sym->getGOTIndex(), "global index");
+ if (rel.Addend) {
+ writeU8(os, WASM_OPCODE_I32_CONST, "CONST");
+ writeSleb128(os, rel.Addend, "addend");
+ writeU8(os, WASM_OPCODE_I32_ADD, "ADD");
}
} else {
- const GlobalSymbol* BaseSymbol = WasmSym::MemoryBase;
- if (Rel.Type == R_WASM_TABLE_INDEX_I32)
- BaseSymbol = WasmSym::TableBase;
- writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
- writeUleb128(OS, BaseSymbol->getGlobalIndex(), "base");
- writeU8(OS, WASM_OPCODE_I32_CONST, "CONST");
- writeSleb128(OS, File->calcNewValue(Rel), "offset");
- writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
+ const GlobalSymbol* baseSymbol = WasmSym::memoryBase;
+ if (rel.Type == R_WASM_TABLE_INDEX_I32)
+ baseSymbol = WasmSym::tableBase;
+ writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
+ writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
+ writeU8(os, WASM_OPCODE_I32_CONST, "CONST");
+ writeSleb128(os, file->calcNewValue(rel), "offset");
+ writeU8(os, WASM_OPCODE_I32_ADD, "ADD");
}
// Store that value at the virtual address
- writeU8(OS, WASM_OPCODE_I32_STORE, "I32_STORE");
- writeUleb128(OS, 2, "align");
- writeUleb128(OS, 0, "offset");
+ writeU8(os, WASM_OPCODE_I32_STORE, "I32_STORE");
+ writeUleb128(os, 2, "align");
+ writeUleb128(os, 0, "offset");
}
}
public:
enum Kind { DataSegment, Function, SyntheticFunction, Section };
- Kind kind() const { return SectionKind; }
+ Kind kind() const { return sectionKind; }
virtual uint32_t getSize() const { return data().size(); }
virtual uint32_t getInputSize() const { return getSize(); };
- virtual void writeTo(uint8_t *SectionStart) const;
+ virtual void writeTo(uint8_t *sectionStart) const;
- ArrayRef<WasmRelocation> getRelocations() const { return Relocations; }
- void setRelocations(ArrayRef<WasmRelocation> Rs) { Relocations = Rs; }
+ ArrayRef<WasmRelocation> getRelocations() const { return relocations; }
+ void setRelocations(ArrayRef<WasmRelocation> rs) { relocations = rs; }
virtual StringRef getName() const = 0;
virtual StringRef getDebugName() const = 0;
StringRef getComdatName() const;
virtual uint32_t getInputSectionOffset() const = 0;
- size_t getNumRelocations() const { return Relocations.size(); }
- void writeRelocations(llvm::raw_ostream &OS) const;
+ size_t getNumRelocations() const { return relocations.size(); }
+ void writeRelocations(llvm::raw_ostream &os) const;
- ObjFile *File;
- int32_t OutputOffset = 0;
+ ObjFile *file;
+ int32_t outputOffset = 0;
// Signals that the section is part of the output. The garbage collector,
// and COMDAT handling can set a sections' Live bit.
// If GC is disabled, all sections start out as live by default.
- unsigned Live : 1;
+ unsigned live : 1;
// Signals the chunk was discarded by COMDAT handling.
- unsigned Discarded : 1;
+ unsigned discarded : 1;
protected:
- InputChunk(ObjFile *F, Kind K)
- : File(F), Live(!Config->GcSections), Discarded(false), SectionKind(K) {}
+ InputChunk(ObjFile *f, Kind k)
+ : file(f), live(!config->gcSections), discarded(false), sectionKind(k) {}
virtual ~InputChunk() = default;
virtual ArrayRef<uint8_t> data() const = 0;
// This is performed only debug builds as an extra sanity check.
void verifyRelocTargets() const;
- ArrayRef<WasmRelocation> Relocations;
- Kind SectionKind;
+ ArrayRef<WasmRelocation> relocations;
+ Kind sectionKind;
};
// Represents a WebAssembly data segment which can be included as part of
// each global variable.
class InputSegment : public InputChunk {
public:
- InputSegment(const WasmSegment &Seg, ObjFile *F)
- : InputChunk(F, InputChunk::DataSegment), Segment(Seg) {}
+ InputSegment(const WasmSegment &seg, ObjFile *f)
+ : InputChunk(f, InputChunk::DataSegment), segment(seg) {}
- static bool classof(const InputChunk *C) { return C->kind() == DataSegment; }
+ static bool classof(const InputChunk *c) { return c->kind() == DataSegment; }
- void generateRelocationCode(raw_ostream &OS) const;
+ void generateRelocationCode(raw_ostream &os) const;
- uint32_t getAlignment() const { return Segment.Data.Alignment; }
- StringRef getName() const override { return Segment.Data.Name; }
+ uint32_t getAlignment() const { return segment.Data.Alignment; }
+ StringRef getName() const override { return segment.Data.Name; }
StringRef getDebugName() const override { return StringRef(); }
- uint32_t getComdat() const override { return Segment.Data.Comdat; }
+ uint32_t getComdat() const override { return segment.Data.Comdat; }
uint32_t getInputSectionOffset() const override {
- return Segment.SectionOffset;
+ return segment.SectionOffset;
}
- const OutputSegment *OutputSeg = nullptr;
- int32_t OutputSegmentOffset = 0;
+ const OutputSegment *outputSeg = nullptr;
+ int32_t outputSegmentOffset = 0;
protected:
- ArrayRef<uint8_t> data() const override { return Segment.Data.Content; }
+ ArrayRef<uint8_t> data() const override { return segment.Data.Content; }
- const WasmSegment &Segment;
+ const WasmSegment &segment;
};
// Represents a single wasm function within and input file. These are
// combined to create the final output CODE section.
class InputFunction : public InputChunk {
public:
- InputFunction(const WasmSignature &S, const WasmFunction *Func, ObjFile *F)
- : InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {}
+ InputFunction(const WasmSignature &s, const WasmFunction *func, ObjFile *f)
+ : InputChunk(f, InputChunk::Function), signature(s), function(func) {}
- static bool classof(const InputChunk *C) {
- return C->kind() == InputChunk::Function ||
- C->kind() == InputChunk::SyntheticFunction;
+ static bool classof(const InputChunk *c) {
+ return c->kind() == InputChunk::Function ||
+ c->kind() == InputChunk::SyntheticFunction;
}
- void writeTo(uint8_t *SectionStart) const override;
- StringRef getName() const override { return Function->SymbolName; }
- StringRef getDebugName() const override { return Function->DebugName; }
- uint32_t getComdat() const override { return Function->Comdat; }
+ void writeTo(uint8_t *sectionStart) const override;
+ StringRef getName() const override { return function->SymbolName; }
+ StringRef getDebugName() const override { return function->DebugName; }
+ uint32_t getComdat() const override { return function->Comdat; }
uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }
- uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; }
+ uint32_t getFunctionCodeOffset() const { return function->CodeOffset; }
uint32_t getSize() const override {
- if (Config->CompressRelocations && File) {
- assert(CompressedSize);
- return CompressedSize;
+ if (config->compressRelocations && file) {
+ assert(compressedSize);
+ return compressedSize;
}
return data().size();
}
- uint32_t getInputSize() const override { return Function->Size; }
- uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); }
- bool hasFunctionIndex() const { return FunctionIndex.hasValue(); }
- void setFunctionIndex(uint32_t Index);
+ uint32_t getInputSize() const override { return function->Size; }
+ uint32_t getFunctionIndex() const { return functionIndex.getValue(); }
+ bool hasFunctionIndex() const { return functionIndex.hasValue(); }
+ void setFunctionIndex(uint32_t index);
uint32_t getInputSectionOffset() const override {
- return Function->CodeSectionOffset;
+ return function->CodeSectionOffset;
}
- uint32_t getTableIndex() const { return TableIndex.getValue(); }
- bool hasTableIndex() const { return TableIndex.hasValue(); }
- void setTableIndex(uint32_t Index);
+ uint32_t getTableIndex() const { return tableIndex.getValue(); }
+ bool hasTableIndex() const { return tableIndex.hasValue(); }
+ void setTableIndex(uint32_t index);
// The size of a given input function can depend on the values of the
// LEB relocations within it. This finalizeContents method is called after
// called.
void calculateSize();
- const WasmSignature &Signature;
+ const WasmSignature &signature;
protected:
ArrayRef<uint8_t> data() const override {
- assert(!Config->CompressRelocations);
- return File->CodeSection->Content.slice(getInputSectionOffset(),
- Function->Size);
+ assert(!config->compressRelocations);
+ return file->codeSection->Content.slice(getInputSectionOffset(),
+ function->Size);
}
- const WasmFunction *Function;
- llvm::Optional<uint32_t> FunctionIndex;
- llvm::Optional<uint32_t> TableIndex;
- uint32_t CompressedFuncSize = 0;
- uint32_t CompressedSize = 0;
+ const WasmFunction *function;
+ llvm::Optional<uint32_t> functionIndex;
+ llvm::Optional<uint32_t> tableIndex;
+ uint32_t compressedFuncSize = 0;
+ uint32_t compressedSize = 0;
};
class SyntheticFunction : public InputFunction {
public:
- SyntheticFunction(const WasmSignature &S, StringRef Name,
- StringRef DebugName = {})
- : InputFunction(S, nullptr, nullptr), Name(Name), DebugName(DebugName) {
- SectionKind = InputChunk::SyntheticFunction;
+ SyntheticFunction(const WasmSignature &s, StringRef name,
+ StringRef debugName = {})
+ : InputFunction(s, nullptr, nullptr), name(name), debugName(debugName) {
+ sectionKind = InputChunk::SyntheticFunction;
}
- static bool classof(const InputChunk *C) {
- return C->kind() == InputChunk::SyntheticFunction;
+ static bool classof(const InputChunk *c) {
+ return c->kind() == InputChunk::SyntheticFunction;
}
- StringRef getName() const override { return Name; }
- StringRef getDebugName() const override { return DebugName; }
+ StringRef getName() const override { return name; }
+ StringRef getDebugName() const override { return debugName; }
uint32_t getComdat() const override { return UINT32_MAX; }
- void setBody(ArrayRef<uint8_t> Body_) { Body = Body_; }
+ void setBody(ArrayRef<uint8_t> body_) { body = body_; }
protected:
- ArrayRef<uint8_t> data() const override { return Body; }
+ ArrayRef<uint8_t> data() const override { return body; }
- StringRef Name;
- StringRef DebugName;
- ArrayRef<uint8_t> Body;
+ StringRef name;
+ StringRef debugName;
+ ArrayRef<uint8_t> body;
};
// Represents a single Wasm Section within an input file.
class InputSection : public InputChunk {
public:
- InputSection(const WasmSection &S, ObjFile *F)
- : InputChunk(F, InputChunk::Section), Section(S) {
- assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM);
+ InputSection(const WasmSection &s, ObjFile *f)
+ : InputChunk(f, InputChunk::Section), section(s) {
+ assert(section.Type == llvm::wasm::WASM_SEC_CUSTOM);
}
- StringRef getName() const override { return Section.Name; }
+ StringRef getName() const override { return section.Name; }
StringRef getDebugName() const override { return StringRef(); }
uint32_t getComdat() const override { return UINT32_MAX; }
- OutputSection *OutputSec = nullptr;
+ OutputSection *outputSec = nullptr;
protected:
- ArrayRef<uint8_t> data() const override { return Section.Content; }
+ ArrayRef<uint8_t> data() const override { return section.Content; }
// Offset within the input section. This is only zero since this chunk
// type represents an entire input section, not part of one.
uint32_t getInputSectionOffset() const override { return 0; }
- const WasmSection &Section;
+ const WasmSection §ion;
};
} // namespace wasm
std::string toString(const wasm::InputChunk *);
-StringRef relocTypeToString(uint8_t RelocType);
+StringRef relocTypeToString(uint8_t relocType);
} // namespace lld
// form the final EVENTS section.
class InputEvent {
public:
- InputEvent(const WasmSignature &S, const WasmEvent &E, ObjFile *F)
- : File(F), Event(E), Signature(S), Live(!Config->GcSections) {}
+ InputEvent(const WasmSignature &s, const WasmEvent &e, ObjFile *f)
+ : file(f), event(e), signature(s), live(!config->gcSections) {}
- StringRef getName() const { return Event.SymbolName; }
- const WasmEventType &getType() const { return Event.Type; }
+ StringRef getName() const { return event.SymbolName; }
+ const WasmEventType &getType() const { return event.Type; }
- uint32_t getEventIndex() const { return EventIndex.getValue(); }
- bool hasEventIndex() const { return EventIndex.hasValue(); }
- void setEventIndex(uint32_t Index) {
+ uint32_t getEventIndex() const { return eventIndex.getValue(); }
+ bool hasEventIndex() const { return eventIndex.hasValue(); }
+ void setEventIndex(uint32_t index) {
assert(!hasEventIndex());
- EventIndex = Index;
+ eventIndex = index;
}
- ObjFile *File;
- WasmEvent Event;
- const WasmSignature &Signature;
+ ObjFile *file;
+ WasmEvent event;
+ const WasmSignature &signature;
- bool Live = false;
+ bool live = false;
protected:
- llvm::Optional<uint32_t> EventIndex;
+ llvm::Optional<uint32_t> eventIndex;
};
} // namespace wasm
-inline std::string toString(const wasm::InputEvent *E) {
- return (toString(E->File) + ":(" + E->getName() + ")").str();
+inline std::string toString(const wasm::InputEvent *e) {
+ return (toString(e->file) + ":(" + e->getName() + ")").str();
}
} // namespace lld
using namespace llvm::object;
using namespace llvm::wasm;
-std::unique_ptr<llvm::TarWriter> lld::wasm::Tar;
+std::unique_ptr<llvm::TarWriter> lld::wasm::tar;
-Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
- log("Loading: " + Path);
+Optional<MemoryBufferRef> lld::wasm::readFile(StringRef path) {
+ log("Loading: " + path);
- auto MBOrErr = MemoryBuffer::getFile(Path);
- if (auto EC = MBOrErr.getError()) {
- error("cannot open " + Path + ": " + EC.message());
+ auto mbOrErr = MemoryBuffer::getFile(path);
+ if (auto ec = mbOrErr.getError()) {
+ error("cannot open " + path + ": " + ec.message());
return None;
}
- std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
- MemoryBufferRef MBRef = MB->getMemBufferRef();
- make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
+ std::unique_ptr<MemoryBuffer> &mb = *mbOrErr;
+ MemoryBufferRef mbref = mb->getMemBufferRef();
+ make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take MB ownership
- if (Tar)
- Tar->append(relativeToRoot(Path), MBRef.getBuffer());
- return MBRef;
+ if (tar)
+ tar->append(relativeToRoot(path), mbref.getBuffer());
+ return mbref;
}
-InputFile *lld::wasm::createObjectFile(MemoryBufferRef MB,
- StringRef ArchiveName) {
- file_magic Magic = identify_magic(MB.getBuffer());
- if (Magic == file_magic::wasm_object) {
- std::unique_ptr<Binary> Bin =
- CHECK(createBinary(MB), MB.getBufferIdentifier());
- auto *Obj = cast<WasmObjectFile>(Bin.get());
- if (Obj->isSharedObject())
- return make<SharedFile>(MB);
- return make<ObjFile>(MB, ArchiveName);
+InputFile *lld::wasm::createObjectFile(MemoryBufferRef mb,
+ StringRef archiveName) {
+ file_magic magic = identify_magic(mb.getBuffer());
+ if (magic == file_magic::wasm_object) {
+ std::unique_ptr<Binary> bin =
+ CHECK(createBinary(mb), mb.getBufferIdentifier());
+ auto *obj = cast<WasmObjectFile>(bin.get());
+ if (obj->isSharedObject())
+ return make<SharedFile>(mb);
+ return make<ObjFile>(mb, archiveName);
}
- if (Magic == file_magic::bitcode)
- return make<BitcodeFile>(MB, ArchiveName);
+ if (magic == file_magic::bitcode)
+ return make<BitcodeFile>(mb, archiveName);
- fatal("unknown file type: " + MB.getBufferIdentifier());
+ fatal("unknown file type: " + mb.getBufferIdentifier());
}
void ObjFile::dumpInfo() const {
log("info for: " + toString(this) +
- "\n Symbols : " + Twine(Symbols.size()) +
- "\n Function Imports : " + Twine(WasmObj->getNumImportedFunctions()) +
- "\n Global Imports : " + Twine(WasmObj->getNumImportedGlobals()) +
- "\n Event Imports : " + Twine(WasmObj->getNumImportedEvents()));
+ "\n Symbols : " + Twine(symbols.size()) +
+ "\n Function Imports : " + Twine(wasmObj->getNumImportedFunctions()) +
+ "\n Global Imports : " + Twine(wasmObj->getNumImportedGlobals()) +
+ "\n Event Imports : " + Twine(wasmObj->getNumImportedEvents()));
}
// Relocations contain either symbol or type indices. This function takes a
// relocation and returns relocated index (i.e. translates from the input
// symbol/type space to the output symbol/type space).
-uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const {
- if (Reloc.Type == R_WASM_TYPE_INDEX_LEB) {
- assert(TypeIsUsed[Reloc.Index]);
- return TypeMap[Reloc.Index];
+uint32_t ObjFile::calcNewIndex(const WasmRelocation &reloc) const {
+ if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {
+ assert(typeIsUsed[reloc.Index]);
+ return typeMap[reloc.Index];
}
- const Symbol *Sym = Symbols[Reloc.Index];
- if (auto *SS = dyn_cast<SectionSymbol>(Sym))
- Sym = SS->getOutputSectionSymbol();
- return Sym->getOutputSymbolIndex();
+ const Symbol *sym = symbols[reloc.Index];
+ if (auto *ss = dyn_cast<SectionSymbol>(sym))
+ sym = ss->getOutputSectionSymbol();
+ return sym->getOutputSymbolIndex();
}
// Relocations can contain addend for combined sections. This function takes a
// relocation and returns updated addend by offset in the output section.
-uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const {
- switch (Reloc.Type) {
+uint32_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const {
+ switch (reloc.Type) {
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_REL_SLEB:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_FUNCTION_OFFSET_I32:
- return Reloc.Addend;
+ return reloc.Addend;
case R_WASM_SECTION_OFFSET_I32:
- return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
+ return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend;
default:
llvm_unreachable("unexpected relocation type");
}
// Calculate the value we expect to find at the relocation location.
// This is used as a sanity check before applying a relocation to a given
// location. It is useful for catching bugs in the compiler and linker.
-uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const {
- switch (Reloc.Type) {
+uint32_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
+ switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB: {
- const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
- return TableEntries[Sym.Info.ElementIndex];
+ const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
+ return tableEntries[sym.Info.ElementIndex];
}
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_REL_SLEB: {
- const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
- if (Sym.isUndefined())
+ const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
+ if (sym.isUndefined())
return 0;
- const WasmSegment &Segment =
- WasmObj->dataSegments()[Sym.Info.DataRef.Segment];
- return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset +
- Reloc.Addend;
+ const WasmSegment &segment =
+ wasmObj->dataSegments()[sym.Info.DataRef.Segment];
+ return segment.Data.Offset.Value.Int32 + sym.Info.DataRef.Offset +
+ reloc.Addend;
}
case R_WASM_FUNCTION_OFFSET_I32: {
- const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
- InputFunction *F =
- Functions[Sym.Info.ElementIndex - WasmObj->getNumImportedFunctions()];
- return F->getFunctionInputOffset() + F->getFunctionCodeOffset() +
- Reloc.Addend;
+ const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
+ InputFunction *f =
+ functions[sym.Info.ElementIndex - wasmObj->getNumImportedFunctions()];
+ return f->getFunctionInputOffset() + f->getFunctionCodeOffset() +
+ reloc.Addend;
}
case R_WASM_SECTION_OFFSET_I32:
- return Reloc.Addend;
+ return reloc.Addend;
case R_WASM_TYPE_INDEX_LEB:
- return Reloc.Index;
+ return reloc.Index;
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB: {
- const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
- return Sym.Info.ElementIndex;
+ const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
+ return sym.Info.ElementIndex;
}
default:
llvm_unreachable("unknown relocation type");
}
// Translate from the relocation's index into the final linked output value.
-uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
- const Symbol* Sym = nullptr;
- if (Reloc.Type != R_WASM_TYPE_INDEX_LEB) {
- Sym = Symbols[Reloc.Index];
+uint32_t ObjFile::calcNewValue(const WasmRelocation &reloc) const {
+ const Symbol* sym = nullptr;
+ if (reloc.Type != R_WASM_TYPE_INDEX_LEB) {
+ sym = symbols[reloc.Index];
// We can end up with relocations against non-live symbols. For example
// in debug sections.
- if ((isa<FunctionSymbol>(Sym) || isa<DataSymbol>(Sym)) && !Sym->isLive())
+ if ((isa<FunctionSymbol>(sym) || isa<DataSymbol>(sym)) && !sym->isLive())
return 0;
}
- switch (Reloc.Type) {
+ switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB:
- if (Config->Pic && !getFunctionSymbol(Reloc.Index)->hasTableIndex())
+ if (config->isPic && !getFunctionSymbol(reloc.Index)->hasTableIndex())
return 0;
- return getFunctionSymbol(Reloc.Index)->getTableIndex();
+ return getFunctionSymbol(reloc.Index)->getTableIndex();
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_I32:
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_REL_SLEB:
- if (isa<UndefinedData>(Sym))
+ if (isa<UndefinedData>(sym))
return 0;
- return cast<DefinedData>(Sym)->getVirtualAddress() + Reloc.Addend;
+ return cast<DefinedData>(sym)->getVirtualAddress() + reloc.Addend;
case R_WASM_TYPE_INDEX_LEB:
- return TypeMap[Reloc.Index];
+ return typeMap[reloc.Index];
case R_WASM_FUNCTION_INDEX_LEB:
- return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
+ return getFunctionSymbol(reloc.Index)->getFunctionIndex();
case R_WASM_GLOBAL_INDEX_LEB:
- if (auto GS = dyn_cast<GlobalSymbol>(Sym))
- return GS->getGlobalIndex();
- return Sym->getGOTIndex();
+ if (auto gs = dyn_cast<GlobalSymbol>(sym))
+ return gs->getGlobalIndex();
+ return sym->getGOTIndex();
case R_WASM_EVENT_INDEX_LEB:
- return getEventSymbol(Reloc.Index)->getEventIndex();
+ return getEventSymbol(reloc.Index)->getEventIndex();
case R_WASM_FUNCTION_OFFSET_I32: {
- auto *F = cast<DefinedFunction>(Sym);
- return F->Function->OutputOffset + F->Function->getFunctionCodeOffset() +
- Reloc.Addend;
+ auto *f = cast<DefinedFunction>(sym);
+ return f->function->outputOffset + f->function->getFunctionCodeOffset() +
+ reloc.Addend;
}
case R_WASM_SECTION_OFFSET_I32:
- return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
+ return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend;
default:
llvm_unreachable("unknown relocation type");
}
}
template <class T>
-static void setRelocs(const std::vector<T *> &Chunks,
- const WasmSection *Section) {
- if (!Section)
+static void setRelocs(const std::vector<T *> &chunks,
+ const WasmSection *section) {
+ if (!section)
return;
- ArrayRef<WasmRelocation> Relocs = Section->Relocations;
- assert(std::is_sorted(Relocs.begin(), Relocs.end(),
- [](const WasmRelocation &R1, const WasmRelocation &R2) {
- return R1.Offset < R2.Offset;
+ ArrayRef<WasmRelocation> relocs = section->Relocations;
+ assert(std::is_sorted(relocs.begin(), relocs.end(),
+ [](const WasmRelocation &r1, const WasmRelocation &r2) {
+ return r1.Offset < r2.Offset;
}));
assert(std::is_sorted(
- Chunks.begin(), Chunks.end(), [](InputChunk *C1, InputChunk *C2) {
- return C1->getInputSectionOffset() < C2->getInputSectionOffset();
+ chunks.begin(), chunks.end(), [](InputChunk *c1, InputChunk *c2) {
+ return c1->getInputSectionOffset() < c2->getInputSectionOffset();
}));
- auto RelocsNext = Relocs.begin();
- auto RelocsEnd = Relocs.end();
- auto RelocLess = [](const WasmRelocation &R, uint32_t Val) {
- return R.Offset < Val;
+ auto relocsNext = relocs.begin();
+ auto relocsEnd = relocs.end();
+ auto relocLess = [](const WasmRelocation &r, uint32_t val) {
+ return r.Offset < val;
};
- for (InputChunk *C : Chunks) {
- auto RelocsStart = std::lower_bound(RelocsNext, RelocsEnd,
- C->getInputSectionOffset(), RelocLess);
- RelocsNext = std::lower_bound(
- RelocsStart, RelocsEnd, C->getInputSectionOffset() + C->getInputSize(),
- RelocLess);
- C->setRelocations(ArrayRef<WasmRelocation>(RelocsStart, RelocsNext));
+ for (InputChunk *c : chunks) {
+ auto relocsStart = std::lower_bound(relocsNext, relocsEnd,
+ c->getInputSectionOffset(), relocLess);
+ relocsNext = std::lower_bound(
+ relocsStart, relocsEnd, c->getInputSectionOffset() + c->getInputSize(),
+ relocLess);
+ c->setRelocations(ArrayRef<WasmRelocation>(relocsStart, relocsNext));
}
}
-void ObjFile::parse(bool IgnoreComdats) {
+void ObjFile::parse(bool ignoreComdats) {
// Parse a memory buffer as a wasm file.
LLVM_DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
- std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), toString(this));
+ std::unique_ptr<Binary> bin = CHECK(createBinary(mb), toString(this));
- auto *Obj = dyn_cast<WasmObjectFile>(Bin.get());
- if (!Obj)
+ auto *obj = dyn_cast<WasmObjectFile>(bin.get());
+ if (!obj)
fatal(toString(this) + ": not a wasm file");
- if (!Obj->isRelocatableObject())
+ if (!obj->isRelocatableObject())
fatal(toString(this) + ": not a relocatable wasm file");
- Bin.release();
- WasmObj.reset(Obj);
+ bin.release();
+ wasmObj.reset(obj);
// Build up a map of function indices to table indices for use when
// verifying the existing table index relocations
- uint32_t TotalFunctions =
- WasmObj->getNumImportedFunctions() + WasmObj->functions().size();
- TableEntries.resize(TotalFunctions);
- for (const WasmElemSegment &Seg : WasmObj->elements()) {
- if (Seg.Offset.Opcode != WASM_OPCODE_I32_CONST)
+ uint32_t totalFunctions =
+ wasmObj->getNumImportedFunctions() + wasmObj->functions().size();
+ tableEntries.resize(totalFunctions);
+ for (const WasmElemSegment &seg : wasmObj->elements()) {
+ if (seg.Offset.Opcode != WASM_OPCODE_I32_CONST)
fatal(toString(this) + ": invalid table elements");
- uint32_t Offset = Seg.Offset.Value.Int32;
- for (uint32_t Index = 0; Index < Seg.Functions.size(); Index++) {
+ uint32_t offset = seg.Offset.Value.Int32;
+ for (uint32_t index = 0; index < seg.Functions.size(); index++) {
- uint32_t FunctionIndex = Seg.Functions[Index];
- TableEntries[FunctionIndex] = Offset + Index;
+ uint32_t functionIndex = seg.Functions[index];
+ tableEntries[functionIndex] = offset + index;
}
}
- uint32_t SectionIndex = 0;
+ uint32_t sectionIndex = 0;
// Bool for each symbol, true if called directly. This allows us to implement
// a weaker form of signature checking where undefined functions that are not
// function's signature. We cannot do this for directly called functions
// because those signatures are checked at validation times.
// See https://bugs.llvm.org/show_bug.cgi?id=40412
- std::vector<bool> IsCalledDirectly(WasmObj->getNumberOfSymbols(), false);
- for (const SectionRef &Sec : WasmObj->sections()) {
- const WasmSection &Section = WasmObj->getWasmSection(Sec);
+ std::vector<bool> isCalledDirectly(wasmObj->getNumberOfSymbols(), false);
+ for (const SectionRef &sec : wasmObj->sections()) {
+ const WasmSection §ion = wasmObj->getWasmSection(sec);
// Wasm objects can have at most one code and one data section.
- if (Section.Type == WASM_SEC_CODE) {
- assert(!CodeSection);
- CodeSection = &Section;
- } else if (Section.Type == WASM_SEC_DATA) {
- assert(!DataSection);
- DataSection = &Section;
- } else if (Section.Type == WASM_SEC_CUSTOM) {
- CustomSections.emplace_back(make<InputSection>(Section, this));
- CustomSections.back()->setRelocations(Section.Relocations);
- CustomSectionsByIndex[SectionIndex] = CustomSections.back();
+ if (section.Type == WASM_SEC_CODE) {
+ assert(!codeSection);
+ codeSection = §ion;
+ } else if (section.Type == WASM_SEC_DATA) {
+ assert(!dataSection);
+ dataSection = §ion;
+ } else if (section.Type == WASM_SEC_CUSTOM) {
+ customSections.emplace_back(make<InputSection>(section, this));
+ customSections.back()->setRelocations(section.Relocations);
+ customSectionsByIndex[sectionIndex] = customSections.back();
}
- SectionIndex++;
+ sectionIndex++;
// Scans relocations to dermine determine if a function symbol is called
// directly
- for (const WasmRelocation &Reloc : Section.Relocations)
- if (Reloc.Type == R_WASM_FUNCTION_INDEX_LEB)
- IsCalledDirectly[Reloc.Index] = true;
+ for (const WasmRelocation &reloc : section.Relocations)
+ if (reloc.Type == R_WASM_FUNCTION_INDEX_LEB)
+ isCalledDirectly[reloc.Index] = true;
}
- TypeMap.resize(getWasmObj()->types().size());
- TypeIsUsed.resize(getWasmObj()->types().size(), false);
+ typeMap.resize(getWasmObj()->types().size());
+ typeIsUsed.resize(getWasmObj()->types().size(), false);
- ArrayRef<StringRef> Comdats = WasmObj->linkingData().Comdats;
- for (StringRef Comdat : Comdats) {
- bool IsNew = IgnoreComdats || Symtab->addComdat(Comdat);
- KeptComdats.push_back(IsNew);
+ ArrayRef<StringRef> comdats = wasmObj->linkingData().Comdats;
+ for (StringRef comdat : comdats) {
+ bool isNew = ignoreComdats || symtab->addComdat(comdat);
+ keptComdats.push_back(isNew);
}
// Populate `Segments`.
- for (const WasmSegment &S : WasmObj->dataSegments()) {
- auto* Seg = make<InputSegment>(S, this);
- Seg->Discarded = isExcludedByComdat(Seg);
- Segments.emplace_back(Seg);
+ for (const WasmSegment &s : wasmObj->dataSegments()) {
+ auto* seg = make<InputSegment>(s, this);
+ seg->discarded = isExcludedByComdat(seg);
+ segments.emplace_back(seg);
}
- setRelocs(Segments, DataSection);
+ setRelocs(segments, dataSection);
// Populate `Functions`.
- ArrayRef<WasmFunction> Funcs = WasmObj->functions();
- ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
- ArrayRef<WasmSignature> Types = WasmObj->types();
- Functions.reserve(Funcs.size());
-
- for (size_t I = 0, E = Funcs.size(); I != E; ++I) {
- auto* Func = make<InputFunction>(Types[FuncTypes[I]], &Funcs[I], this);
- Func->Discarded = isExcludedByComdat(Func);
- Functions.emplace_back(Func);
+ ArrayRef<WasmFunction> funcs = wasmObj->functions();
+ ArrayRef<uint32_t> funcTypes = wasmObj->functionTypes();
+ ArrayRef<WasmSignature> types = wasmObj->types();
+ functions.reserve(funcs.size());
+
+ for (size_t i = 0, e = funcs.size(); i != e; ++i) {
+ auto* func = make<InputFunction>(types[funcTypes[i]], &funcs[i], this);
+ func->discarded = isExcludedByComdat(func);
+ functions.emplace_back(func);
}
- setRelocs(Functions, CodeSection);
+ setRelocs(functions, codeSection);
// Populate `Globals`.
- for (const WasmGlobal &G : WasmObj->globals())
- Globals.emplace_back(make<InputGlobal>(G, this));
+ for (const WasmGlobal &g : wasmObj->globals())
+ globals.emplace_back(make<InputGlobal>(g, this));
// Populate `Events`.
- for (const WasmEvent &E : WasmObj->events())
- Events.emplace_back(make<InputEvent>(Types[E.Type.SigIndex], E, this));
+ for (const WasmEvent &e : wasmObj->events())
+ events.emplace_back(make<InputEvent>(types[e.Type.SigIndex], e, this));
// Populate `Symbols` based on the WasmSymbols in the object.
- Symbols.reserve(WasmObj->getNumberOfSymbols());
- for (const SymbolRef &Sym : WasmObj->symbols()) {
- const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
- if (WasmSym.isDefined()) {
+ symbols.reserve(wasmObj->getNumberOfSymbols());
+ for (const SymbolRef &sym : wasmObj->symbols()) {
+ const WasmSymbol &wasmSym = wasmObj->getWasmSymbol(sym.getRawDataRefImpl());
+ if (wasmSym.isDefined()) {
// createDefined may fail if the symbol is comdat excluded in which case
// we fall back to creating an undefined symbol
- if (Symbol *D = createDefined(WasmSym)) {
- Symbols.push_back(D);
+ if (Symbol *d = createDefined(wasmSym)) {
+ symbols.push_back(d);
continue;
}
}
- size_t Idx = Symbols.size();
- Symbols.push_back(createUndefined(WasmSym, IsCalledDirectly[Idx]));
+ size_t idx = symbols.size();
+ symbols.push_back(createUndefined(wasmSym, isCalledDirectly[idx]));
}
}
-bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const {
- uint32_t C = Chunk->getComdat();
- if (C == UINT32_MAX)
+bool ObjFile::isExcludedByComdat(InputChunk *chunk) const {
+ uint32_t c = chunk->getComdat();
+ if (c == UINT32_MAX)
return false;
- return !KeptComdats[C];
+ return !keptComdats[c];
}
-FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t Index) const {
- return cast<FunctionSymbol>(Symbols[Index]);
+FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t index) const {
+ return cast<FunctionSymbol>(symbols[index]);
}
-GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
- return cast<GlobalSymbol>(Symbols[Index]);
+GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t index) const {
+ return cast<GlobalSymbol>(symbols[index]);
}
-EventSymbol *ObjFile::getEventSymbol(uint32_t Index) const {
- return cast<EventSymbol>(Symbols[Index]);
+EventSymbol *ObjFile::getEventSymbol(uint32_t index) const {
+ return cast<EventSymbol>(symbols[index]);
}
-SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const {
- return cast<SectionSymbol>(Symbols[Index]);
+SectionSymbol *ObjFile::getSectionSymbol(uint32_t index) const {
+ return cast<SectionSymbol>(symbols[index]);
}
-DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const {
- return cast<DataSymbol>(Symbols[Index]);
+DataSymbol *ObjFile::getDataSymbol(uint32_t index) const {
+ return cast<DataSymbol>(symbols[index]);
}
-Symbol *ObjFile::createDefined(const WasmSymbol &Sym) {
- StringRef Name = Sym.Info.Name;
- uint32_t Flags = Sym.Info.Flags;
+Symbol *ObjFile::createDefined(const WasmSymbol &sym) {
+ StringRef name = sym.Info.Name;
+ uint32_t flags = sym.Info.Flags;
- switch (Sym.Info.Kind) {
+ switch (sym.Info.Kind) {
case WASM_SYMBOL_TYPE_FUNCTION: {
- InputFunction *Func =
- Functions[Sym.Info.ElementIndex - WasmObj->getNumImportedFunctions()];
- if (Func->Discarded)
+ InputFunction *func =
+ functions[sym.Info.ElementIndex - wasmObj->getNumImportedFunctions()];
+ if (func->discarded)
return nullptr;
- if (Sym.isBindingLocal())
- return make<DefinedFunction>(Name, Flags, this, Func);
- return Symtab->addDefinedFunction(Name, Flags, this, Func);
+ if (sym.isBindingLocal())
+ return make<DefinedFunction>(name, flags, this, func);
+ return symtab->addDefinedFunction(name, flags, this, func);
}
case WASM_SYMBOL_TYPE_DATA: {
- InputSegment *Seg = Segments[Sym.Info.DataRef.Segment];
- if (Seg->Discarded)
+ InputSegment *seg = segments[sym.Info.DataRef.Segment];
+ if (seg->discarded)
return nullptr;
- uint32_t Offset = Sym.Info.DataRef.Offset;
- uint32_t Size = Sym.Info.DataRef.Size;
+ uint32_t offset = sym.Info.DataRef.Offset;
+ uint32_t size = sym.Info.DataRef.Size;
- if (Sym.isBindingLocal())
- return make<DefinedData>(Name, Flags, this, Seg, Offset, Size);
- return Symtab->addDefinedData(Name, Flags, this, Seg, Offset, Size);
+ if (sym.isBindingLocal())
+ return make<DefinedData>(name, flags, this, seg, offset, size);
+ return symtab->addDefinedData(name, flags, this, seg, offset, size);
}
case WASM_SYMBOL_TYPE_GLOBAL: {
- InputGlobal *Global =
- Globals[Sym.Info.ElementIndex - WasmObj->getNumImportedGlobals()];
- if (Sym.isBindingLocal())
- return make<DefinedGlobal>(Name, Flags, this, Global);
- return Symtab->addDefinedGlobal(Name, Flags, this, Global);
+ InputGlobal *global =
+ globals[sym.Info.ElementIndex - wasmObj->getNumImportedGlobals()];
+ if (sym.isBindingLocal())
+ return make<DefinedGlobal>(name, flags, this, global);
+ return symtab->addDefinedGlobal(name, flags, this, global);
}
case WASM_SYMBOL_TYPE_SECTION: {
- InputSection *Section = CustomSectionsByIndex[Sym.Info.ElementIndex];
- assert(Sym.isBindingLocal());
- return make<SectionSymbol>(Flags, Section, this);
+ InputSection *section = customSectionsByIndex[sym.Info.ElementIndex];
+ assert(sym.isBindingLocal());
+ return make<SectionSymbol>(flags, section, this);
}
case WASM_SYMBOL_TYPE_EVENT: {
- InputEvent *Event =
- Events[Sym.Info.ElementIndex - WasmObj->getNumImportedEvents()];
- if (Sym.isBindingLocal())
- return make<DefinedEvent>(Name, Flags, this, Event);
- return Symtab->addDefinedEvent(Name, Flags, this, Event);
+ InputEvent *event =
+ events[sym.Info.ElementIndex - wasmObj->getNumImportedEvents()];
+ if (sym.isBindingLocal())
+ return make<DefinedEvent>(name, flags, this, event);
+ return symtab->addDefinedEvent(name, flags, this, event);
}
}
llvm_unreachable("unknown symbol kind");
}
-Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, bool IsCalledDirectly) {
- StringRef Name = Sym.Info.Name;
- uint32_t Flags = Sym.Info.Flags;
+Symbol *ObjFile::createUndefined(const WasmSymbol &sym, bool isCalledDirectly) {
+ StringRef name = sym.Info.Name;
+ uint32_t flags = sym.Info.Flags;
- switch (Sym.Info.Kind) {
+ switch (sym.Info.Kind) {
case WASM_SYMBOL_TYPE_FUNCTION:
- if (Sym.isBindingLocal())
- return make<UndefinedFunction>(Name, Sym.Info.ImportName,
- Sym.Info.ImportModule, Flags, this,
- Sym.Signature, IsCalledDirectly);
- return Symtab->addUndefinedFunction(Name, Sym.Info.ImportName,
- Sym.Info.ImportModule, Flags, this,
- Sym.Signature, IsCalledDirectly);
+ if (sym.isBindingLocal())
+ return make<UndefinedFunction>(name, sym.Info.ImportName,
+ sym.Info.ImportModule, flags, this,
+ sym.Signature, isCalledDirectly);
+ return symtab->addUndefinedFunction(name, sym.Info.ImportName,
+ sym.Info.ImportModule, flags, this,
+ sym.Signature, isCalledDirectly);
case WASM_SYMBOL_TYPE_DATA:
- if (Sym.isBindingLocal())
- return make<UndefinedData>(Name, Flags, this);
- return Symtab->addUndefinedData(Name, Flags, this);
+ if (sym.isBindingLocal())
+ return make<UndefinedData>(name, flags, this);
+ return symtab->addUndefinedData(name, flags, this);
case WASM_SYMBOL_TYPE_GLOBAL:
- if (Sym.isBindingLocal())
- return make<UndefinedGlobal>(Name, Sym.Info.ImportName,
- Sym.Info.ImportModule, Flags, this,
- Sym.GlobalType);
- return Symtab->addUndefinedGlobal(Name, Sym.Info.ImportName,
- Sym.Info.ImportModule, Flags, this,
- Sym.GlobalType);
+ if (sym.isBindingLocal())
+ return make<UndefinedGlobal>(name, sym.Info.ImportName,
+ sym.Info.ImportModule, flags, this,
+ sym.GlobalType);
+ return symtab->addUndefinedGlobal(name, sym.Info.ImportName,
+ sym.Info.ImportModule, flags, this,
+ sym.GlobalType);
case WASM_SYMBOL_TYPE_SECTION:
llvm_unreachable("section symbols cannot be undefined");
}
void ArchiveFile::parse() {
// Parse a MemoryBufferRef as an archive file.
LLVM_DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n");
- File = CHECK(Archive::create(MB), toString(this));
+ file = CHECK(Archive::create(mb), toString(this));
// Read the symbol table to construct Lazy symbols.
- int Count = 0;
- for (const Archive::Symbol &Sym : File->symbols()) {
- Symtab->addLazy(this, &Sym);
- ++Count;
+ int count = 0;
+ for (const Archive::Symbol &sym : file->symbols()) {
+ symtab->addLazy(this, &sym);
+ ++count;
}
- LLVM_DEBUG(dbgs() << "Read " << Count << " symbols\n");
+ LLVM_DEBUG(dbgs() << "Read " << count << " symbols\n");
}
-void ArchiveFile::addMember(const Archive::Symbol *Sym) {
- const Archive::Child &C =
- CHECK(Sym->getMember(),
- "could not get the member for symbol " + Sym->getName());
+void ArchiveFile::addMember(const Archive::Symbol *sym) {
+ const Archive::Child &c =
+ CHECK(sym->getMember(),
+ "could not get the member for symbol " + sym->getName());
// Don't try to load the same member twice (this can happen when members
// mutually reference each other).
- if (!Seen.insert(C.getChildOffset()).second)
+ if (!seen.insert(c.getChildOffset()).second)
return;
- LLVM_DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n");
+ LLVM_DEBUG(dbgs() << "loading lazy: " << sym->getName() << "\n");
LLVM_DEBUG(dbgs() << "from archive: " << toString(this) << "\n");
- MemoryBufferRef MB =
- CHECK(C.getMemoryBufferRef(),
+ MemoryBufferRef mb =
+ CHECK(c.getMemoryBufferRef(),
"could not get the buffer for the member defining symbol " +
- Sym->getName());
+ sym->getName());
- InputFile *Obj = createObjectFile(MB, getName());
- Symtab->addFile(Obj);
+ InputFile *obj = createObjectFile(mb, getName());
+ symtab->addFile(obj);
}
-static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
- switch (GvVisibility) {
+static uint8_t mapVisibility(GlobalValue::VisibilityTypes gvVisibility) {
+ switch (gvVisibility) {
case GlobalValue::DefaultVisibility:
return WASM_SYMBOL_VISIBILITY_DEFAULT;
case GlobalValue::HiddenVisibility:
llvm_unreachable("unknown visibility");
}
-static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
- const lto::InputFile::Symbol &ObjSym,
- BitcodeFile &F) {
- StringRef Name = Saver.save(ObjSym.getName());
+static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,
+ const lto::InputFile::Symbol &objSym,
+ BitcodeFile &f) {
+ StringRef name = saver.save(objSym.getName());
- uint32_t Flags = ObjSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0;
- Flags |= mapVisibility(ObjSym.getVisibility());
+ uint32_t flags = objSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0;
+ flags |= mapVisibility(objSym.getVisibility());
- int C = ObjSym.getComdatIndex();
- bool ExcludedByComdat = C != -1 && !KeptComdats[C];
+ int c = objSym.getComdatIndex();
+ bool excludedByComdat = c != -1 && !keptComdats[c];
- if (ObjSym.isUndefined() || ExcludedByComdat) {
- if (ObjSym.isExecutable())
- return Symtab->addUndefinedFunction(Name, Name, DefaultModule, Flags, &F,
+ if (objSym.isUndefined() || excludedByComdat) {
+ if (objSym.isExecutable())
+ return symtab->addUndefinedFunction(name, name, defaultModule, flags, &f,
nullptr, true);
- return Symtab->addUndefinedData(Name, Flags, &F);
+ return symtab->addUndefinedData(name, flags, &f);
}
- if (ObjSym.isExecutable())
- return Symtab->addDefinedFunction(Name, Flags, &F, nullptr);
- return Symtab->addDefinedData(Name, Flags, &F, nullptr, 0, 0);
+ if (objSym.isExecutable())
+ return symtab->addDefinedFunction(name, flags, &f, nullptr);
+ return symtab->addDefinedData(name, flags, &f, nullptr, 0, 0);
}
void BitcodeFile::parse() {
- Obj = check(lto::InputFile::create(MemoryBufferRef(
- MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier()))));
- Triple T(Obj->getTargetTriple());
- if (T.getArch() != Triple::wasm32) {
- error(toString(MB.getBufferIdentifier()) + ": machine type must be wasm32");
+ obj = check(lto::InputFile::create(MemoryBufferRef(
+ mb.getBuffer(), saver.save(archiveName + mb.getBufferIdentifier()))));
+ Triple t(obj->getTargetTriple());
+ if (t.getArch() != Triple::wasm32) {
+ error(toString(mb.getBufferIdentifier()) + ": machine type must be wasm32");
return;
}
- std::vector<bool> KeptComdats;
- for (StringRef S : Obj->getComdatTable())
- KeptComdats.push_back(Symtab->addComdat(S));
+ std::vector<bool> keptComdats;
+ for (StringRef s : obj->getComdatTable())
+ keptComdats.push_back(symtab->addComdat(s));
- for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
- Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, *this));
+ for (const lto::InputFile::Symbol &objSym : obj->symbols())
+ symbols.push_back(createBitcodeSymbol(keptComdats, objSym, *this));
}
// Returns a string in the format of "foo.o" or "foo.a(bar.o)".
-std::string lld::toString(const wasm::InputFile *File) {
- if (!File)
+std::string lld::toString(const wasm::InputFile *file) {
+ if (!file)
return "<internal>";
- if (File->ArchiveName.empty())
- return File->getName();
+ if (file->archiveName.empty())
+ return file->getName();
- return (File->ArchiveName + "(" + File->getName() + ")").str();
+ return (file->archiveName + "(" + file->getName() + ")").str();
}
// If --reproduce option is given, all input files are written
// to this tar archive.
-extern std::unique_ptr<llvm::TarWriter> Tar;
+extern std::unique_ptr<llvm::TarWriter> tar;
class InputFile {
public:
virtual ~InputFile() {}
// Returns the filename.
- StringRef getName() const { return MB.getBufferIdentifier(); }
+ StringRef getName() const { return mb.getBufferIdentifier(); }
- Kind kind() const { return FileKind; }
+ Kind kind() const { return fileKind; }
// An archive file name if this file is created from an archive.
- StringRef ArchiveName;
+ StringRef archiveName;
- ArrayRef<Symbol *> getSymbols() const { return Symbols; }
+ ArrayRef<Symbol *> getSymbols() const { return symbols; }
- MutableArrayRef<Symbol *> getMutableSymbols() { return Symbols; }
+ MutableArrayRef<Symbol *> getMutableSymbols() { return symbols; }
protected:
- InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
- MemoryBufferRef MB;
+ InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {}
+ MemoryBufferRef mb;
// List of all symbols referenced or defined by this file.
- std::vector<Symbol *> Symbols;
+ std::vector<Symbol *> symbols;
private:
- const Kind FileKind;
+ const Kind fileKind;
};
// .a file (ar archive)
class ArchiveFile : public InputFile {
public:
- explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
- static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+ explicit ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
+ static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
- void addMember(const llvm::object::Archive::Symbol *Sym);
+ void addMember(const llvm::object::Archive::Symbol *sym);
void parse();
private:
- std::unique_ptr<llvm::object::Archive> File;
- llvm::DenseSet<uint64_t> Seen;
+ std::unique_ptr<llvm::object::Archive> file;
+ llvm::DenseSet<uint64_t> seen;
};
// .o file (wasm object file)
class ObjFile : public InputFile {
public:
- explicit ObjFile(MemoryBufferRef M, StringRef ArchiveName)
- : InputFile(ObjectKind, M) {
- this->ArchiveName = ArchiveName;
+ explicit ObjFile(MemoryBufferRef m, StringRef archiveName)
+ : InputFile(ObjectKind, m) {
+ this->archiveName = archiveName;
}
- static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
+ static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
- void parse(bool IgnoreComdats = false);
+ void parse(bool ignoreComdats = false);
// Returns the underlying wasm file.
- const WasmObjectFile *getWasmObj() const { return WasmObj.get(); }
+ const WasmObjectFile *getWasmObj() const { return wasmObj.get(); }
void dumpInfo() const;
- uint32_t calcNewIndex(const WasmRelocation &Reloc) const;
- uint32_t calcNewValue(const WasmRelocation &Reloc) const;
- uint32_t calcNewAddend(const WasmRelocation &Reloc) const;
- uint32_t calcExpectedValue(const WasmRelocation &Reloc) const;
- Symbol *getSymbol(const WasmRelocation &Reloc) const {
- return Symbols[Reloc.Index];
+ uint32_t calcNewIndex(const WasmRelocation &reloc) const;
+ uint32_t calcNewValue(const WasmRelocation &reloc) const;
+ uint32_t calcNewAddend(const WasmRelocation &reloc) const;
+ uint32_t calcExpectedValue(const WasmRelocation &reloc) const;
+ Symbol *getSymbol(const WasmRelocation &reloc) const {
+ return symbols[reloc.Index];
};
- const WasmSection *CodeSection = nullptr;
- const WasmSection *DataSection = nullptr;
+ const WasmSection *codeSection = nullptr;
+ const WasmSection *dataSection = nullptr;
// Maps input type indices to output type indices
- std::vector<uint32_t> TypeMap;
- std::vector<bool> TypeIsUsed;
+ std::vector<uint32_t> typeMap;
+ std::vector<bool> typeIsUsed;
// Maps function indices to table indices
- std::vector<uint32_t> TableEntries;
- std::vector<bool> KeptComdats;
- std::vector<InputSegment *> Segments;
- std::vector<InputFunction *> Functions;
- std::vector<InputGlobal *> Globals;
- std::vector<InputEvent *> Events;
- std::vector<InputSection *> CustomSections;
- llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex;
-
- Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; }
- FunctionSymbol *getFunctionSymbol(uint32_t Index) const;
- DataSymbol *getDataSymbol(uint32_t Index) const;
- GlobalSymbol *getGlobalSymbol(uint32_t Index) const;
- SectionSymbol *getSectionSymbol(uint32_t Index) const;
- EventSymbol *getEventSymbol(uint32_t Index) const;
+ std::vector<uint32_t> tableEntries;
+ std::vector<bool> keptComdats;
+ std::vector<InputSegment *> segments;
+ std::vector<InputFunction *> functions;
+ std::vector<InputGlobal *> globals;
+ std::vector<InputEvent *> events;
+ std::vector<InputSection *> customSections;
+ llvm::DenseMap<uint32_t, InputSection *> customSectionsByIndex;
+
+ Symbol *getSymbol(uint32_t index) const { return symbols[index]; }
+ FunctionSymbol *getFunctionSymbol(uint32_t index) const;
+ DataSymbol *getDataSymbol(uint32_t index) const;
+ GlobalSymbol *getGlobalSymbol(uint32_t index) const;
+ SectionSymbol *getSectionSymbol(uint32_t index) const;
+ EventSymbol *getEventSymbol(uint32_t index) const;
private:
- Symbol *createDefined(const WasmSymbol &Sym);
- Symbol *createUndefined(const WasmSymbol &Sym, bool IsCalledDirectly);
+ Symbol *createDefined(const WasmSymbol &sym);
+ Symbol *createUndefined(const WasmSymbol &sym, bool isCalledDirectly);
- bool isExcludedByComdat(InputChunk *Chunk) const;
+ bool isExcludedByComdat(InputChunk *chunk) const;
- std::unique_ptr<WasmObjectFile> WasmObj;
+ std::unique_ptr<WasmObjectFile> wasmObj;
};
// .so file.
class SharedFile : public InputFile {
public:
- explicit SharedFile(MemoryBufferRef M) : InputFile(SharedKind, M) {}
- static bool classof(const InputFile *F) { return F->kind() == SharedKind; }
+ explicit SharedFile(MemoryBufferRef m) : InputFile(SharedKind, m) {}
+ static bool classof(const InputFile *f) { return f->kind() == SharedKind; }
};
// .bc file
class BitcodeFile : public InputFile {
public:
- explicit BitcodeFile(MemoryBufferRef M, StringRef ArchiveName)
- : InputFile(BitcodeKind, M) {
- this->ArchiveName = ArchiveName;
+ explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName)
+ : InputFile(BitcodeKind, m) {
+ this->archiveName = archiveName;
}
- static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
+ static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
void parse();
- std::unique_ptr<llvm::lto::InputFile> Obj;
+ std::unique_ptr<llvm::lto::InputFile> obj;
};
// Will report a fatal() error if the input buffer is not a valid bitcode
// or wasm object file.
-InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "");
+InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "");
// Opens a given file.
-llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
+llvm::Optional<MemoryBufferRef> readFile(StringRef path);
} // namespace wasm
-std::string toString(const wasm::InputFile *File);
+std::string toString(const wasm::InputFile *file);
} // namespace lld
// combined to form the final GLOBALS section.
class InputGlobal {
public:
- InputGlobal(const WasmGlobal &G, ObjFile *F)
- : File(F), Global(G), Live(!Config->GcSections) {}
+ InputGlobal(const WasmGlobal &g, ObjFile *f)
+ : file(f), global(g), live(!config->gcSections) {}
- StringRef getName() const { return Global.SymbolName; }
- const WasmGlobalType &getType() const { return Global.Type; }
+ StringRef getName() const { return global.SymbolName; }
+ const WasmGlobalType &getType() const { return global.Type; }
- uint32_t getGlobalIndex() const { return GlobalIndex.getValue(); }
- bool hasGlobalIndex() const { return GlobalIndex.hasValue(); }
- void setGlobalIndex(uint32_t Index) {
+ uint32_t getGlobalIndex() const { return globalIndex.getValue(); }
+ bool hasGlobalIndex() const { return globalIndex.hasValue(); }
+ void setGlobalIndex(uint32_t index) {
assert(!hasGlobalIndex());
- GlobalIndex = Index;
+ globalIndex = index;
}
- ObjFile *File;
- WasmGlobal Global;
+ ObjFile *file;
+ WasmGlobal global;
- bool Live = false;
+ bool live = false;
protected:
- llvm::Optional<uint32_t> GlobalIndex;
+ llvm::Optional<uint32_t> globalIndex;
};
} // namespace wasm
-inline std::string toString(const wasm::InputGlobal *G) {
- return (toString(G->File) + ":(" + G->getName() + ")").str();
+inline std::string toString(const wasm::InputGlobal *g) {
+ return (toString(g->file) + ":(" + g->getName() + ")").str();
}
} // namespace lld
using namespace lld::wasm;
static std::unique_ptr<lto::LTO> createLTO() {
- lto::Config C;
- C.Options = initTargetOptionsFromCodeGenFlags();
+ lto::Config c;
+ c.Options = initTargetOptionsFromCodeGenFlags();
// Always emit a section per function/data with LTO.
- C.Options.FunctionSections = true;
- C.Options.DataSections = true;
-
- C.DisableVerify = Config->DisableVerify;
- C.DiagHandler = diagnosticHandler;
- C.OptLevel = Config->LTOO;
- C.MAttrs = getMAttrs();
- C.CGOptLevel = args::getCGOptLevel(Config->LTOO);
-
- if (Config->Relocatable)
- C.RelocModel = None;
- else if (Config->Pic)
- C.RelocModel = Reloc::PIC_;
+ c.Options.FunctionSections = true;
+ c.Options.DataSections = true;
+
+ c.DisableVerify = config->disableVerify;
+ c.DiagHandler = diagnosticHandler;
+ c.OptLevel = config->ltoo;
+ c.MAttrs = getMAttrs();
+ c.CGOptLevel = args::getCGOptLevel(config->ltoo);
+
+ if (config->relocatable)
+ c.RelocModel = None;
+ else if (config->isPic)
+ c.RelocModel = Reloc::PIC_;
else
- C.RelocModel = Reloc::Static;
+ c.RelocModel = Reloc::Static;
- if (Config->SaveTemps)
- checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
+ if (config->saveTemps)
+ checkError(c.addSaveTemps(config->outputFile.str() + ".",
/*UseInputModulePath*/ true));
- lto::ThinBackend Backend;
- if (Config->ThinLTOJobs != -1U)
- Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
- return llvm::make_unique<lto::LTO>(std::move(C), Backend,
- Config->LTOPartitions);
+ lto::ThinBackend backend;
+ if (config->thinLTOJobs != -1U)
+ backend = lto::createInProcessThinBackend(config->thinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(c), backend,
+ config->ltoPartitions);
}
-BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+BitcodeCompiler::BitcodeCompiler() : ltoObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
-static void undefine(Symbol *S) {
- if (auto F = dyn_cast<DefinedFunction>(S))
- replaceSymbol<UndefinedFunction>(F, F->getName(), F->getName(),
- DefaultModule, 0,
- F->getFile(), F->Signature);
- else if (isa<DefinedData>(S))
- replaceSymbol<UndefinedData>(S, S->getName(), 0, S->getFile());
+static void undefine(Symbol *s) {
+ if (auto f = dyn_cast<DefinedFunction>(s))
+ replaceSymbol<UndefinedFunction>(f, f->getName(), f->getName(),
+ defaultModule, 0,
+ f->getFile(), f->signature);
+ else if (isa<DefinedData>(s))
+ replaceSymbol<UndefinedData>(s, s->getName(), 0, s->getFile());
else
llvm_unreachable("unexpected symbol kind");
}
-void BitcodeCompiler::add(BitcodeFile &F) {
- lto::InputFile &Obj = *F.Obj;
- unsigned SymNum = 0;
- ArrayRef<Symbol *> Syms = F.getSymbols();
- std::vector<lto::SymbolResolution> Resols(Syms.size());
+void BitcodeCompiler::add(BitcodeFile &f) {
+ lto::InputFile &obj = *f.obj;
+ unsigned symNum = 0;
+ ArrayRef<Symbol *> syms = f.getSymbols();
+ std::vector<lto::SymbolResolution> resols(syms.size());
// Provide a resolution to the LTO API for each symbol.
- for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
- Symbol *Sym = Syms[SymNum];
- lto::SymbolResolution &R = Resols[SymNum];
- ++SymNum;
+ for (const lto::InputFile::Symbol &objSym : obj.symbols()) {
+ Symbol *sym = syms[symNum];
+ lto::SymbolResolution &r = resols[symNum];
+ ++symNum;
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
// reports two symbols for module ASM defined. Without this check, lld
// flags an undefined in IR with a definition in ASM as prevailing.
// Once IRObjectFile is fixed to report only one symbol this hack can
// be removed.
- R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F;
- R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj ||
- (R.Prevailing && Sym->isExported());
- if (R.Prevailing)
- undefine(Sym);
+ r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f;
+ r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj ||
+ (r.Prevailing && sym->isExported());
+ if (r.Prevailing)
+ undefine(sym);
// We tell LTO to not apply interprocedural optimization for wrapped
// (with --wrap) symbols because otherwise LTO would inline them while
// their values are still not final.
- R.LinkerRedefined = !Sym->CanInline;
+ r.LinkerRedefined = !sym->canInline;
}
- checkError(LTOObj->add(std::move(F.Obj), Resols));
+ checkError(ltoObj->add(std::move(f.obj), resols));
}
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects.
std::vector<StringRef> BitcodeCompiler::compile() {
- unsigned MaxTasks = LTOObj->getMaxTasks();
- Buf.resize(MaxTasks);
- Files.resize(MaxTasks);
+ unsigned maxTasks = ltoObj->getMaxTasks();
+ buf.resize(maxTasks);
+ files.resize(maxTasks);
// The --thinlto-cache-dir option specifies the path to a directory in which
// to cache native object files for ThinLTO incremental builds. If a path was
// specified, configure LTO to use it as the cache directory.
- lto::NativeObjectCache Cache;
- if (!Config->ThinLTOCacheDir.empty())
- Cache = check(
- lto::localCache(Config->ThinLTOCacheDir,
- [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
- Files[Task] = std::move(MB);
+ lto::NativeObjectCache cache;
+ if (!config->thinLTOCacheDir.empty())
+ cache = check(
+ lto::localCache(config->thinLTOCacheDir,
+ [&](size_t task, std::unique_ptr<MemoryBuffer> mb) {
+ files[task] = std::move(mb);
}));
- checkError(LTOObj->run(
- [&](size_t Task) {
+ checkError(ltoObj->run(
+ [&](size_t task) {
return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buf[Task]));
+ llvm::make_unique<raw_svector_ostream>(buf[task]));
},
- Cache));
+ cache));
- if (!Config->ThinLTOCacheDir.empty())
- pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
+ if (!config->thinLTOCacheDir.empty())
+ pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy);
- std::vector<StringRef> Ret;
- for (unsigned I = 0; I != MaxTasks; ++I) {
- if (Buf[I].empty())
+ std::vector<StringRef> ret;
+ for (unsigned i = 0; i != maxTasks; ++i) {
+ if (buf[i].empty())
continue;
- if (Config->SaveTemps) {
- if (I == 0)
- saveBuffer(Buf[I], Config->OutputFile + ".lto.o");
+ if (config->saveTemps) {
+ if (i == 0)
+ saveBuffer(buf[i], config->outputFile + ".lto.o");
else
- saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o");
+ saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o");
}
- Ret.emplace_back(Buf[I].data(), Buf[I].size());
+ ret.emplace_back(buf[i].data(), buf[i].size());
}
- for (std::unique_ptr<MemoryBuffer> &File : Files)
- if (File)
- Ret.push_back(File->getBuffer());
+ for (std::unique_ptr<MemoryBuffer> &file : files)
+ if (file)
+ ret.push_back(file->getBuffer());
- return Ret;
+ return ret;
}
BitcodeCompiler();
~BitcodeCompiler();
- void add(BitcodeFile &F);
+ void add(BitcodeFile &f);
std::vector<StringRef> compile();
private:
- std::unique_ptr<llvm::lto::LTO> LTOObj;
- std::vector<SmallString<0>> Buf;
- std::vector<std::unique_ptr<MemoryBuffer>> Files;
+ std::unique_ptr<llvm::lto::LTO> ltoObj;
+ std::vector<SmallString<0>> buf;
+ std::vector<std::unique_ptr<MemoryBuffer>> files;
};
} // namespace wasm
} // namespace lld
using namespace llvm::wasm;
void lld::wasm::markLive() {
- if (!Config->GcSections)
+ if (!config->gcSections)
return;
LLVM_DEBUG(dbgs() << "markLive\n");
- SmallVector<InputChunk *, 256> Q;
+ SmallVector<InputChunk *, 256> q;
- std::function<void(Symbol*)> Enqueue = [&](Symbol *Sym) {
- if (!Sym || Sym->isLive())
+ std::function<void(Symbol*)> enqueue = [&](Symbol *sym) {
+ if (!sym || sym->isLive())
return;
- LLVM_DEBUG(dbgs() << "markLive: " << Sym->getName() << "\n");
- Sym->markLive();
- if (InputChunk *Chunk = Sym->getChunk())
- Q.push_back(Chunk);
+ LLVM_DEBUG(dbgs() << "markLive: " << sym->getName() << "\n");
+ sym->markLive();
+ if (InputChunk *chunk = sym->getChunk())
+ q.push_back(chunk);
// The ctor functions are all referenced by the synthetic CallCtors
// function. However, this function does not contain relocations so we
// have to manually mark the ctors as live if CallCtors itself is live.
- if (Sym == WasmSym::CallCtors) {
- if (Config->PassiveSegments)
- Enqueue(WasmSym::InitMemory);
- if (Config->Pic)
- Enqueue(WasmSym::ApplyRelocs);
- for (const ObjFile *Obj : Symtab->ObjectFiles) {
- const WasmLinkingData &L = Obj->getWasmObj()->linkingData();
- for (const WasmInitFunc &F : L.InitFunctions) {
- auto* InitSym = Obj->getFunctionSymbol(F.Symbol);
- if (!InitSym->isDiscarded())
- Enqueue(InitSym);
+ if (sym == WasmSym::callCtors) {
+ if (config->passiveSegments)
+ enqueue(WasmSym::initMemory);
+ if (config->isPic)
+ enqueue(WasmSym::applyRelocs);
+ for (const ObjFile *obj : symtab->objectFiles) {
+ const WasmLinkingData &l = obj->getWasmObj()->linkingData();
+ for (const WasmInitFunc &f : l.InitFunctions) {
+ auto* initSym = obj->getFunctionSymbol(f.Symbol);
+ if (!initSym->isDiscarded())
+ enqueue(initSym);
}
}
}
};
// Add GC root symbols.
- if (!Config->Entry.empty())
- Enqueue(Symtab->find(Config->Entry));
+ if (!config->entry.empty())
+ enqueue(symtab->find(config->entry));
// We need to preserve any exported symbol
- for (Symbol *Sym : Symtab->getSymbols())
- if (Sym->isExported())
- Enqueue(Sym);
+ for (Symbol *sym : symtab->getSymbols())
+ if (sym->isExported())
+ enqueue(sym);
// For relocatable output, we need to preserve all the ctor functions
- if (Config->Relocatable) {
- for (const ObjFile *Obj : Symtab->ObjectFiles) {
- const WasmLinkingData &L = Obj->getWasmObj()->linkingData();
- for (const WasmInitFunc &F : L.InitFunctions)
- Enqueue(Obj->getFunctionSymbol(F.Symbol));
+ if (config->relocatable) {
+ for (const ObjFile *obj : symtab->objectFiles) {
+ const WasmLinkingData &l = obj->getWasmObj()->linkingData();
+ for (const WasmInitFunc &f : l.InitFunctions)
+ enqueue(obj->getFunctionSymbol(f.Symbol));
}
}
- if (Config->Pic)
- Enqueue(WasmSym::CallCtors);
+ if (config->isPic)
+ enqueue(WasmSym::callCtors);
// Follow relocations to mark all reachable chunks.
- while (!Q.empty()) {
- InputChunk *C = Q.pop_back_val();
+ while (!q.empty()) {
+ InputChunk *c = q.pop_back_val();
- for (const WasmRelocation Reloc : C->getRelocations()) {
- if (Reloc.Type == R_WASM_TYPE_INDEX_LEB)
+ for (const WasmRelocation reloc : c->getRelocations()) {
+ if (reloc.Type == R_WASM_TYPE_INDEX_LEB)
continue;
- Symbol *Sym = C->File->getSymbol(Reloc.Index);
+ Symbol *sym = c->file->getSymbol(reloc.Index);
// If the function has been assigned the special index zero in the table,
// the relocation doesn't pull in the function body, since the function
// zero is only reachable via "call", not via "call_indirect". The stub
// functions used for weak-undefined symbols have this behaviour (compare
// equal to null pointer, only reachable via direct call).
- if (Reloc.Type == R_WASM_TABLE_INDEX_SLEB ||
- Reloc.Type == R_WASM_TABLE_INDEX_I32) {
- auto *FuncSym = cast<FunctionSymbol>(Sym);
- if (FuncSym->hasTableIndex() && FuncSym->getTableIndex() == 0)
+ if (reloc.Type == R_WASM_TABLE_INDEX_SLEB ||
+ reloc.Type == R_WASM_TABLE_INDEX_I32) {
+ auto *funcSym = cast<FunctionSymbol>(sym);
+ if (funcSym->hasTableIndex() && funcSym->getTableIndex() == 0)
continue;
}
- Enqueue(Sym);
+ enqueue(sym);
}
}
// Report garbage-collected sections.
- if (Config->PrintGcSections) {
- for (const ObjFile *Obj : Symtab->ObjectFiles) {
- for (InputChunk *C : Obj->Functions)
- if (!C->Live)
- message("removing unused section " + toString(C));
- for (InputChunk *C : Obj->Segments)
- if (!C->Live)
- message("removing unused section " + toString(C));
- for (InputGlobal *G : Obj->Globals)
- if (!G->Live)
- message("removing unused section " + toString(G));
- for (InputEvent *E : Obj->Events)
- if (!E->Live)
- message("removing unused section " + toString(E));
+ if (config->printGcSections) {
+ for (const ObjFile *obj : symtab->objectFiles) {
+ for (InputChunk *c : obj->functions)
+ if (!c->live)
+ message("removing unused section " + toString(c));
+ for (InputChunk *c : obj->segments)
+ if (!c->live)
+ message("removing unused section " + toString(c));
+ for (InputGlobal *g : obj->globals)
+ if (!g->live)
+ message("removing unused section " + toString(g));
+ for (InputEvent *e : obj->events)
+ if (!e->live)
+ message("removing unused section " + toString(e));
}
- for (InputChunk *C : Symtab->SyntheticFunctions)
- if (!C->Live)
- message("removing unused section " + toString(C));
- for (InputGlobal *G : Symtab->SyntheticGlobals)
- if (!G->Live)
- message("removing unused section " + toString(G));
+ for (InputChunk *c : symtab->syntheticFunctions)
+ if (!c->live)
+ message("removing unused section " + toString(c));
+ for (InputGlobal *g : symtab->syntheticGlobals)
+ if (!g->live)
+ message("removing unused section " + toString(g));
}
}
using namespace lld;
using namespace lld::wasm;
-static StringRef sectionTypeToString(uint32_t SectionType) {
- switch (SectionType) {
+static StringRef sectionTypeToString(uint32_t sectionType) {
+ switch (sectionType) {
case WASM_SEC_CUSTOM:
return "CUSTOM";
case WASM_SEC_TYPE:
}
// Returns a string, e.g. "FUNCTION(.text)".
-std::string lld::toString(const OutputSection &Sec) {
- if (!Sec.Name.empty())
- return (Sec.getSectionName() + "(" + Sec.Name + ")").str();
- return Sec.getSectionName();
+std::string lld::toString(const OutputSection &sec) {
+ if (!sec.name.empty())
+ return (sec.getSectionName() + "(" + sec.name + ")").str();
+ return sec.getSectionName();
}
StringRef OutputSection::getSectionName() const {
- return sectionTypeToString(Type);
+ return sectionTypeToString(type);
}
-void OutputSection::createHeader(size_t BodySize) {
- raw_string_ostream OS(Header);
- debugWrite(OS.tell(), "section type [" + getSectionName() + "]");
- encodeULEB128(Type, OS);
- writeUleb128(OS, BodySize, "section size");
- OS.flush();
- log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) +
+void OutputSection::createHeader(size_t bodySize) {
+ raw_string_ostream os(header);
+ debugWrite(os.tell(), "section type [" + getSectionName() + "]");
+ encodeULEB128(type, os);
+ writeUleb128(os, bodySize, "section size");
+ os.flush();
+ log("createHeader: " + toString(*this) + " body=" + Twine(bodySize) +
" total=" + Twine(getSize()));
}
void CodeSection::finalizeContents() {
- raw_string_ostream OS(CodeSectionHeader);
- writeUleb128(OS, Functions.size(), "function count");
- OS.flush();
- BodySize = CodeSectionHeader.size();
-
- for (InputFunction *Func : Functions) {
- Func->OutputOffset = BodySize;
- Func->calculateSize();
- BodySize += Func->getSize();
+ raw_string_ostream os(codeSectionHeader);
+ writeUleb128(os, functions.size(), "function count");
+ os.flush();
+ bodySize = codeSectionHeader.size();
+
+ for (InputFunction *func : functions) {
+ func->outputOffset = bodySize;
+ func->calculateSize();
+ bodySize += func->getSize();
}
- createHeader(BodySize);
+ createHeader(bodySize);
}
-void CodeSection::writeTo(uint8_t *Buf) {
+void CodeSection::writeTo(uint8_t *buf) {
log("writing " + toString(*this));
log(" size=" + Twine(getSize()));
- log(" headersize=" + Twine(Header.size()));
- log(" codeheadersize=" + Twine(CodeSectionHeader.size()));
- Buf += Offset;
+ log(" headersize=" + Twine(header.size()));
+ log(" codeheadersize=" + Twine(codeSectionHeader.size()));
+ buf += offset;
// Write section header
- memcpy(Buf, Header.data(), Header.size());
- Buf += Header.size();
+ memcpy(buf, header.data(), header.size());
+ buf += header.size();
// Write code section headers
- memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
+ memcpy(buf, codeSectionHeader.data(), codeSectionHeader.size());
// Write code section bodies
- for (const InputChunk *Chunk : Functions)
- Chunk->writeTo(Buf);
+ for (const InputChunk *chunk : functions)
+ chunk->writeTo(buf);
}
uint32_t CodeSection::getNumRelocations() const {
- uint32_t Count = 0;
- for (const InputChunk *Func : Functions)
- Count += Func->getNumRelocations();
- return Count;
+ uint32_t count = 0;
+ for (const InputChunk *func : functions)
+ count += func->getNumRelocations();
+ return count;
}
-void CodeSection::writeRelocations(raw_ostream &OS) const {
- for (const InputChunk *C : Functions)
- C->writeRelocations(OS);
+void CodeSection::writeRelocations(raw_ostream &os) const {
+ for (const InputChunk *c : functions)
+ c->writeRelocations(os);
}
void DataSection::finalizeContents() {
- raw_string_ostream OS(DataSectionHeader);
+ raw_string_ostream os(dataSectionHeader);
- writeUleb128(OS, Segments.size(), "data segment count");
- OS.flush();
- BodySize = DataSectionHeader.size();
+ writeUleb128(os, segments.size(), "data segment count");
+ os.flush();
+ bodySize = dataSectionHeader.size();
- assert((!Config->Pic || Segments.size() <= 1) &&
+ assert((!config->isPic || segments.size() <= 1) &&
"Currenly only a single data segment is supported in PIC mode");
- for (OutputSegment *Segment : Segments) {
- raw_string_ostream OS(Segment->Header);
- writeUleb128(OS, Segment->InitFlags, "init flags");
- if (Segment->InitFlags & WASM_SEGMENT_HAS_MEMINDEX)
- writeUleb128(OS, 0, "memory index");
- if ((Segment->InitFlags & WASM_SEGMENT_IS_PASSIVE) == 0) {
- WasmInitExpr InitExpr;
- if (Config->Pic) {
- InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
- InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex();
+ for (OutputSegment *segment : segments) {
+ raw_string_ostream os(segment->header);
+ writeUleb128(os, segment->initFlags, "init flags");
+ if (segment->initFlags & WASM_SEGMENT_HAS_MEMINDEX)
+ writeUleb128(os, 0, "memory index");
+ if ((segment->initFlags & WASM_SEGMENT_IS_PASSIVE) == 0) {
+ WasmInitExpr initExpr;
+ if (config->isPic) {
+ initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
+ initExpr.Value.Global = WasmSym::memoryBase->getGlobalIndex();
} else {
- InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- InitExpr.Value.Int32 = Segment->StartVA;
+ initExpr.Opcode = WASM_OPCODE_I32_CONST;
+ initExpr.Value.Int32 = segment->startVA;
}
- writeInitExpr(OS, InitExpr);
+ writeInitExpr(os, initExpr);
}
- writeUleb128(OS, Segment->Size, "segment size");
- OS.flush();
+ writeUleb128(os, segment->size, "segment size");
+ os.flush();
- Segment->SectionOffset = BodySize;
- BodySize += Segment->Header.size() + Segment->Size;
- log("Data segment: size=" + Twine(Segment->Size) + ", startVA=" +
- Twine::utohexstr(Segment->StartVA) + ", name=" + Segment->Name);
+ segment->sectionOffset = bodySize;
+ bodySize += segment->header.size() + segment->size;
+ log("Data segment: size=" + Twine(segment->size) + ", startVA=" +
+ Twine::utohexstr(segment->startVA) + ", name=" + segment->name);
- for (InputSegment *InputSeg : Segment->InputSegments)
- InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() +
- InputSeg->OutputSegmentOffset;
+ for (InputSegment *inputSeg : segment->inputSegments)
+ inputSeg->outputOffset = segment->sectionOffset + segment->header.size() +
+ inputSeg->outputSegmentOffset;
}
- createHeader(BodySize);
+ createHeader(bodySize);
}
-void DataSection::writeTo(uint8_t *Buf) {
+void DataSection::writeTo(uint8_t *buf) {
log("writing " + toString(*this) + " size=" + Twine(getSize()) +
- " body=" + Twine(BodySize));
- Buf += Offset;
+ " body=" + Twine(bodySize));
+ buf += offset;
// Write section header
- memcpy(Buf, Header.data(), Header.size());
- Buf += Header.size();
+ memcpy(buf, header.data(), header.size());
+ buf += header.size();
// Write data section headers
- memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
+ memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size());
- for (const OutputSegment *Segment : Segments) {
+ for (const OutputSegment *segment : segments) {
// Write data segment header
- uint8_t *SegStart = Buf + Segment->SectionOffset;
- memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
+ uint8_t *segStart = buf + segment->sectionOffset;
+ memcpy(segStart, segment->header.data(), segment->header.size());
// Write segment data payload
- for (const InputChunk *Chunk : Segment->InputSegments)
- Chunk->writeTo(Buf);
+ for (const InputChunk *chunk : segment->inputSegments)
+ chunk->writeTo(buf);
}
}
uint32_t DataSection::getNumRelocations() const {
- uint32_t Count = 0;
- for (const OutputSegment *Seg : Segments)
- for (const InputChunk *InputSeg : Seg->InputSegments)
- Count += InputSeg->getNumRelocations();
- return Count;
+ uint32_t count = 0;
+ for (const OutputSegment *seg : segments)
+ for (const InputChunk *inputSeg : seg->inputSegments)
+ count += inputSeg->getNumRelocations();
+ return count;
}
-void DataSection::writeRelocations(raw_ostream &OS) const {
- for (const OutputSegment *Seg : Segments)
- for (const InputChunk *C : Seg->InputSegments)
- C->writeRelocations(OS);
+void DataSection::writeRelocations(raw_ostream &os) const {
+ for (const OutputSegment *seg : segments)
+ for (const InputChunk *c : seg->inputSegments)
+ c->writeRelocations(os);
}
void CustomSection::finalizeContents() {
- raw_string_ostream OS(NameData);
- encodeULEB128(Name.size(), OS);
- OS << Name;
- OS.flush();
-
- for (InputSection *Section : InputSections) {
- Section->OutputOffset = PayloadSize;
- Section->OutputSec = this;
- PayloadSize += Section->getSize();
+ raw_string_ostream os(nameData);
+ encodeULEB128(name.size(), os);
+ os << name;
+ os.flush();
+
+ for (InputSection *section : inputSections) {
+ section->outputOffset = payloadSize;
+ section->outputSec = this;
+ payloadSize += section->getSize();
}
- createHeader(PayloadSize + NameData.size());
+ createHeader(payloadSize + nameData.size());
}
-void CustomSection::writeTo(uint8_t *Buf) {
+void CustomSection::writeTo(uint8_t *buf) {
log("writing " + toString(*this) + " size=" + Twine(getSize()) +
- " chunks=" + Twine(InputSections.size()));
+ " chunks=" + Twine(inputSections.size()));
- assert(Offset);
- Buf += Offset;
+ assert(offset);
+ buf += offset;
// Write section header
- memcpy(Buf, Header.data(), Header.size());
- Buf += Header.size();
- memcpy(Buf, NameData.data(), NameData.size());
- Buf += NameData.size();
+ memcpy(buf, header.data(), header.size());
+ buf += header.size();
+ memcpy(buf, nameData.data(), nameData.size());
+ buf += nameData.size();
// Write custom sections payload
- for (const InputSection *Section : InputSections)
- Section->writeTo(Buf);
+ for (const InputSection *section : inputSections)
+ section->writeTo(buf);
}
uint32_t CustomSection::getNumRelocations() const {
- uint32_t Count = 0;
- for (const InputSection *InputSect : InputSections)
- Count += InputSect->getNumRelocations();
- return Count;
+ uint32_t count = 0;
+ for (const InputSection *inputSect : inputSections)
+ count += inputSect->getNumRelocations();
+ return count;
}
-void CustomSection::writeRelocations(raw_ostream &OS) const {
- for (const InputSection *S : InputSections)
- S->writeRelocations(OS);
+void CustomSection::writeRelocations(raw_ostream &os) const {
+ for (const InputSection *s : inputSections)
+ s->writeRelocations(os);
}
namespace wasm {
class OutputSection;
}
-std::string toString(const wasm::OutputSection &Section);
+std::string toString(const wasm::OutputSection §ion);
namespace wasm {
class OutputSection {
public:
- OutputSection(uint32_t Type, std::string Name = "")
- : Type(Type), Name(Name) {}
+ OutputSection(uint32_t type, std::string name = "")
+ : type(type), name(name) {}
virtual ~OutputSection() = default;
StringRef getSectionName() const;
- void setOffset(size_t NewOffset) {
- log("setOffset: " + toString(*this) + ": " + Twine(NewOffset));
- Offset = NewOffset;
+ void setOffset(size_t newOffset) {
+ log("setOffset: " + toString(*this) + ": " + Twine(newOffset));
+ offset = newOffset;
}
- void createHeader(size_t BodySize);
+ void createHeader(size_t bodySize);
virtual bool isNeeded() const { return true; }
virtual size_t getSize() const = 0;
- virtual void writeTo(uint8_t *Buf) = 0;
+ virtual void writeTo(uint8_t *buf) = 0;
virtual void finalizeContents() = 0;
virtual uint32_t getNumRelocations() const { return 0; }
- virtual void writeRelocations(raw_ostream &OS) const {}
+ virtual void writeRelocations(raw_ostream &os) const {}
- std::string Header;
- uint32_t Type;
- uint32_t SectionIndex = UINT32_MAX;
- std::string Name;
- OutputSectionSymbol *SectionSym = nullptr;
+ std::string header;
+ uint32_t type;
+ uint32_t sectionIndex = UINT32_MAX;
+ std::string name;
+ OutputSectionSymbol *sectionSym = nullptr;
protected:
- size_t Offset = 0;
+ size_t offset = 0;
};
class CodeSection : public OutputSection {
public:
- explicit CodeSection(ArrayRef<InputFunction *> Functions)
- : OutputSection(llvm::wasm::WASM_SEC_CODE), Functions(Functions) {}
+ explicit CodeSection(ArrayRef<InputFunction *> functions)
+ : OutputSection(llvm::wasm::WASM_SEC_CODE), functions(functions) {}
- size_t getSize() const override { return Header.size() + BodySize; }
- void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return header.size() + bodySize; }
+ void writeTo(uint8_t *buf) override;
uint32_t getNumRelocations() const override;
- void writeRelocations(raw_ostream &OS) const override;
- bool isNeeded() const override { return Functions.size() > 0; }
+ void writeRelocations(raw_ostream &os) const override;
+ bool isNeeded() const override { return functions.size() > 0; }
void finalizeContents() override;
protected:
- ArrayRef<InputFunction *> Functions;
- std::string CodeSectionHeader;
- size_t BodySize = 0;
+ ArrayRef<InputFunction *> functions;
+ std::string codeSectionHeader;
+ size_t bodySize = 0;
};
class DataSection : public OutputSection {
public:
- explicit DataSection(ArrayRef<OutputSegment *> Segments)
- : OutputSection(llvm::wasm::WASM_SEC_DATA), Segments(Segments) {}
+ explicit DataSection(ArrayRef<OutputSegment *> segments)
+ : OutputSection(llvm::wasm::WASM_SEC_DATA), segments(segments) {}
- size_t getSize() const override { return Header.size() + BodySize; }
- void writeTo(uint8_t *Buf) override;
+ size_t getSize() const override { return header.size() + bodySize; }
+ void writeTo(uint8_t *buf) override;
uint32_t getNumRelocations() const override;
- void writeRelocations(raw_ostream &OS) const override;
- bool isNeeded() const override { return Segments.size() > 0; }
+ void writeRelocations(raw_ostream &os) const override;
+ bool isNeeded() const override { return segments.size() > 0; }
void finalizeContents() override;
protected:
- ArrayRef<OutputSegment *> Segments;
- std::string DataSectionHeader;
- size_t BodySize = 0;
+ ArrayRef<OutputSegment *> segments;
+ std::string dataSectionHeader;
+ size_t bodySize = 0;
};
// Represents a custom section in the output file. Wasm custom sections are
// separately and are instead synthesized by the linker.
class CustomSection : public OutputSection {
public:
- CustomSection(std::string Name, ArrayRef<InputSection *> InputSections)
- : OutputSection(llvm::wasm::WASM_SEC_CUSTOM, Name),
- InputSections(InputSections) {}
+ CustomSection(std::string name, ArrayRef<InputSection *> inputSections)
+ : OutputSection(llvm::wasm::WASM_SEC_CUSTOM, name),
+ inputSections(inputSections) {}
size_t getSize() const override {
- return Header.size() + NameData.size() + PayloadSize;
+ return header.size() + nameData.size() + payloadSize;
}
- void writeTo(uint8_t *Buf) override;
+ void writeTo(uint8_t *buf) override;
uint32_t getNumRelocations() const override;
- void writeRelocations(raw_ostream &OS) const override;
+ void writeRelocations(raw_ostream &os) const override;
void finalizeContents() override;
protected:
- size_t PayloadSize = 0;
- ArrayRef<InputSection *> InputSections;
- std::string NameData;
+ size_t payloadSize = 0;
+ ArrayRef<InputSection *> inputSections;
+ std::string nameData;
};
} // namespace wasm
class OutputSegment {
public:
- OutputSegment(StringRef N, uint32_t Index) : Name(N), Index(Index) {}
-
- void addInputSegment(InputSegment *InSeg) {
- Alignment = std::max(Alignment, InSeg->getAlignment());
- InputSegments.push_back(InSeg);
- Size = llvm::alignTo(Size, 1ULL << InSeg->getAlignment());
- InSeg->OutputSeg = this;
- InSeg->OutputSegmentOffset = Size;
- Size += InSeg->getSize();
+ OutputSegment(StringRef n, uint32_t index) : name(n), index(index) {}
+
+ void addInputSegment(InputSegment *inSeg) {
+ alignment = std::max(alignment, inSeg->getAlignment());
+ inputSegments.push_back(inSeg);
+ size = llvm::alignTo(size, 1ULL << inSeg->getAlignment());
+ inSeg->outputSeg = this;
+ inSeg->outputSegmentOffset = size;
+ size += inSeg->getSize();
}
- StringRef Name;
- const uint32_t Index;
- uint32_t InitFlags = 0;
- uint32_t SectionOffset = 0;
- uint32_t Alignment = 0;
- uint32_t StartVA = 0;
- std::vector<InputSegment *> InputSegments;
+ StringRef name;
+ const uint32_t index;
+ uint32_t initFlags = 0;
+ uint32_t sectionOffset = 0;
+ uint32_t alignment = 0;
+ uint32_t startVA = 0;
+ std::vector<InputSegment *> inputSegments;
// Sum of the size of the all the input segments
- uint32_t Size = 0;
+ uint32_t size = 0;
// Segment header
- std::string Header;
+ std::string header;
};
} // namespace wasm
using namespace lld;
using namespace lld::wasm;
-static bool requiresGOTAccess(const Symbol *Sym) {
- return Config->Pic && !Sym->isHidden() && !Sym->isLocal();
+static bool requiresGOTAccess(const Symbol *sym) {
+ return config->isPic && !sym->isHidden() && !sym->isLocal();
}
-static bool allowUndefined(const Symbol* Sym) {
+static bool allowUndefined(const Symbol* sym) {
// Historically --allow-undefined doesn't work for data symbols since we don't
// have any way to represent these as imports in the final binary. The idea
// behind allowing undefined symbols is to allow importing these symbols from
// the embedder and we can't do this for data symbols (at least not without
// compiling with -fPIC)
- if (isa<DataSymbol>(Sym))
+ if (isa<DataSymbol>(sym))
return false;
- return (Config->AllowUndefined ||
- Config->AllowUndefinedSymbols.count(Sym->getName()) != 0);
+ return (config->allowUndefined ||
+ config->allowUndefinedSymbols.count(sym->getName()) != 0);
}
-static void reportUndefined(const Symbol* Sym) {
- assert(Sym->isUndefined());
- assert(!Sym->isWeak());
- if (!allowUndefined(Sym))
- error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
+static void reportUndefined(const Symbol* sym) {
+ assert(sym->isUndefined());
+ assert(!sym->isWeak());
+ if (!allowUndefined(sym))
+ error(toString(sym->getFile()) + ": undefined symbol: " + toString(*sym));
}
-void lld::wasm::scanRelocations(InputChunk *Chunk) {
- if (!Chunk->Live)
+void lld::wasm::scanRelocations(InputChunk *chunk) {
+ if (!chunk->live)
return;
- ObjFile *File = Chunk->File;
- ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
- for (const WasmRelocation &Reloc : Chunk->getRelocations()) {
- if (Reloc.Type == R_WASM_TYPE_INDEX_LEB) {
+ ObjFile *file = chunk->file;
+ ArrayRef<WasmSignature> types = file->getWasmObj()->types();
+ for (const WasmRelocation &reloc : chunk->getRelocations()) {
+ if (reloc.Type == R_WASM_TYPE_INDEX_LEB) {
// Mark target type as live
- File->TypeMap[Reloc.Index] =
- Out.TypeSec->registerType(Types[Reloc.Index]);
- File->TypeIsUsed[Reloc.Index] = true;
+ file->typeMap[reloc.Index] =
+ out.typeSec->registerType(types[reloc.Index]);
+ file->typeIsUsed[reloc.Index] = true;
continue;
}
// Other relocation types all have a corresponding symbol
- Symbol *Sym = File->getSymbols()[Reloc.Index];
+ Symbol *sym = file->getSymbols()[reloc.Index];
- switch (Reloc.Type) {
+ switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB:
- if (requiresGOTAccess(Sym))
+ if (requiresGOTAccess(sym))
break;
- Out.ElemSec->addEntry(cast<FunctionSymbol>(Sym));
+ out.elemSec->addEntry(cast<FunctionSymbol>(sym));
break;
case R_WASM_GLOBAL_INDEX_LEB:
- if (!isa<GlobalSymbol>(Sym))
- Out.ImportSec->addGOTEntry(Sym);
+ if (!isa<GlobalSymbol>(sym))
+ out.importSec->addGOTEntry(sym);
break;
}
- if (Config->Pic) {
- switch (Reloc.Type) {
+ if (config->isPic) {
+ switch (reloc.Type) {
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
case R_WASM_MEMORY_ADDR_LEB:
// Certain relocation types can't be used when building PIC output,
// since they would require absolute symbol addresses at link time.
- error(toString(File) + ": relocation " + relocTypeToString(Reloc.Type) +
- " cannot be used against symbol " + toString(*Sym) +
+ error(toString(file) + ": relocation " + relocTypeToString(reloc.Type) +
+ " cannot be used against symbol " + toString(*sym) +
"; recompile with -fPIC");
break;
case R_WASM_TABLE_INDEX_I32:
// These relocation types are only present in the data section and
// will be converted into code by `generateRelocationCode`. This code
// requires the symbols to have GOT entires.
- if (requiresGOTAccess(Sym))
- Out.ImportSec->addGOTEntry(Sym);
+ if (requiresGOTAccess(sym))
+ out.importSec->addGOTEntry(sym);
break;
}
} else {
// Report undefined symbols
- if (Sym->isUndefined() && !Config->Relocatable && !Sym->isWeak())
- reportUndefined(Sym);
+ if (sym->isUndefined() && !config->relocatable && !sym->isWeak())
+ reportUndefined(sym);
}
}
class InputChunk;
-void scanRelocations(InputChunk *Chunk);
+void scanRelocations(InputChunk *chunk);
} // namespace wasm
} // namespace lld
using namespace lld;
using namespace lld::wasm;
-SymbolTable *lld::wasm::Symtab;
+SymbolTable *lld::wasm::symtab;
-void SymbolTable::addFile(InputFile *File) {
- log("Processing: " + toString(File));
+void SymbolTable::addFile(InputFile *file) {
+ log("Processing: " + toString(file));
// .a file
- if (auto *F = dyn_cast<ArchiveFile>(File)) {
- F->parse();
+ if (auto *f = dyn_cast<ArchiveFile>(file)) {
+ f->parse();
return;
}
// .so file
- if (auto *F = dyn_cast<SharedFile>(File)) {
- SharedFiles.push_back(F);
+ if (auto *f = dyn_cast<SharedFile>(file)) {
+ sharedFiles.push_back(f);
return;
}
- if (Config->Trace)
- message(toString(File));
+ if (config->trace)
+ message(toString(file));
// LLVM bitcode file
- if (auto *F = dyn_cast<BitcodeFile>(File)) {
- F->parse();
- BitcodeFiles.push_back(F);
+ if (auto *f = dyn_cast<BitcodeFile>(file)) {
+ f->parse();
+ bitcodeFiles.push_back(f);
return;
}
// Regular object file
- auto *F = cast<ObjFile>(File);
- F->parse(false);
- ObjectFiles.push_back(F);
+ auto *f = cast<ObjFile>(file);
+ f->parse(false);
+ objectFiles.push_back(f);
}
// This function is where all the optimizations of link-time
// Because all bitcode files that the program consists of are passed
// to the compiler at once, it can do whole-program optimization.
void SymbolTable::addCombinedLTOObject() {
- if (BitcodeFiles.empty())
+ if (bitcodeFiles.empty())
return;
// Compile bitcode files and replace bitcode symbols.
- LTO.reset(new BitcodeCompiler);
- for (BitcodeFile *F : BitcodeFiles)
- LTO->add(*F);
-
- for (StringRef Filename : LTO->compile()) {
- auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"), "");
- Obj->parse(true);
- ObjectFiles.push_back(Obj);
+ lto.reset(new BitcodeCompiler);
+ for (BitcodeFile *f : bitcodeFiles)
+ lto->add(*f);
+
+ for (StringRef filename : lto->compile()) {
+ auto *obj = make<ObjFile>(MemoryBufferRef(filename, "lto.tmp"), "");
+ obj->parse(true);
+ objectFiles.push_back(obj);
}
}
-Symbol *SymbolTable::find(StringRef Name) {
- auto It = SymMap.find(CachedHashStringRef(Name));
- if (It == SymMap.end() || It->second == -1)
+Symbol *SymbolTable::find(StringRef name) {
+ auto it = symMap.find(CachedHashStringRef(name));
+ if (it == symMap.end() || it->second == -1)
return nullptr;
- return SymVector[It->second];
+ return symVector[it->second];
}
-void SymbolTable::replace(StringRef Name, Symbol* Sym) {
- auto It = SymMap.find(CachedHashStringRef(Name));
- SymVector[It->second] = Sym;
+void SymbolTable::replace(StringRef name, Symbol* sym) {
+ auto it = symMap.find(CachedHashStringRef(name));
+ symVector[it->second] = sym;
}
-std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
- bool Trace = false;
- auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
- int &SymIndex = P.first->second;
- bool IsNew = P.second;
- if (SymIndex == -1) {
- SymIndex = SymVector.size();
- Trace = true;
- IsNew = true;
+std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
+ bool trace = false;
+ auto p = symMap.insert({CachedHashStringRef(name), (int)symVector.size()});
+ int &symIndex = p.first->second;
+ bool isNew = p.second;
+ if (symIndex == -1) {
+ symIndex = symVector.size();
+ trace = true;
+ isNew = true;
}
- if (!IsNew)
- return {SymVector[SymIndex], false};
+ if (!isNew)
+ return {symVector[symIndex], false};
- Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Sym->IsUsedInRegularObj = false;
- Sym->CanInline = true;
- Sym->Traced = Trace;
- SymVector.emplace_back(Sym);
- return {Sym, true};
+ Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ sym->isUsedInRegularObj = false;
+ sym->canInline = true;
+ sym->traced = trace;
+ symVector.emplace_back(sym);
+ return {sym, true};
}
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
- const InputFile *File) {
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insertName(Name);
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef name,
+ const InputFile *file) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insertName(name);
- if (!File || File->kind() == InputFile::ObjectKind)
- S->IsUsedInRegularObj = true;
+ if (!file || file->kind() == InputFile::ObjectKind)
+ s->isUsedInRegularObj = true;
- return {S, WasInserted};
+ return {s, wasInserted};
}
-static void reportTypeError(const Symbol *Existing, const InputFile *File,
- llvm::wasm::WasmSymbolType Type) {
- error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
- toString(Existing->getWasmType()) + " in " +
- toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
- " in " + toString(File));
+static void reportTypeError(const Symbol *existing, const InputFile *file,
+ llvm::wasm::WasmSymbolType type) {
+ error("symbol type mismatch: " + toString(*existing) + "\n>>> defined as " +
+ toString(existing->getWasmType()) + " in " +
+ toString(existing->getFile()) + "\n>>> defined as " + toString(type) +
+ " in " + toString(file));
}
// Check the type of new symbol matches that of the symbol is replacing.
// Returns true if the function types match, false is there is a singature
// mismatch.
-static bool signatureMatches(FunctionSymbol *Existing,
- const WasmSignature *NewSig) {
- const WasmSignature *OldSig = Existing->Signature;
+static bool signatureMatches(FunctionSymbol *existing,
+ const WasmSignature *newSig) {
+ const WasmSignature *oldSig = existing->signature;
// If either function is missing a signature (this happend for bitcode
// symbols) then assume they match. Any mismatch will be reported later
// when the LTO objects are added.
- if (!NewSig || !OldSig)
+ if (!newSig || !oldSig)
return true;
- return *NewSig == *OldSig;
+ return *newSig == *oldSig;
}
-static void checkGlobalType(const Symbol *Existing, const InputFile *File,
- const WasmGlobalType *NewType) {
- if (!isa<GlobalSymbol>(Existing)) {
- reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
+static void checkGlobalType(const Symbol *existing, const InputFile *file,
+ const WasmGlobalType *newType) {
+ if (!isa<GlobalSymbol>(existing)) {
+ reportTypeError(existing, file, WASM_SYMBOL_TYPE_GLOBAL);
return;
}
- const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
- if (*NewType != *OldType) {
- error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
- toString(*OldType) + " in " + toString(Existing->getFile()) +
- "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
+ const WasmGlobalType *oldType = cast<GlobalSymbol>(existing)->getGlobalType();
+ if (*newType != *oldType) {
+ error("Global type mismatch: " + existing->getName() + "\n>>> defined as " +
+ toString(*oldType) + " in " + toString(existing->getFile()) +
+ "\n>>> defined as " + toString(*newType) + " in " + toString(file));
}
}
-static void checkEventType(const Symbol *Existing, const InputFile *File,
- const WasmEventType *NewType,
- const WasmSignature *NewSig) {
- auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
- if (!isa<EventSymbol>(Existing)) {
- reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
+static void checkEventType(const Symbol *existing, const InputFile *file,
+ const WasmEventType *newType,
+ const WasmSignature *newSig) {
+ auto existingEvent = dyn_cast<EventSymbol>(existing);
+ if (!isa<EventSymbol>(existing)) {
+ reportTypeError(existing, file, WASM_SYMBOL_TYPE_EVENT);
return;
}
- const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
- const WasmSignature *OldSig = ExistingEvent->Signature;
- if (NewType->Attribute != OldType->Attribute)
- error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
- toString(*OldType) + " in " + toString(Existing->getFile()) +
- "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
- if (*NewSig != *OldSig)
- warn("Event signature mismatch: " + Existing->getName() +
- "\n>>> defined as " + toString(*OldSig) + " in " +
- toString(Existing->getFile()) + "\n>>> defined as " +
- toString(*NewSig) + " in " + toString(File));
+ const WasmEventType *oldType = cast<EventSymbol>(existing)->getEventType();
+ const WasmSignature *oldSig = existingEvent->signature;
+ if (newType->Attribute != oldType->Attribute)
+ error("Event type mismatch: " + existing->getName() + "\n>>> defined as " +
+ toString(*oldType) + " in " + toString(existing->getFile()) +
+ "\n>>> defined as " + toString(*newType) + " in " + toString(file));
+ if (*newSig != *oldSig)
+ warn("Event signature mismatch: " + existing->getName() +
+ "\n>>> defined as " + toString(*oldSig) + " in " +
+ toString(existing->getFile()) + "\n>>> defined as " +
+ toString(*newSig) + " in " + toString(file));
}
-static void checkDataType(const Symbol *Existing, const InputFile *File) {
- if (!isa<DataSymbol>(Existing))
- reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
+static void checkDataType(const Symbol *existing, const InputFile *file) {
+ if (!isa<DataSymbol>(existing))
+ reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA);
}
-DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
- uint32_t Flags,
- InputFunction *Function) {
- LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
- assert(!find(Name));
- SyntheticFunctions.emplace_back(Function);
- return replaceSymbol<DefinedFunction>(insertName(Name).first, Name,
- Flags, nullptr, Function);
+DefinedFunction *SymbolTable::addSyntheticFunction(StringRef name,
+ uint32_t flags,
+ InputFunction *function) {
+ LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << name << "\n");
+ assert(!find(name));
+ syntheticFunctions.emplace_back(function);
+ return replaceSymbol<DefinedFunction>(insertName(name).first, name,
+ flags, nullptr, function);
}
// Adds an optional, linker generated, data symbols. The symbol will only be
// added if there is an undefine reference to it, or if it is explictly exported
// via the --export flag. Otherwise we don't add the symbol and return nullptr.
-DefinedData *SymbolTable::addOptionalDataSymbol(StringRef Name, uint32_t Value,
- uint32_t Flags) {
- Symbol *S = find(Name);
- if (!S && (Config->ExportAll || Config->ExportedSymbols.count(Name) != 0))
- S = insertName(Name).first;
- else if (!S || S->isDefined())
+DefinedData *SymbolTable::addOptionalDataSymbol(StringRef name, uint32_t value,
+ uint32_t flags) {
+ Symbol *s = find(name);
+ if (!s && (config->exportAll || config->exportedSymbols.count(name) != 0))
+ s = insertName(name).first;
+ else if (!s || s->isDefined())
return nullptr;
- LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << Name << "\n");
- auto *rtn = replaceSymbol<DefinedData>(S, Name, Flags);
- rtn->setVirtualAddress(Value);
- rtn->Referenced = true;
+ LLVM_DEBUG(dbgs() << "addOptionalDataSymbol: " << name << "\n");
+ auto *rtn = replaceSymbol<DefinedData>(s, name, flags);
+ rtn->setVirtualAddress(value);
+ rtn->referenced = true;
return rtn;
}
-DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
- uint32_t Flags) {
- LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
- assert(!find(Name));
- return replaceSymbol<DefinedData>(insertName(Name).first, Name, Flags);
+DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef name,
+ uint32_t flags) {
+ LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << name << "\n");
+ assert(!find(name));
+ return replaceSymbol<DefinedData>(insertName(name).first, name, flags);
}
-DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
- InputGlobal *Global) {
- LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
+DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef name, uint32_t flags,
+ InputGlobal *global) {
+ LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << name << " -> " << global
<< "\n");
- assert(!find(Name));
- SyntheticGlobals.emplace_back(Global);
- return replaceSymbol<DefinedGlobal>(insertName(Name).first, Name, Flags,
- nullptr, Global);
+ assert(!find(name));
+ syntheticGlobals.emplace_back(global);
+ return replaceSymbol<DefinedGlobal>(insertName(name).first, name, flags,
+ nullptr, global);
}
-static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
- uint32_t NewFlags) {
+static bool shouldReplace(const Symbol *existing, InputFile *newFile,
+ uint32_t newFlags) {
// If existing symbol is undefined, replace it.
- if (!Existing->isDefined()) {
+ if (!existing->isDefined()) {
LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
- << Existing->getName() << "\n");
+ << existing->getName() << "\n");
return true;
}
// Now we have two defined symbols. If the new one is weak, we can ignore it.
- if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
+ if ((newFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
return false;
}
// If the existing symbol is weak, we should replace it.
- if (Existing->isWeak()) {
+ if (existing->isWeak()) {
LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
return true;
}
// Neither symbol is week. They conflict.
- error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
- toString(Existing->getFile()) + "\n>>> defined in " +
- toString(NewFile));
+ error("duplicate symbol: " + toString(*existing) + "\n>>> defined in " +
+ toString(existing->getFile()) + "\n>>> defined in " +
+ toString(newFile));
return true;
}
-Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
- InputFile *File,
- InputFunction *Function) {
- LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
- << (Function ? toString(Function->Signature) : "none")
+Symbol *SymbolTable::addDefinedFunction(StringRef name, uint32_t flags,
+ InputFile *file,
+ InputFunction *function) {
+ LLVM_DEBUG(dbgs() << "addDefinedFunction: " << name << " ["
+ << (function ? toString(function->signature) : "none")
<< "]\n");
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, File);
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
- auto ReplaceSym = [&](Symbol *Sym) {
+ auto replaceSym = [&](Symbol *sym) {
// If the new defined function doesn't have signture (i.e. bitcode
// functions) but the old symbol does, then preserve the old signature
- const WasmSignature *OldSig = S->getSignature();
- auto* NewSym = replaceSymbol<DefinedFunction>(Sym, Name, Flags, File, Function);
- if (!NewSym->Signature)
- NewSym->Signature = OldSig;
+ const WasmSignature *oldSig = s->getSignature();
+ auto* newSym = replaceSymbol<DefinedFunction>(sym, name, flags, file, function);
+ if (!newSym->signature)
+ newSym->signature = oldSig;
};
- if (WasInserted || S->isLazy()) {
- ReplaceSym(S);
- return S;
+ if (wasInserted || s->isLazy()) {
+ replaceSym(s);
+ return s;
}
- auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
- if (!ExistingFunction) {
- reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
- return S;
+ auto existingFunction = dyn_cast<FunctionSymbol>(s);
+ if (!existingFunction) {
+ reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
+ return s;
}
- bool CheckSig = true;
- if (auto UD = dyn_cast<UndefinedFunction>(ExistingFunction))
- CheckSig = UD->IsCalledDirectly;
+ bool checkSig = true;
+ if (auto ud = dyn_cast<UndefinedFunction>(existingFunction))
+ checkSig = ud->isCalledDirectly;
- if (CheckSig && Function && !signatureMatches(ExistingFunction, &Function->Signature)) {
- Symbol* Variant;
- if (getFunctionVariant(S, &Function->Signature, File, &Variant))
+ if (checkSig && function && !signatureMatches(existingFunction, &function->signature)) {
+ Symbol* variant;
+ if (getFunctionVariant(s, &function->signature, file, &variant))
// New variant, always replace
- ReplaceSym(Variant);
- else if (shouldReplace(S, File, Flags))
+ replaceSym(variant);
+ else if (shouldReplace(s, file, flags))
// Variant already exists, replace it after checking shouldReplace
- ReplaceSym(Variant);
+ replaceSym(variant);
// This variant we found take the place in the symbol table as the primary
// variant.
- replace(Name, Variant);
- return Variant;
+ replace(name, variant);
+ return variant;
}
// Existing function with matching signature.
- if (shouldReplace(S, File, Flags))
- ReplaceSym(S);
+ if (shouldReplace(s, file, flags))
+ replaceSym(s);
- return S;
+ return s;
}
-Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
- InputFile *File, InputSegment *Segment,
- uint32_t Address, uint32_t Size) {
- LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
+Symbol *SymbolTable::addDefinedData(StringRef name, uint32_t flags,
+ InputFile *file, InputSegment *segment,
+ uint32_t address, uint32_t size) {
+ LLVM_DEBUG(dbgs() << "addDefinedData:" << name << " addr:" << address
<< "\n");
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, File);
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
- auto ReplaceSym = [&]() {
- replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
+ auto replaceSym = [&]() {
+ replaceSymbol<DefinedData>(s, name, flags, file, segment, address, size);
};
- if (WasInserted || S->isLazy()) {
- ReplaceSym();
- return S;
+ if (wasInserted || s->isLazy()) {
+ replaceSym();
+ return s;
}
- checkDataType(S, File);
+ checkDataType(s, file);
- if (shouldReplace(S, File, Flags))
- ReplaceSym();
- return S;
+ if (shouldReplace(s, file, flags))
+ replaceSym();
+ return s;
}
-Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
- InputFile *File, InputGlobal *Global) {
- LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
+Symbol *SymbolTable::addDefinedGlobal(StringRef name, uint32_t flags,
+ InputFile *file, InputGlobal *global) {
+ LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << name << "\n");
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, File);
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
- auto ReplaceSym = [&]() {
- replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
+ auto replaceSym = [&]() {
+ replaceSymbol<DefinedGlobal>(s, name, flags, file, global);
};
- if (WasInserted || S->isLazy()) {
- ReplaceSym();
- return S;
+ if (wasInserted || s->isLazy()) {
+ replaceSym();
+ return s;
}
- checkGlobalType(S, File, &Global->getType());
+ checkGlobalType(s, file, &global->getType());
- if (shouldReplace(S, File, Flags))
- ReplaceSym();
- return S;
+ if (shouldReplace(s, file, flags))
+ replaceSym();
+ return s;
}
-Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
- InputFile *File, InputEvent *Event) {
- LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
+Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags,
+ InputFile *file, InputEvent *event) {
+ LLVM_DEBUG(dbgs() << "addDefinedEvent:" << name << "\n");
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, File);
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
- auto ReplaceSym = [&]() {
- replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
+ auto replaceSym = [&]() {
+ replaceSymbol<DefinedEvent>(s, name, flags, file, event);
};
- if (WasInserted || S->isLazy()) {
- ReplaceSym();
- return S;
+ if (wasInserted || s->isLazy()) {
+ replaceSym();
+ return s;
}
- checkEventType(S, File, &Event->getType(), &Event->Signature);
+ checkEventType(s, file, &event->getType(), &event->signature);
- if (shouldReplace(S, File, Flags))
- ReplaceSym();
- return S;
+ if (shouldReplace(s, file, flags))
+ replaceSym();
+ return s;
}
-Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName,
- StringRef ImportModule,
- uint32_t Flags, InputFile *File,
- const WasmSignature *Sig,
- bool IsCalledDirectly) {
- LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << " ["
- << (Sig ? toString(*Sig) : "none")
- << "] IsCalledDirectly:" << IsCalledDirectly << "\n");
+Symbol *SymbolTable::addUndefinedFunction(StringRef name, StringRef importName,
+ StringRef importModule,
+ uint32_t flags, InputFile *file,
+ const WasmSignature *sig,
+ bool isCalledDirectly) {
+ LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " ["
+ << (sig ? toString(*sig) : "none")
+ << "] IsCalledDirectly:" << isCalledDirectly << "\n");
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, File);
- if (S->Traced)
- printTraceSymbolUndefined(Name, File);
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
+ if (s->traced)
+ printTraceSymbolUndefined(name, file);
- auto ReplaceSym = [&]() {
- replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags,
- File, Sig, IsCalledDirectly);
+ auto replaceSym = [&]() {
+ replaceSymbol<UndefinedFunction>(s, name, importName, importModule, flags,
+ file, sig, isCalledDirectly);
};
- if (WasInserted)
- ReplaceSym();
- else if (auto *Lazy = dyn_cast<LazySymbol>(S))
- Lazy->fetch();
+ if (wasInserted)
+ replaceSym();
+ else if (auto *lazy = dyn_cast<LazySymbol>(s))
+ lazy->fetch();
else {
- auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
- if (!ExistingFunction) {
- reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
- return S;
+ auto existingFunction = dyn_cast<FunctionSymbol>(s);
+ if (!existingFunction) {
+ reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION);
+ return s;
}
- if (!ExistingFunction->Signature && Sig)
- ExistingFunction->Signature = Sig;
- if (IsCalledDirectly && !signatureMatches(ExistingFunction, Sig))
- if (getFunctionVariant(S, Sig, File, &S))
- ReplaceSym();
+ if (!existingFunction->signature && sig)
+ existingFunction->signature = sig;
+ if (isCalledDirectly && !signatureMatches(existingFunction, sig))
+ if (getFunctionVariant(s, sig, file, &s))
+ replaceSym();
}
- return S;
+ return s;
}
-Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
- InputFile *File) {
- LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
+Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags,
+ InputFile *file) {
+ LLVM_DEBUG(dbgs() << "addUndefinedData: " << name << "\n");
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, File);
- if (S->Traced)
- printTraceSymbolUndefined(Name, File);
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
+ if (s->traced)
+ printTraceSymbolUndefined(name, file);
- if (WasInserted)
- replaceSymbol<UndefinedData>(S, Name, Flags, File);
- else if (auto *Lazy = dyn_cast<LazySymbol>(S))
- Lazy->fetch();
- else if (S->isDefined())
- checkDataType(S, File);
- return S;
+ if (wasInserted)
+ replaceSymbol<UndefinedData>(s, name, flags, file);
+ else if (auto *lazy = dyn_cast<LazySymbol>(s))
+ lazy->fetch();
+ else if (s->isDefined())
+ checkDataType(s, file);
+ return s;
}
-Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName,
- StringRef ImportModule, uint32_t Flags,
- InputFile *File,
- const WasmGlobalType *Type) {
- LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
+Symbol *SymbolTable::addUndefinedGlobal(StringRef name, StringRef importName,
+ StringRef importModule, uint32_t flags,
+ InputFile *file,
+ const WasmGlobalType *type) {
+ LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << name << "\n");
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, File);
- if (S->Traced)
- printTraceSymbolUndefined(Name, File);
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
+ if (s->traced)
+ printTraceSymbolUndefined(name, file);
- if (WasInserted)
- replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags,
- File, Type);
- else if (auto *Lazy = dyn_cast<LazySymbol>(S))
- Lazy->fetch();
- else if (S->isDefined())
- checkGlobalType(S, File, Type);
- return S;
+ if (wasInserted)
+ replaceSymbol<UndefinedGlobal>(s, name, importName, importModule, flags,
+ file, type);
+ else if (auto *lazy = dyn_cast<LazySymbol>(s))
+ lazy->fetch();
+ else if (s->isDefined())
+ checkGlobalType(s, file, type);
+ return s;
}
-void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
- LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
- StringRef Name = Sym->getName();
+void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) {
+ LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n");
+ StringRef name = sym->getName();
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insertName(Name);
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insertName(name);
- if (WasInserted) {
- replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym);
+ if (wasInserted) {
+ replaceSymbol<LazySymbol>(s, name, 0, file, *sym);
return;
}
- if (!S->isUndefined())
+ if (!s->isUndefined())
return;
// The existing symbol is undefined, load a new one from the archive,
// unless the the existing symbol is weak in which case replace the undefined
// symbols with a LazySymbol.
- if (S->isWeak()) {
- const WasmSignature *OldSig = nullptr;
+ if (s->isWeak()) {
+ const WasmSignature *oldSig = nullptr;
// In the case of an UndefinedFunction we need to preserve the expected
// signature.
- if (auto *F = dyn_cast<UndefinedFunction>(S))
- OldSig = F->Signature;
+ if (auto *f = dyn_cast<UndefinedFunction>(s))
+ oldSig = f->signature;
LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
- auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK,
- File, *Sym);
- NewSym->Signature = OldSig;
+ auto newSym = replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK,
+ file, *sym);
+ newSym->signature = oldSig;
return;
}
LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
- File->addMember(Sym);
+ file->addMember(sym);
}
-bool SymbolTable::addComdat(StringRef Name) {
- return ComdatGroups.insert(CachedHashStringRef(Name)).second;
+bool SymbolTable::addComdat(StringRef name) {
+ return comdatGroups.insert(CachedHashStringRef(name)).second;
}
// The new signature doesn't match. Create a variant to the symbol with the
// signature encoded in the name and return that instead. These symbols are
// then unified later in handleSymbolVariants.
-bool SymbolTable::getFunctionVariant(Symbol* Sym, const WasmSignature *Sig,
- const InputFile *File, Symbol **Out) {
- LLVM_DEBUG(dbgs() << "getFunctionVariant: " << Sym->getName() << " -> "
- << " " << toString(*Sig) << "\n");
- Symbol *Variant = nullptr;
+bool SymbolTable::getFunctionVariant(Symbol* sym, const WasmSignature *sig,
+ const InputFile *file, Symbol **out) {
+ LLVM_DEBUG(dbgs() << "getFunctionVariant: " << sym->getName() << " -> "
+ << " " << toString(*sig) << "\n");
+ Symbol *variant = nullptr;
// Linear search through symbol variants. Should never be more than two
// or three entries here.
- auto &Variants = SymVariants[CachedHashStringRef(Sym->getName())];
- if (Variants.empty())
- Variants.push_back(Sym);
+ auto &variants = symVariants[CachedHashStringRef(sym->getName())];
+ if (variants.empty())
+ variants.push_back(sym);
- for (Symbol* V : Variants) {
- if (*V->getSignature() == *Sig) {
- Variant = V;
+ for (Symbol* v : variants) {
+ if (*v->getSignature() == *sig) {
+ variant = v;
break;
}
}
- bool WasAdded = !Variant;
- if (WasAdded) {
+ bool wasAdded = !variant;
+ if (wasAdded) {
// Create a new variant;
LLVM_DEBUG(dbgs() << "added new variant\n");
- Variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Variants.push_back(Variant);
+ variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ variants.push_back(variant);
} else {
- LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*Variant) << "\n");
- assert(*Variant->getSignature() == *Sig);
+ LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*variant) << "\n");
+ assert(*variant->getSignature() == *sig);
}
- *Out = Variant;
- return WasAdded;
+ *out = variant;
+ return wasAdded;
}
// Set a flag for --trace-symbol so that we can print out a log message
// if a new symbol with the same name is inserted into the symbol table.
-void SymbolTable::trace(StringRef Name) {
- SymMap.insert({CachedHashStringRef(Name), -1});
+void SymbolTable::trace(StringRef name) {
+ symMap.insert({CachedHashStringRef(name), -1});
}
-void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) {
+void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {
// Swap symbols as instructed by -wrap.
- int &OrigIdx = SymMap[CachedHashStringRef(Sym->getName())];
- int &RealIdx= SymMap[CachedHashStringRef(Real->getName())];
- int &WrapIdx = SymMap[CachedHashStringRef(Wrap->getName())];
- LLVM_DEBUG(dbgs() << "wrap: " << Sym->getName() << "\n");
+ int &origIdx = symMap[CachedHashStringRef(sym->getName())];
+ int &realIdx= symMap[CachedHashStringRef(real->getName())];
+ int &wrapIdx = symMap[CachedHashStringRef(wrap->getName())];
+ LLVM_DEBUG(dbgs() << "wrap: " << sym->getName() << "\n");
// Anyone looking up __real symbols should get the original
- RealIdx = OrigIdx;
+ realIdx = origIdx;
// Anyone looking up the original should get the __wrap symbol
- OrigIdx = WrapIdx;
+ origIdx = wrapIdx;
}
-static const uint8_t UnreachableFn[] = {
+static const uint8_t unreachableFn[] = {
0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
0x00 /* opcode unreachable */, 0x0b /* opcode end */
};
// This is used by handleWeakUndefines in order to generate a callable
// equivalent of an undefined function and also handleSymbolVariants for
// undefined functions that don't match the signature of the definition.
-InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym,
- const WasmSignature &Sig,
- StringRef DebugName) {
- auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
- Func->setBody(UnreachableFn);
- SyntheticFunctions.emplace_back(Func);
- replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr,
- Func);
- return Func;
+InputFunction *SymbolTable::replaceWithUnreachable(Symbol *sym,
+ const WasmSignature &sig,
+ StringRef debugName) {
+ auto *func = make<SyntheticFunction>(sig, sym->getName(), debugName);
+ func->setBody(unreachableFn);
+ syntheticFunctions.emplace_back(func);
+ replaceSymbol<DefinedFunction>(sym, sym->getName(), sym->getFlags(), nullptr,
+ func);
+ return func;
}
// For weak undefined functions, there may be "call" instructions that reference
// will abort at runtime, so that relocations can still provided an operand to
// the call instruction that passes Wasm validation.
void SymbolTable::handleWeakUndefines() {
- for (Symbol *Sym : getSymbols()) {
- if (!Sym->isUndefWeak())
+ for (Symbol *sym : getSymbols()) {
+ if (!sym->isUndefWeak())
continue;
- const WasmSignature *Sig = Sym->getSignature();
- if (!Sig) {
+ const WasmSignature *sig = sym->getSignature();
+ if (!sig) {
// It is possible for undefined functions not to have a signature (eg. if
// added via "--undefined"), but weak undefined ones do have a signature.
// Lazy symbols may not be functions and therefore Sig can still be null
// in some circumstantce.
- assert(!isa<FunctionSymbol>(Sym));
+ assert(!isa<FunctionSymbol>(sym));
continue;
}
// Add a synthetic dummy for weak undefined functions. These dummies will
// be GC'd if not used as the target of any "call" instructions.
- StringRef DebugName = Saver.save("undefined:" + toString(*Sym));
- InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName);
+ StringRef debugName = saver.save("undefined:" + toString(*sym));
+ InputFunction* func = replaceWithUnreachable(sym, *sig, debugName);
// Ensure it compares equal to the null pointer, and so that table relocs
// don't pull in the stub body (only call-operand relocs should do that).
- Func->setTableIndex(0);
+ func->setTableIndex(0);
// Hide our dummy to prevent export.
- Sym->setHidden(true);
+ sym->setHidden(true);
}
}
-static void reportFunctionSignatureMismatch(StringRef SymName,
- FunctionSymbol *A,
- FunctionSymbol *B, bool IsError) {
- std::string msg = ("function signature mismatch: " + SymName +
- "\n>>> defined as " + toString(*A->Signature) + " in " +
- toString(A->getFile()) + "\n>>> defined as " +
- toString(*B->Signature) + " in " + toString(B->getFile()))
+static void reportFunctionSignatureMismatch(StringRef symName,
+ FunctionSymbol *a,
+ FunctionSymbol *b, bool isError) {
+ std::string msg = ("function signature mismatch: " + symName +
+ "\n>>> defined as " + toString(*a->signature) + " in " +
+ toString(a->getFile()) + "\n>>> defined as " +
+ toString(*b->signature) + " in " + toString(b->getFile()))
.str();
- if (IsError)
+ if (isError)
error(msg);
else
warn(msg);
// Remove any variant symbols that were created due to function signature
// mismatches.
void SymbolTable::handleSymbolVariants() {
- for (auto Pair : SymVariants) {
+ for (auto pair : symVariants) {
// Push the initial symbol onto the list of variants.
- StringRef SymName = Pair.first.val();
- std::vector<Symbol *> &Variants = Pair.second;
+ StringRef symName = pair.first.val();
+ std::vector<Symbol *> &variants = pair.second;
#ifndef NDEBUG
- LLVM_DEBUG(dbgs() << "symbol with (" << Variants.size()
- << ") variants: " << SymName << "\n");
- for (auto *S: Variants) {
- auto *F = cast<FunctionSymbol>(S);
- LLVM_DEBUG(dbgs() << " variant: " + F->getName() << " "
- << toString(*F->Signature) << "\n");
+ LLVM_DEBUG(dbgs() << "symbol with (" << variants.size()
+ << ") variants: " << symName << "\n");
+ for (auto *s: variants) {
+ auto *f = cast<FunctionSymbol>(s);
+ LLVM_DEBUG(dbgs() << " variant: " + f->getName() << " "
+ << toString(*f->signature) << "\n");
}
#endif
// Find the one definition.
- DefinedFunction *Defined = nullptr;
- for (auto *Symbol : Variants) {
- if (auto F = dyn_cast<DefinedFunction>(Symbol)) {
- Defined = F;
+ DefinedFunction *defined = nullptr;
+ for (auto *symbol : variants) {
+ if (auto f = dyn_cast<DefinedFunction>(symbol)) {
+ defined = f;
break;
}
}
// If there are no definitions, and the undefined symbols disagree on
// the signature, there is not we can do since we don't know which one
// to use as the signature on the import.
- if (!Defined) {
- reportFunctionSignatureMismatch(SymName,
- cast<FunctionSymbol>(Variants[0]),
- cast<FunctionSymbol>(Variants[1]), true);
+ if (!defined) {
+ reportFunctionSignatureMismatch(symName,
+ cast<FunctionSymbol>(variants[0]),
+ cast<FunctionSymbol>(variants[1]), true);
return;
}
- for (auto *Symbol : Variants) {
- if (Symbol != Defined) {
- auto *F = cast<FunctionSymbol>(Symbol);
- reportFunctionSignatureMismatch(SymName, F, Defined, false);
- StringRef DebugName = Saver.save("unreachable:" + toString(*F));
- replaceWithUnreachable(F, *F->Signature, DebugName);
+ for (auto *symbol : variants) {
+ if (symbol != defined) {
+ auto *f = cast<FunctionSymbol>(symbol);
+ reportFunctionSignatureMismatch(symName, f, defined, false);
+ StringRef debugName = saver.save("unreachable:" + toString(*f));
+ replaceWithUnreachable(f, *f->signature, debugName);
}
}
}
// There is one add* function per symbol type.
class SymbolTable {
public:
- void wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap);
+ void wrap(Symbol *sym, Symbol *real, Symbol *wrap);
- void addFile(InputFile *File);
+ void addFile(InputFile *file);
void addCombinedLTOObject();
- ArrayRef<Symbol *> getSymbols() const { return SymVector; }
+ ArrayRef<Symbol *> getSymbols() const { return symVector; }
- Symbol *find(StringRef Name);
+ Symbol *find(StringRef name);
- void replace(StringRef Name, Symbol* Sym);
+ void replace(StringRef name, Symbol* sym);
- void trace(StringRef Name);
+ void trace(StringRef name);
- Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *File,
- InputFunction *Function);
- Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *File,
- InputSegment *Segment, uint32_t Address,
- uint32_t Size);
- Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
- InputGlobal *G);
- Symbol *addDefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
- InputEvent *E);
+ Symbol *addDefinedFunction(StringRef name, uint32_t flags, InputFile *file,
+ InputFunction *function);
+ Symbol *addDefinedData(StringRef name, uint32_t flags, InputFile *file,
+ InputSegment *segment, uint32_t address,
+ uint32_t size);
+ Symbol *addDefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
+ InputGlobal *g);
+ Symbol *addDefinedEvent(StringRef name, uint32_t flags, InputFile *file,
+ InputEvent *e);
- Symbol *addUndefinedFunction(StringRef Name, StringRef ImportName,
- StringRef ImportModule, uint32_t Flags,
- InputFile *File, const WasmSignature *Signature,
- bool IsCalledDirectly);
- Symbol *addUndefinedData(StringRef Name, uint32_t Flags, InputFile *File);
- Symbol *addUndefinedGlobal(StringRef Name, StringRef ImportName,
- StringRef ImportModule, uint32_t Flags,
- InputFile *File, const WasmGlobalType *Type);
+ Symbol *addUndefinedFunction(StringRef name, StringRef importName,
+ StringRef importModule, uint32_t flags,
+ InputFile *file, const WasmSignature *signature,
+ bool isCalledDirectly);
+ Symbol *addUndefinedData(StringRef name, uint32_t flags, InputFile *file);
+ Symbol *addUndefinedGlobal(StringRef name, StringRef importName,
+ StringRef importModule, uint32_t flags,
+ InputFile *file, const WasmGlobalType *type);
- void addLazy(ArchiveFile *F, const llvm::object::Archive::Symbol *Sym);
+ void addLazy(ArchiveFile *f, const llvm::object::Archive::Symbol *sym);
- bool addComdat(StringRef Name);
+ bool addComdat(StringRef name);
- DefinedData *addSyntheticDataSymbol(StringRef Name, uint32_t Flags);
- DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags,
- InputGlobal *Global);
- DefinedFunction *addSyntheticFunction(StringRef Name, uint32_t Flags,
- InputFunction *Function);
- DefinedData *addOptionalDataSymbol(StringRef Name, uint32_t Value = 0,
- uint32_t Flags = 0);
+ DefinedData *addSyntheticDataSymbol(StringRef name, uint32_t flags);
+ DefinedGlobal *addSyntheticGlobal(StringRef name, uint32_t flags,
+ InputGlobal *global);
+ DefinedFunction *addSyntheticFunction(StringRef name, uint32_t flags,
+ InputFunction *function);
+ DefinedData *addOptionalDataSymbol(StringRef name, uint32_t value = 0,
+ uint32_t flags = 0);
void handleSymbolVariants();
void handleWeakUndefines();
- std::vector<ObjFile *> ObjectFiles;
- std::vector<SharedFile *> SharedFiles;
- std::vector<BitcodeFile *> BitcodeFiles;
- std::vector<InputFunction *> SyntheticFunctions;
- std::vector<InputGlobal *> SyntheticGlobals;
+ std::vector<ObjFile *> objectFiles;
+ std::vector<SharedFile *> sharedFiles;
+ std::vector<BitcodeFile *> bitcodeFiles;
+ std::vector<InputFunction *> syntheticFunctions;
+ std::vector<InputGlobal *> syntheticGlobals;
private:
- std::pair<Symbol *, bool> insert(StringRef Name, const InputFile *File);
- std::pair<Symbol *, bool> insertName(StringRef Name);
+ std::pair<Symbol *, bool> insert(StringRef name, const InputFile *file);
+ std::pair<Symbol *, bool> insertName(StringRef name);
- bool getFunctionVariant(Symbol* Sym, const WasmSignature *Sig,
- const InputFile *File, Symbol **Out);
- InputFunction *replaceWithUnreachable(Symbol *Sym, const WasmSignature &Sig,
- StringRef DebugName);
+ bool getFunctionVariant(Symbol* sym, const WasmSignature *sig,
+ const InputFile *file, Symbol **out);
+ InputFunction *replaceWithUnreachable(Symbol *sym, const WasmSignature &sig,
+ StringRef debugName);
// Maps symbol names to index into the SymVector. -1 means that symbols
// is to not yet in the vector but it should have tracing enabled if it is
// ever added.
- llvm::DenseMap<llvm::CachedHashStringRef, int> SymMap;
- std::vector<Symbol *> SymVector;
+ llvm::DenseMap<llvm::CachedHashStringRef, int> symMap;
+ std::vector<Symbol *> symVector;
// For certain symbols types, e.g. function symbols, we allow for muliple
// variants of the same symbol with different signatures.
- llvm::DenseMap<llvm::CachedHashStringRef, std::vector<Symbol *>> SymVariants;
+ llvm::DenseMap<llvm::CachedHashStringRef, std::vector<Symbol *>> symVariants;
// Comdat groups define "link once" sections. If two comdat groups have the
// same name, only one of them is linked, and the other is ignored. This set
// is used to uniquify them.
- llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups;
+ llvm::DenseSet<llvm::CachedHashStringRef> comdatGroups;
// For LTO.
- std::unique_ptr<BitcodeCompiler> LTO;
+ std::unique_ptr<BitcodeCompiler> lto;
};
-extern SymbolTable *Symtab;
+extern SymbolTable *symtab;
} // namespace wasm
} // namespace lld
using namespace lld;
using namespace lld::wasm;
-DefinedFunction *WasmSym::CallCtors;
-DefinedFunction *WasmSym::InitMemory;
-DefinedFunction *WasmSym::ApplyRelocs;
-DefinedData *WasmSym::DsoHandle;
-DefinedData *WasmSym::DataEnd;
-DefinedData *WasmSym::GlobalBase;
-DefinedData *WasmSym::HeapBase;
-GlobalSymbol *WasmSym::StackPointer;
-UndefinedGlobal *WasmSym::TableBase;
-UndefinedGlobal *WasmSym::MemoryBase;
+DefinedFunction *WasmSym::callCtors;
+DefinedFunction *WasmSym::initMemory;
+DefinedFunction *WasmSym::applyRelocs;
+DefinedData *WasmSym::dsoHandle;
+DefinedData *WasmSym::dataEnd;
+DefinedData *WasmSym::globalBase;
+DefinedData *WasmSym::heapBase;
+GlobalSymbol *WasmSym::stackPointer;
+UndefinedGlobal *WasmSym::tableBase;
+UndefinedGlobal *WasmSym::memoryBase;
WasmSymbolType Symbol::getWasmType() const {
if (isa<FunctionSymbol>(this))
}
const WasmSignature *Symbol::getSignature() const {
- if (auto* F = dyn_cast<FunctionSymbol>(this))
- return F->Signature;
- if (auto *L = dyn_cast<LazySymbol>(this))
- return L->Signature;
+ if (auto* f = dyn_cast<FunctionSymbol>(this))
+ return f->signature;
+ if (auto *l = dyn_cast<LazySymbol>(this))
+ return l->signature;
return nullptr;
}
InputChunk *Symbol::getChunk() const {
- if (auto *F = dyn_cast<DefinedFunction>(this))
- return F->Function;
- if (auto *D = dyn_cast<DefinedData>(this))
- return D->Segment;
+ if (auto *f = dyn_cast<DefinedFunction>(this))
+ return f->function;
+ if (auto *d = dyn_cast<DefinedData>(this))
+ return d->segment;
return nullptr;
}
bool Symbol::isDiscarded() const {
- if (InputChunk *C = getChunk())
- return C->Discarded;
+ if (InputChunk *c = getChunk())
+ return c->discarded;
return false;
}
bool Symbol::isLive() const {
- if (auto *G = dyn_cast<DefinedGlobal>(this))
- return G->Global->Live;
- if (auto *E = dyn_cast<DefinedEvent>(this))
- return E->Event->Live;
- if (InputChunk *C = getChunk())
- return C->Live;
- return Referenced;
+ if (auto *g = dyn_cast<DefinedGlobal>(this))
+ return g->global->live;
+ if (auto *e = dyn_cast<DefinedEvent>(this))
+ return e->event->live;
+ if (InputChunk *c = getChunk())
+ return c->live;
+ return referenced;
}
void Symbol::markLive() {
assert(!isDiscarded());
- if (auto *G = dyn_cast<DefinedGlobal>(this))
- G->Global->Live = true;
- if (auto *E = dyn_cast<DefinedEvent>(this))
- E->Event->Live = true;
- if (InputChunk *C = getChunk())
- C->Live = true;
- Referenced = true;
+ if (auto *g = dyn_cast<DefinedGlobal>(this))
+ g->global->live = true;
+ if (auto *e = dyn_cast<DefinedEvent>(this))
+ e->event->live = true;
+ if (InputChunk *c = getChunk())
+ c->live = true;
+ referenced = true;
}
uint32_t Symbol::getOutputSymbolIndex() const {
- assert(OutputSymbolIndex != INVALID_INDEX);
- return OutputSymbolIndex;
+ assert(outputSymbolIndex != INVALID_INDEX);
+ return outputSymbolIndex;
}
-void Symbol::setOutputSymbolIndex(uint32_t Index) {
- LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index
+void Symbol::setOutputSymbolIndex(uint32_t index) {
+ LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << name << " -> " << index
<< "\n");
- assert(OutputSymbolIndex == INVALID_INDEX);
- OutputSymbolIndex = Index;
+ assert(outputSymbolIndex == INVALID_INDEX);
+ outputSymbolIndex = index;
}
-void Symbol::setGOTIndex(uint32_t Index) {
- LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n");
- assert(GOTIndex == INVALID_INDEX);
+void Symbol::setGOTIndex(uint32_t index) {
+ LLVM_DEBUG(dbgs() << "setGOTIndex " << name << " -> " << index << "\n");
+ assert(gotIndex == INVALID_INDEX);
// Any symbol that is assigned a GOT entry must be exported othewise the
// dynamic linker won't be able create the entry that contains it.
- ForceExport = true;
- GOTIndex = Index;
+ forceExport = true;
+ gotIndex = index;
}
bool Symbol::isWeak() const {
- return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
+ return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
}
bool Symbol::isLocal() const {
- return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
+ return (flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
}
bool Symbol::isHidden() const {
- return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
+ return (flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
}
-void Symbol::setHidden(bool IsHidden) {
- LLVM_DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n");
- Flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
- if (IsHidden)
- Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
+void Symbol::setHidden(bool isHidden) {
+ LLVM_DEBUG(dbgs() << "setHidden: " << name << " -> " << isHidden << "\n");
+ flags &= ~WASM_SYMBOL_VISIBILITY_MASK;
+ if (isHidden)
+ flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
else
- Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
+ flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
}
bool Symbol::isExported() const {
if (!isDefined() || isLocal())
return false;
- if (ForceExport || Config->ExportAll)
+ if (forceExport || config->exportAll)
return true;
- if (Config->ExportDynamic && !isHidden())
+ if (config->exportDynamic && !isHidden())
return true;
- return Flags & WASM_SYMBOL_EXPORTED;
+ return flags & WASM_SYMBOL_EXPORTED;
}
uint32_t FunctionSymbol::getFunctionIndex() const {
- if (auto *F = dyn_cast<DefinedFunction>(this))
- return F->Function->getFunctionIndex();
- assert(FunctionIndex != INVALID_INDEX);
- return FunctionIndex;
+ if (auto *f = dyn_cast<DefinedFunction>(this))
+ return f->function->getFunctionIndex();
+ assert(functionIndex != INVALID_INDEX);
+ return functionIndex;
}
-void FunctionSymbol::setFunctionIndex(uint32_t Index) {
- LLVM_DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n");
- assert(FunctionIndex == INVALID_INDEX);
- FunctionIndex = Index;
+void FunctionSymbol::setFunctionIndex(uint32_t index) {
+ LLVM_DEBUG(dbgs() << "setFunctionIndex " << name << " -> " << index << "\n");
+ assert(functionIndex == INVALID_INDEX);
+ functionIndex = index;
}
bool FunctionSymbol::hasFunctionIndex() const {
- if (auto *F = dyn_cast<DefinedFunction>(this))
- return F->Function->hasFunctionIndex();
- return FunctionIndex != INVALID_INDEX;
+ if (auto *f = dyn_cast<DefinedFunction>(this))
+ return f->function->hasFunctionIndex();
+ return functionIndex != INVALID_INDEX;
}
uint32_t FunctionSymbol::getTableIndex() const {
- if (auto *F = dyn_cast<DefinedFunction>(this))
- return F->Function->getTableIndex();
- assert(TableIndex != INVALID_INDEX);
- return TableIndex;
+ if (auto *f = dyn_cast<DefinedFunction>(this))
+ return f->function->getTableIndex();
+ assert(tableIndex != INVALID_INDEX);
+ return tableIndex;
}
bool FunctionSymbol::hasTableIndex() const {
- if (auto *F = dyn_cast<DefinedFunction>(this))
- return F->Function->hasTableIndex();
- return TableIndex != INVALID_INDEX;
+ if (auto *f = dyn_cast<DefinedFunction>(this))
+ return f->function->hasTableIndex();
+ return tableIndex != INVALID_INDEX;
}
-void FunctionSymbol::setTableIndex(uint32_t Index) {
+void FunctionSymbol::setTableIndex(uint32_t index) {
// For imports, we set the table index here on the Symbol; for defined
// functions we set the index on the InputFunction so that we don't export
// the same thing twice (keeps the table size down).
- if (auto *F = dyn_cast<DefinedFunction>(this)) {
- F->Function->setTableIndex(Index);
+ if (auto *f = dyn_cast<DefinedFunction>(this)) {
+ f->function->setTableIndex(index);
return;
}
- LLVM_DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
- assert(TableIndex == INVALID_INDEX);
- TableIndex = Index;
+ LLVM_DEBUG(dbgs() << "setTableIndex " << name << " -> " << index << "\n");
+ assert(tableIndex == INVALID_INDEX);
+ tableIndex = index;
}
-DefinedFunction::DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
- InputFunction *Function)
- : FunctionSymbol(Name, DefinedFunctionKind, Flags, F,
- Function ? &Function->Signature : nullptr),
- Function(Function) {}
+DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
+ InputFunction *function)
+ : FunctionSymbol(name, DefinedFunctionKind, flags, f,
+ function ? &function->signature : nullptr),
+ function(function) {}
uint32_t DefinedData::getVirtualAddress() const {
LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
- if (Segment)
- return Segment->OutputSeg->StartVA + Segment->OutputSegmentOffset + Offset;
- return Offset;
+ if (segment)
+ return segment->outputSeg->startVA + segment->outputSegmentOffset + offset;
+ return offset;
}
-void DefinedData::setVirtualAddress(uint32_t Value) {
- LLVM_DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
- assert(!Segment);
- Offset = Value;
+void DefinedData::setVirtualAddress(uint32_t value) {
+ LLVM_DEBUG(dbgs() << "setVirtualAddress " << name << " -> " << value << "\n");
+ assert(!segment);
+ offset = value;
}
uint32_t DefinedData::getOutputSegmentOffset() const {
LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n");
- return Segment->OutputSegmentOffset + Offset;
+ return segment->outputSegmentOffset + offset;
}
uint32_t DefinedData::getOutputSegmentIndex() const {
LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n");
- return Segment->OutputSeg->Index;
+ return segment->outputSeg->index;
}
uint32_t GlobalSymbol::getGlobalIndex() const {
- if (auto *F = dyn_cast<DefinedGlobal>(this))
- return F->Global->getGlobalIndex();
- assert(GlobalIndex != INVALID_INDEX);
- return GlobalIndex;
+ if (auto *f = dyn_cast<DefinedGlobal>(this))
+ return f->global->getGlobalIndex();
+ assert(globalIndex != INVALID_INDEX);
+ return globalIndex;
}
-void GlobalSymbol::setGlobalIndex(uint32_t Index) {
- LLVM_DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n");
- assert(GlobalIndex == INVALID_INDEX);
- GlobalIndex = Index;
+void GlobalSymbol::setGlobalIndex(uint32_t index) {
+ LLVM_DEBUG(dbgs() << "setGlobalIndex " << name << " -> " << index << "\n");
+ assert(globalIndex == INVALID_INDEX);
+ globalIndex = index;
}
bool GlobalSymbol::hasGlobalIndex() const {
- if (auto *F = dyn_cast<DefinedGlobal>(this))
- return F->Global->hasGlobalIndex();
- return GlobalIndex != INVALID_INDEX;
+ if (auto *f = dyn_cast<DefinedGlobal>(this))
+ return f->global->hasGlobalIndex();
+ return globalIndex != INVALID_INDEX;
}
-DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
- InputGlobal *Global)
- : GlobalSymbol(Name, DefinedGlobalKind, Flags, File,
- Global ? &Global->getType() : nullptr),
- Global(Global) {}
+DefinedGlobal::DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
+ InputGlobal *global)
+ : GlobalSymbol(name, DefinedGlobalKind, flags, file,
+ global ? &global->getType() : nullptr),
+ global(global) {}
uint32_t EventSymbol::getEventIndex() const {
- if (auto *F = dyn_cast<DefinedEvent>(this))
- return F->Event->getEventIndex();
- assert(EventIndex != INVALID_INDEX);
- return EventIndex;
+ if (auto *f = dyn_cast<DefinedEvent>(this))
+ return f->event->getEventIndex();
+ assert(eventIndex != INVALID_INDEX);
+ return eventIndex;
}
-void EventSymbol::setEventIndex(uint32_t Index) {
- LLVM_DEBUG(dbgs() << "setEventIndex " << Name << " -> " << Index << "\n");
- assert(EventIndex == INVALID_INDEX);
- EventIndex = Index;
+void EventSymbol::setEventIndex(uint32_t index) {
+ LLVM_DEBUG(dbgs() << "setEventIndex " << name << " -> " << index << "\n");
+ assert(eventIndex == INVALID_INDEX);
+ eventIndex = index;
}
bool EventSymbol::hasEventIndex() const {
- if (auto *F = dyn_cast<DefinedEvent>(this))
- return F->Event->hasEventIndex();
- return EventIndex != INVALID_INDEX;
+ if (auto *f = dyn_cast<DefinedEvent>(this))
+ return f->event->hasEventIndex();
+ return eventIndex != INVALID_INDEX;
}
-DefinedEvent::DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
- InputEvent *Event)
- : EventSymbol(Name, DefinedEventKind, Flags, File,
- Event ? &Event->getType() : nullptr,
- Event ? &Event->Signature : nullptr),
- Event(Event) {}
+DefinedEvent::DefinedEvent(StringRef name, uint32_t flags, InputFile *file,
+ InputEvent *event)
+ : EventSymbol(name, DefinedEventKind, flags, file,
+ event ? &event->getType() : nullptr,
+ event ? &event->signature : nullptr),
+ event(event) {}
const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
- assert(Section->OutputSec && Section->OutputSec->SectionSym);
- return Section->OutputSec->SectionSym;
+ assert(section->outputSec && section->outputSec->sectionSym);
+ return section->outputSec->sectionSym;
}
-void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); }
+void LazySymbol::fetch() { cast<ArchiveFile>(file)->addMember(&archiveSymbol); }
-std::string lld::toString(const wasm::Symbol &Sym) {
- return lld::maybeDemangleSymbol(Sym.getName());
+std::string lld::toString(const wasm::Symbol &sym) {
+ return lld::maybeDemangleSymbol(sym.getName());
}
-std::string lld::maybeDemangleSymbol(StringRef Name) {
- if (Config->Demangle)
- if (Optional<std::string> S = demangleItanium(Name))
- return *S;
- return Name;
+std::string lld::maybeDemangleSymbol(StringRef name) {
+ if (config->demangle)
+ if (Optional<std::string> s = demangleItanium(name))
+ return *s;
+ return name;
}
-std::string lld::toString(wasm::Symbol::Kind Kind) {
- switch (Kind) {
+std::string lld::toString(wasm::Symbol::Kind kind) {
+ switch (kind) {
case wasm::Symbol::DefinedFunctionKind:
return "DefinedFunction";
case wasm::Symbol::DefinedDataKind:
}
-void lld::wasm::printTraceSymbolUndefined(StringRef Name, const InputFile* File) {
- message(toString(File) + ": reference to " + Name);
+void lld::wasm::printTraceSymbolUndefined(StringRef name, const InputFile* file) {
+ message(toString(file) + ": reference to " + name);
}
// Print out a log message for --trace-symbol.
-void lld::wasm::printTraceSymbol(Symbol *Sym) {
+void lld::wasm::printTraceSymbol(Symbol *sym) {
// Undefined symbols are traced via printTraceSymbolUndefined
- if (Sym->isUndefined())
+ if (sym->isUndefined())
return;
- std::string S;
- if (Sym->isLazy())
- S = ": lazy definition of ";
+ std::string s;
+ if (sym->isLazy())
+ s = ": lazy definition of ";
else
- S = ": definition of ";
+ s = ": definition of ";
- message(toString(Sym->getFile()) + S + Sym->getName());
+ message(toString(sym->getFile()) + s + sym->getName());
}
-const char *lld::wasm::DefaultModule = "env";
-const char *lld::wasm::FunctionTableName = "__indirect_function_table";
+const char *lld::wasm::defaultModule = "env";
+const char *lld::wasm::functionTableName = "__indirect_function_table";
// Shared string constants
// The default module name to use for symbol imports.
-extern const char *DefaultModule;
+extern const char *defaultModule;
// The name under which to import or export the wasm table.
-extern const char *FunctionTableName;
+extern const char *functionTableName;
using llvm::wasm::WasmSymbolType;
LazyKind,
};
- Kind kind() const { return SymbolKind; }
+ Kind kind() const { return symbolKind; }
bool isDefined() const { return !isLazy() && !isUndefined(); }
bool isUndefined() const {
- return SymbolKind == UndefinedFunctionKind ||
- SymbolKind == UndefinedDataKind || SymbolKind == UndefinedGlobalKind;
+ return symbolKind == UndefinedFunctionKind ||
+ symbolKind == UndefinedDataKind || symbolKind == UndefinedGlobalKind;
}
- bool isLazy() const { return SymbolKind == LazyKind; }
+ bool isLazy() const { return symbolKind == LazyKind; }
bool isLocal() const;
bool isWeak() const;
}
// Returns the symbol name.
- StringRef getName() const { return Name; }
+ StringRef getName() const { return name; }
// Returns the file from which this symbol was created.
- InputFile *getFile() const { return File; }
+ InputFile *getFile() const { return file; }
- uint32_t getFlags() const { return Flags; }
+ uint32_t getFlags() const { return flags; }
InputChunk *getChunk() const;
// final image.
void markLive();
- void setHidden(bool IsHidden);
+ void setHidden(bool isHidden);
// Get/set the index in the output symbol table. This is only used for
// relocatable output.
uint32_t getOutputSymbolIndex() const;
- void setOutputSymbolIndex(uint32_t Index);
+ void setOutputSymbolIndex(uint32_t index);
WasmSymbolType getWasmType() const;
bool isExported() const;
const WasmSignature* getSignature() const;
- bool isInGOT() const { return GOTIndex != INVALID_INDEX; }
+ bool isInGOT() const { return gotIndex != INVALID_INDEX; }
uint32_t getGOTIndex() const {
- assert(GOTIndex != INVALID_INDEX);
- return GOTIndex;
+ assert(gotIndex != INVALID_INDEX);
+ return gotIndex;
}
- void setGOTIndex(uint32_t Index);
- bool hasGOTIndex() const { return GOTIndex != INVALID_INDEX; }
+ void setGOTIndex(uint32_t index);
+ bool hasGOTIndex() const { return gotIndex != INVALID_INDEX; }
protected:
- Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
- : Name(Name), File(F), Flags(Flags), SymbolKind(K),
- Referenced(!Config->GcSections), IsUsedInRegularObj(false),
- ForceExport(false), CanInline(false), Traced(false) {}
-
- StringRef Name;
- InputFile *File;
- uint32_t Flags;
- uint32_t OutputSymbolIndex = INVALID_INDEX;
- uint32_t GOTIndex = INVALID_INDEX;
- Kind SymbolKind;
+ Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
+ : name(name), file(f), flags(flags), symbolKind(k),
+ referenced(!config->gcSections), isUsedInRegularObj(false),
+ forceExport(false), canInline(false), traced(false) {}
+
+ StringRef name;
+ InputFile *file;
+ uint32_t flags;
+ uint32_t outputSymbolIndex = INVALID_INDEX;
+ uint32_t gotIndex = INVALID_INDEX;
+ Kind symbolKind;
public:
- bool Referenced : 1;
+ bool referenced : 1;
// True if the symbol was used for linking and thus need to be added to the
// output file's symbol table. This is true for all symbols except for
// unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that
// are unreferenced except by other bitcode objects.
- bool IsUsedInRegularObj : 1;
+ bool isUsedInRegularObj : 1;
// True if ths symbol is explicity marked for export (i.e. via the -e/--export
// command line flag)
- bool ForceExport : 1;
+ bool forceExport : 1;
// False if LTO shouldn't inline whatever this symbol points to. If a symbol
// is overwritten after LTO, LTO shouldn't inline the symbol because it
// doesn't know the final contents of the symbol.
- bool CanInline : 1;
+ bool canInline : 1;
// True if this symbol is specified by --trace-symbol option.
- bool Traced : 1;
+ bool traced : 1;
};
class FunctionSymbol : public Symbol {
public:
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedFunctionKind ||
- S->kind() == UndefinedFunctionKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedFunctionKind ||
+ s->kind() == UndefinedFunctionKind;
}
// Get/set the table index
- void setTableIndex(uint32_t Index);
+ void setTableIndex(uint32_t index);
uint32_t getTableIndex() const;
bool hasTableIndex() const;
// Get/set the function index
uint32_t getFunctionIndex() const;
- void setFunctionIndex(uint32_t Index);
+ void setFunctionIndex(uint32_t index);
bool hasFunctionIndex() const;
- const WasmSignature *Signature;
+ const WasmSignature *signature;
protected:
- FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
- const WasmSignature *Sig)
- : Symbol(Name, K, Flags, F), Signature(Sig) {}
+ FunctionSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
+ const WasmSignature *sig)
+ : Symbol(name, k, flags, f), signature(sig) {}
- uint32_t TableIndex = INVALID_INDEX;
- uint32_t FunctionIndex = INVALID_INDEX;
+ uint32_t tableIndex = INVALID_INDEX;
+ uint32_t functionIndex = INVALID_INDEX;
};
class DefinedFunction : public FunctionSymbol {
public:
- DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F,
- InputFunction *Function);
+ DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
+ InputFunction *function);
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedFunctionKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedFunctionKind;
}
- InputFunction *Function;
+ InputFunction *function;
};
class UndefinedFunction : public FunctionSymbol {
public:
- UndefinedFunction(StringRef Name, StringRef ImportName,
- StringRef ImportModule, uint32_t Flags,
- InputFile *File = nullptr,
- const WasmSignature *Type = nullptr,
- bool IsCalledDirectly = true)
- : FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, Type),
- ImportName(ImportName), ImportModule(ImportModule), IsCalledDirectly(IsCalledDirectly) {}
-
- static bool classof(const Symbol *S) {
- return S->kind() == UndefinedFunctionKind;
+ UndefinedFunction(StringRef name, StringRef importName,
+ StringRef importModule, uint32_t flags,
+ InputFile *file = nullptr,
+ const WasmSignature *type = nullptr,
+ bool isCalledDirectly = true)
+ : FunctionSymbol(name, UndefinedFunctionKind, flags, file, type),
+ importName(importName), importModule(importModule), isCalledDirectly(isCalledDirectly) {}
+
+ static bool classof(const Symbol *s) {
+ return s->kind() == UndefinedFunctionKind;
}
- StringRef ImportName;
- StringRef ImportModule;
- bool IsCalledDirectly;
+ StringRef importName;
+ StringRef importModule;
+ bool isCalledDirectly;
};
// Section symbols for output sections are different from those for input
// rather than an InputSection.
class OutputSectionSymbol : public Symbol {
public:
- OutputSectionSymbol(const OutputSection *S)
+ OutputSectionSymbol(const OutputSection *s)
: Symbol("", OutputSectionKind, llvm::wasm::WASM_SYMBOL_BINDING_LOCAL,
nullptr),
- Section(S) {}
+ section(s) {}
- static bool classof(const Symbol *S) {
- return S->kind() == OutputSectionKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == OutputSectionKind;
}
- const OutputSection *Section;
+ const OutputSection *section;
};
class SectionSymbol : public Symbol {
public:
- SectionSymbol(uint32_t Flags, const InputSection *S, InputFile *F = nullptr)
- : Symbol("", SectionKind, Flags, F), Section(S) {}
+ SectionSymbol(uint32_t flags, const InputSection *s, InputFile *f = nullptr)
+ : Symbol("", SectionKind, flags, f), section(s) {}
- static bool classof(const Symbol *S) { return S->kind() == SectionKind; }
+ static bool classof(const Symbol *s) { return s->kind() == SectionKind; }
const OutputSectionSymbol *getOutputSectionSymbol() const;
- const InputSection *Section;
+ const InputSection *section;
};
class DataSymbol : public Symbol {
public:
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedDataKind || S->kind() == UndefinedDataKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedDataKind || s->kind() == UndefinedDataKind;
}
protected:
- DataSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
- : Symbol(Name, K, Flags, F) {}
+ DataSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f)
+ : Symbol(name, k, flags, f) {}
};
class DefinedData : public DataSymbol {
public:
// Constructor for regular data symbols originating from input files.
- DefinedData(StringRef Name, uint32_t Flags, InputFile *F,
- InputSegment *Segment, uint32_t Offset, uint32_t Size)
- : DataSymbol(Name, DefinedDataKind, Flags, F), Segment(Segment),
- Offset(Offset), Size(Size) {}
+ DefinedData(StringRef name, uint32_t flags, InputFile *f,
+ InputSegment *segment, uint32_t offset, uint32_t size)
+ : DataSymbol(name, DefinedDataKind, flags, f), segment(segment),
+ offset(offset), size(size) {}
// Constructor for linker synthetic data symbols.
- DefinedData(StringRef Name, uint32_t Flags)
- : DataSymbol(Name, DefinedDataKind, Flags, nullptr) {}
+ DefinedData(StringRef name, uint32_t flags)
+ : DataSymbol(name, DefinedDataKind, flags, nullptr) {}
- static bool classof(const Symbol *S) { return S->kind() == DefinedDataKind; }
+ static bool classof(const Symbol *s) { return s->kind() == DefinedDataKind; }
// Returns the output virtual address of a defined data symbol.
uint32_t getVirtualAddress() const;
- void setVirtualAddress(uint32_t VA);
+ void setVirtualAddress(uint32_t va);
// Returns the offset of a defined data symbol within its OutputSegment.
uint32_t getOutputSegmentOffset() const;
uint32_t getOutputSegmentIndex() const;
- uint32_t getSize() const { return Size; }
+ uint32_t getSize() const { return size; }
- InputSegment *Segment = nullptr;
+ InputSegment *segment = nullptr;
protected:
- uint32_t Offset = 0;
- uint32_t Size = 0;
+ uint32_t offset = 0;
+ uint32_t size = 0;
};
class UndefinedData : public DataSymbol {
public:
- UndefinedData(StringRef Name, uint32_t Flags, InputFile *File = nullptr)
- : DataSymbol(Name, UndefinedDataKind, Flags, File) {}
- static bool classof(const Symbol *S) {
- return S->kind() == UndefinedDataKind;
+ UndefinedData(StringRef name, uint32_t flags, InputFile *file = nullptr)
+ : DataSymbol(name, UndefinedDataKind, flags, file) {}
+ static bool classof(const Symbol *s) {
+ return s->kind() == UndefinedDataKind;
}
};
class GlobalSymbol : public Symbol {
public:
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedGlobalKind || s->kind() == UndefinedGlobalKind;
}
- const WasmGlobalType *getGlobalType() const { return GlobalType; }
+ const WasmGlobalType *getGlobalType() const { return globalType; }
// Get/set the global index
uint32_t getGlobalIndex() const;
- void setGlobalIndex(uint32_t Index);
+ void setGlobalIndex(uint32_t index);
bool hasGlobalIndex() const;
protected:
- GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
- const WasmGlobalType *GlobalType)
- : Symbol(Name, K, Flags, F), GlobalType(GlobalType) {}
+ GlobalSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
+ const WasmGlobalType *globalType)
+ : Symbol(name, k, flags, f), globalType(globalType) {}
- const WasmGlobalType *GlobalType;
- uint32_t GlobalIndex = INVALID_INDEX;
+ const WasmGlobalType *globalType;
+ uint32_t globalIndex = INVALID_INDEX;
};
class DefinedGlobal : public GlobalSymbol {
public:
- DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
- InputGlobal *Global);
+ DefinedGlobal(StringRef name, uint32_t flags, InputFile *file,
+ InputGlobal *global);
- static bool classof(const Symbol *S) {
- return S->kind() == DefinedGlobalKind;
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedGlobalKind;
}
- InputGlobal *Global;
+ InputGlobal *global;
};
class UndefinedGlobal : public GlobalSymbol {
public:
- UndefinedGlobal(StringRef Name, StringRef ImportName, StringRef ImportModule,
- uint32_t Flags, InputFile *File = nullptr,
- const WasmGlobalType *Type = nullptr)
- : GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, Type),
- ImportName(ImportName), ImportModule(ImportModule) {}
-
- static bool classof(const Symbol *S) {
- return S->kind() == UndefinedGlobalKind;
+ UndefinedGlobal(StringRef name, StringRef importName, StringRef importModule,
+ uint32_t flags, InputFile *file = nullptr,
+ const WasmGlobalType *type = nullptr)
+ : GlobalSymbol(name, UndefinedGlobalKind, flags, file, type),
+ importName(importName), importModule(importModule) {}
+
+ static bool classof(const Symbol *s) {
+ return s->kind() == UndefinedGlobalKind;
}
- StringRef ImportName;
- StringRef ImportModule;
+ StringRef importName;
+ StringRef importModule;
};
// Wasm events are features that suspend the current execution and transfer the
// are used, and has name '__cpp_exception' for linking.
class EventSymbol : public Symbol {
public:
- static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; }
+ static bool classof(const Symbol *s) { return s->kind() == DefinedEventKind; }
- const WasmEventType *getEventType() const { return EventType; }
+ const WasmEventType *getEventType() const { return eventType; }
// Get/set the event index
uint32_t getEventIndex() const;
- void setEventIndex(uint32_t Index);
+ void setEventIndex(uint32_t index);
bool hasEventIndex() const;
- const WasmSignature *Signature;
+ const WasmSignature *signature;
protected:
- EventSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
- const WasmEventType *EventType, const WasmSignature *Sig)
- : Symbol(Name, K, Flags, F), Signature(Sig), EventType(EventType) {}
+ EventSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
+ const WasmEventType *eventType, const WasmSignature *sig)
+ : Symbol(name, k, flags, f), signature(sig), eventType(eventType) {}
- const WasmEventType *EventType;
- uint32_t EventIndex = INVALID_INDEX;
+ const WasmEventType *eventType;
+ uint32_t eventIndex = INVALID_INDEX;
};
class DefinedEvent : public EventSymbol {
public:
- DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
- InputEvent *Event);
+ DefinedEvent(StringRef name, uint32_t flags, InputFile *file,
+ InputEvent *event);
- static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; }
+ static bool classof(const Symbol *s) { return s->kind() == DefinedEventKind; }
- InputEvent *Event;
+ InputEvent *event;
};
// LazySymbol represents a symbol that is not yet in the link, but we know where
// symbols into consideration.
class LazySymbol : public Symbol {
public:
- LazySymbol(StringRef Name, uint32_t Flags, InputFile *File,
- const llvm::object::Archive::Symbol &Sym)
- : Symbol(Name, LazyKind, Flags, File), ArchiveSymbol(Sym) {}
+ LazySymbol(StringRef name, uint32_t flags, InputFile *file,
+ const llvm::object::Archive::Symbol &sym)
+ : Symbol(name, LazyKind, flags, file), archiveSymbol(sym) {}
- static bool classof(const Symbol *S) { return S->kind() == LazyKind; }
+ static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
void fetch();
// Lazy symbols can have a signature because they can replace an
// signture.
// TODO(sbc): This repetition of the signature field is inelegant. Revisit
// the use of class hierarchy to represent symbol taxonomy.
- const WasmSignature *Signature = nullptr;
+ const WasmSignature *signature = nullptr;
private:
- llvm::object::Archive::Symbol ArchiveSymbol;
+ llvm::object::Archive::Symbol archiveSymbol;
};
// linker-generated symbols
struct WasmSym {
// __global_base
// Symbol marking the start of the global section.
- static DefinedData *GlobalBase;
+ static DefinedData *globalBase;
// __stack_pointer
// Global that holds the address of the top of the explicit value stack in
// linear memory.
- static GlobalSymbol *StackPointer;
+ static GlobalSymbol *stackPointer;
// __data_end
// Symbol marking the end of the data and bss.
- static DefinedData *DataEnd;
+ static DefinedData *dataEnd;
// __heap_base
// Symbol marking the end of the data, bss and explicit stack. Any linear
// memory following this address is not used by the linked code and can
// therefore be used as a backing store for brk()/malloc() implementations.
- static DefinedData *HeapBase;
+ static DefinedData *heapBase;
// __wasm_call_ctors
// Function that directly calls all ctors in priority order.
- static DefinedFunction *CallCtors;
+ static DefinedFunction *callCtors;
// __wasm_init_memory
// Function that initializes passive data segments post-instantiation.
- static DefinedFunction *InitMemory;
+ static DefinedFunction *initMemory;
// __wasm_apply_relocs
// Function that applies relocations to data segment post-instantiation.
- static DefinedFunction *ApplyRelocs;
+ static DefinedFunction *applyRelocs;
// __dso_handle
// Symbol used in calls to __cxa_atexit to determine current DLL
- static DefinedData *DsoHandle;
+ static DefinedData *dsoHandle;
// __table_base
// Used in PIC code for offset of indirect function table
- static UndefinedGlobal *TableBase;
+ static UndefinedGlobal *tableBase;
// __memory_base
// Used in PIC code for offset of global data
- static UndefinedGlobal *MemoryBase;
+ static UndefinedGlobal *memoryBase;
};
// A buffer class that is large enough to hold any Symbol-derived
// object. We allocate memory using this class and instantiate a symbol
// using the placement new.
union SymbolUnion {
- alignas(DefinedFunction) char A[sizeof(DefinedFunction)];
- alignas(DefinedData) char B[sizeof(DefinedData)];
- alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)];
- alignas(DefinedEvent) char D[sizeof(DefinedEvent)];
- alignas(LazySymbol) char E[sizeof(LazySymbol)];
- alignas(UndefinedFunction) char F[sizeof(UndefinedFunction)];
- alignas(UndefinedData) char G[sizeof(UndefinedData)];
- alignas(UndefinedGlobal) char H[sizeof(UndefinedGlobal)];
- alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
+ alignas(DefinedFunction) char a[sizeof(DefinedFunction)];
+ alignas(DefinedData) char b[sizeof(DefinedData)];
+ alignas(DefinedGlobal) char c[sizeof(DefinedGlobal)];
+ alignas(DefinedEvent) char d[sizeof(DefinedEvent)];
+ alignas(LazySymbol) char e[sizeof(LazySymbol)];
+ alignas(UndefinedFunction) char f[sizeof(UndefinedFunction)];
+ alignas(UndefinedData) char g[sizeof(UndefinedData)];
+ alignas(UndefinedGlobal) char h[sizeof(UndefinedGlobal)];
+ alignas(SectionSymbol) char i[sizeof(SectionSymbol)];
};
// It is important to keep the size of SymbolUnion small for performance and
// UndefinedFunction on a 64-bit system.
static_assert(sizeof(SymbolUnion) <= 96, "SymbolUnion too large");
-void printTraceSymbol(Symbol *Sym);
-void printTraceSymbolUndefined(StringRef Name, const InputFile* File);
+void printTraceSymbol(Symbol *sym);
+void printTraceSymbolUndefined(StringRef name, const InputFile* file);
template <typename T, typename... ArgT>
-T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
+T *replaceSymbol(Symbol *s, ArgT &&... arg) {
static_assert(std::is_trivially_destructible<T>(),
"Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a Symbol");
- Symbol SymCopy = *S;
+ Symbol symCopy = *s;
- T *S2 = new (S) T(std::forward<ArgT>(Arg)...);
- S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj;
- S2->ForceExport = SymCopy.ForceExport;
- S2->CanInline = SymCopy.CanInline;
- S2->Traced = SymCopy.Traced;
+ T *s2 = new (s) T(std::forward<ArgT>(arg)...);
+ s2->isUsedInRegularObj = symCopy.isUsedInRegularObj;
+ s2->forceExport = symCopy.forceExport;
+ s2->canInline = symCopy.canInline;
+ s2->traced = symCopy.traced;
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
- if (S2->Traced)
- printTraceSymbol(S2);
+ if (s2->traced)
+ printTraceSymbol(s2);
- return S2;
+ return s2;
}
} // namespace wasm
// Returns a symbol name for an error message.
-std::string toString(const wasm::Symbol &Sym);
-std::string toString(wasm::Symbol::Kind Kind);
-std::string maybeDemangleSymbol(StringRef Name);
+std::string toString(const wasm::Symbol &sym);
+std::string toString(wasm::Symbol::Kind kind);
+std::string maybeDemangleSymbol(StringRef name);
} // namespace lld
using namespace lld;
using namespace lld::wasm;
-OutStruct lld::wasm::Out;
+OutStruct lld::wasm::out;
namespace {
// of the parent section.
class SubSection {
public:
- explicit SubSection(uint32_t Type) : Type(Type) {}
+ explicit SubSection(uint32_t type) : type(type) {}
- void writeTo(raw_ostream &To) {
- OS.flush();
- writeUleb128(To, Type, "subsection type");
- writeUleb128(To, Body.size(), "subsection size");
- To.write(Body.data(), Body.size());
+ void writeTo(raw_ostream &to) {
+ os.flush();
+ writeUleb128(to, type, "subsection type");
+ writeUleb128(to, body.size(), "subsection size");
+ to.write(body.data(), body.size());
}
private:
- uint32_t Type;
- std::string Body;
+ uint32_t type;
+ std::string body;
public:
- raw_string_ostream OS{Body};
+ raw_string_ostream os{body};
};
} // namespace
void DylinkSection::writeBody() {
- raw_ostream &OS = BodyOutputStream;
-
- writeUleb128(OS, MemSize, "MemSize");
- writeUleb128(OS, MemAlign, "MemAlign");
- writeUleb128(OS, Out.ElemSec->numEntries(), "TableSize");
- writeUleb128(OS, 0, "TableAlign");
- writeUleb128(OS, Symtab->SharedFiles.size(), "Needed");
- for (auto *SO : Symtab->SharedFiles)
- writeStr(OS, llvm::sys::path::filename(SO->getName()), "so name");
+ raw_ostream &os = bodyOutputStream;
+
+ writeUleb128(os, memSize, "MemSize");
+ writeUleb128(os, memAlign, "MemAlign");
+ writeUleb128(os, out.elemSec->numEntries(), "TableSize");
+ writeUleb128(os, 0, "TableAlign");
+ writeUleb128(os, symtab->sharedFiles.size(), "Needed");
+ for (auto *so : symtab->sharedFiles)
+ writeStr(os, llvm::sys::path::filename(so->getName()), "so name");
}
-uint32_t TypeSection::registerType(const WasmSignature &Sig) {
- auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
- if (Pair.second) {
- LLVM_DEBUG(llvm::dbgs() << "type " << toString(Sig) << "\n");
- Types.push_back(&Sig);
+uint32_t TypeSection::registerType(const WasmSignature &sig) {
+ auto pair = typeIndices.insert(std::make_pair(sig, types.size()));
+ if (pair.second) {
+ LLVM_DEBUG(llvm::dbgs() << "type " << toString(sig) << "\n");
+ types.push_back(&sig);
}
- return Pair.first->second;
+ return pair.first->second;
}
-uint32_t TypeSection::lookupType(const WasmSignature &Sig) {
- auto It = TypeIndices.find(Sig);
- if (It == TypeIndices.end()) {
- error("type not found: " + toString(Sig));
+uint32_t TypeSection::lookupType(const WasmSignature &sig) {
+ auto it = typeIndices.find(sig);
+ if (it == typeIndices.end()) {
+ error("type not found: " + toString(sig));
return 0;
}
- return It->second;
+ return it->second;
}
void TypeSection::writeBody() {
- writeUleb128(BodyOutputStream, Types.size(), "type count");
- for (const WasmSignature *Sig : Types)
- writeSig(BodyOutputStream, *Sig);
+ writeUleb128(bodyOutputStream, types.size(), "type count");
+ for (const WasmSignature *sig : types)
+ writeSig(bodyOutputStream, *sig);
}
uint32_t ImportSection::getNumImports() const {
- assert(IsSealed);
- uint32_t NumImports = ImportedSymbols.size() + GOTSymbols.size();
- if (Config->ImportMemory)
- ++NumImports;
- if (Config->ImportTable)
- ++NumImports;
- return NumImports;
+ assert(isSealed);
+ uint32_t numImports = importedSymbols.size() + gotSymbols.size();
+ if (config->importMemory)
+ ++numImports;
+ if (config->importTable)
+ ++numImports;
+ return numImports;
}
-void ImportSection::addGOTEntry(Symbol *Sym) {
- assert(!IsSealed);
- if (Sym->hasGOTIndex())
+void ImportSection::addGOTEntry(Symbol *sym) {
+ assert(!isSealed);
+ if (sym->hasGOTIndex())
return;
- Sym->setGOTIndex(NumImportedGlobals++);
- GOTSymbols.push_back(Sym);
+ sym->setGOTIndex(numImportedGlobals++);
+ gotSymbols.push_back(sym);
}
-void ImportSection::addImport(Symbol *Sym) {
- assert(!IsSealed);
- ImportedSymbols.emplace_back(Sym);
- if (auto *F = dyn_cast<FunctionSymbol>(Sym))
- F->setFunctionIndex(NumImportedFunctions++);
- else if (auto *G = dyn_cast<GlobalSymbol>(Sym))
- G->setGlobalIndex(NumImportedGlobals++);
+void ImportSection::addImport(Symbol *sym) {
+ assert(!isSealed);
+ importedSymbols.emplace_back(sym);
+ if (auto *f = dyn_cast<FunctionSymbol>(sym))
+ f->setFunctionIndex(numImportedFunctions++);
+ else if (auto *g = dyn_cast<GlobalSymbol>(sym))
+ g->setGlobalIndex(numImportedGlobals++);
else
- cast<EventSymbol>(Sym)->setEventIndex(NumImportedEvents++);
+ cast<EventSymbol>(sym)->setEventIndex(numImportedEvents++);
}
void ImportSection::writeBody() {
- raw_ostream &OS = BodyOutputStream;
-
- writeUleb128(OS, getNumImports(), "import count");
-
- if (Config->ImportMemory) {
- WasmImport Import;
- Import.Module = DefaultModule;
- Import.Field = "memory";
- Import.Kind = WASM_EXTERNAL_MEMORY;
- Import.Memory.Flags = 0;
- Import.Memory.Initial = Out.MemorySec->NumMemoryPages;
- if (Out.MemorySec->MaxMemoryPages != 0 || Config->SharedMemory) {
- Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
- Import.Memory.Maximum = Out.MemorySec->MaxMemoryPages;
+ raw_ostream &os = bodyOutputStream;
+
+ writeUleb128(os, getNumImports(), "import count");
+
+ if (config->importMemory) {
+ WasmImport import;
+ import.Module = defaultModule;
+ import.Field = "memory";
+ import.Kind = WASM_EXTERNAL_MEMORY;
+ import.Memory.Flags = 0;
+ import.Memory.Initial = out.memorySec->numMemoryPages;
+ if (out.memorySec->maxMemoryPages != 0 || config->sharedMemory) {
+ import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
+ import.Memory.Maximum = out.memorySec->maxMemoryPages;
}
- if (Config->SharedMemory)
- Import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
- writeImport(OS, Import);
+ if (config->sharedMemory)
+ import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
+ writeImport(os, import);
}
- if (Config->ImportTable) {
- uint32_t TableSize = Out.ElemSec->ElemOffset + Out.ElemSec->numEntries();
- WasmImport Import;
- Import.Module = DefaultModule;
- Import.Field = FunctionTableName;
- Import.Kind = WASM_EXTERNAL_TABLE;
- Import.Table.ElemType = WASM_TYPE_FUNCREF;
- Import.Table.Limits = {0, TableSize, 0};
- writeImport(OS, Import);
+ if (config->importTable) {
+ uint32_t tableSize = out.elemSec->elemOffset + out.elemSec->numEntries();
+ WasmImport import;
+ import.Module = defaultModule;
+ import.Field = functionTableName;
+ import.Kind = WASM_EXTERNAL_TABLE;
+ import.Table.ElemType = WASM_TYPE_FUNCREF;
+ import.Table.Limits = {0, tableSize, 0};
+ writeImport(os, import);
}
- for (const Symbol *Sym : ImportedSymbols) {
- WasmImport Import;
- if (auto *F = dyn_cast<UndefinedFunction>(Sym)) {
- Import.Field = F->ImportName;
- Import.Module = F->ImportModule;
- } else if (auto *G = dyn_cast<UndefinedGlobal>(Sym)) {
- Import.Field = G->ImportName;
- Import.Module = G->ImportModule;
+ for (const Symbol *sym : importedSymbols) {
+ WasmImport import;
+ if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
+ import.Field = f->importName;
+ import.Module = f->importModule;
+ } else if (auto *g = dyn_cast<UndefinedGlobal>(sym)) {
+ import.Field = g->importName;
+ import.Module = g->importModule;
} else {
- Import.Field = Sym->getName();
- Import.Module = DefaultModule;
+ import.Field = sym->getName();
+ import.Module = defaultModule;
}
- if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
- Import.Kind = WASM_EXTERNAL_FUNCTION;
- Import.SigIndex = Out.TypeSec->lookupType(*FunctionSym->Signature);
- } else if (auto *GlobalSym = dyn_cast<GlobalSymbol>(Sym)) {
- Import.Kind = WASM_EXTERNAL_GLOBAL;
- Import.Global = *GlobalSym->getGlobalType();
+ if (auto *functionSym = dyn_cast<FunctionSymbol>(sym)) {
+ import.Kind = WASM_EXTERNAL_FUNCTION;
+ import.SigIndex = out.typeSec->lookupType(*functionSym->signature);
+ } else if (auto *globalSym = dyn_cast<GlobalSymbol>(sym)) {
+ import.Kind = WASM_EXTERNAL_GLOBAL;
+ import.Global = *globalSym->getGlobalType();
} else {
- auto *EventSym = cast<EventSymbol>(Sym);
- Import.Kind = WASM_EXTERNAL_EVENT;
- Import.Event.Attribute = EventSym->getEventType()->Attribute;
- Import.Event.SigIndex = Out.TypeSec->lookupType(*EventSym->Signature);
+ auto *eventSym = cast<EventSymbol>(sym);
+ import.Kind = WASM_EXTERNAL_EVENT;
+ import.Event.Attribute = eventSym->getEventType()->Attribute;
+ import.Event.SigIndex = out.typeSec->lookupType(*eventSym->signature);
}
- writeImport(OS, Import);
+ writeImport(os, import);
}
- for (const Symbol *Sym : GOTSymbols) {
- WasmImport Import;
- Import.Kind = WASM_EXTERNAL_GLOBAL;
- Import.Global = {WASM_TYPE_I32, true};
- if (isa<DataSymbol>(Sym))
- Import.Module = "GOT.mem";
+ for (const Symbol *sym : gotSymbols) {
+ WasmImport import;
+ import.Kind = WASM_EXTERNAL_GLOBAL;
+ import.Global = {WASM_TYPE_I32, true};
+ if (isa<DataSymbol>(sym))
+ import.Module = "GOT.mem";
else
- Import.Module = "GOT.func";
- Import.Field = Sym->getName();
- writeImport(OS, Import);
+ import.Module = "GOT.func";
+ import.Field = sym->getName();
+ writeImport(os, import);
}
}
void FunctionSection::writeBody() {
- raw_ostream &OS = BodyOutputStream;
+ raw_ostream &os = bodyOutputStream;
- writeUleb128(OS, InputFunctions.size(), "function count");
- for (const InputFunction *Func : InputFunctions)
- writeUleb128(OS, Out.TypeSec->lookupType(Func->Signature), "sig index");
+ writeUleb128(os, inputFunctions.size(), "function count");
+ for (const InputFunction *func : inputFunctions)
+ writeUleb128(os, out.typeSec->lookupType(func->signature), "sig index");
}
-void FunctionSection::addFunction(InputFunction *Func) {
- if (!Func->Live)
+void FunctionSection::addFunction(InputFunction *func) {
+ if (!func->live)
return;
- uint32_t FunctionIndex =
- Out.ImportSec->getNumImportedFunctions() + InputFunctions.size();
- InputFunctions.emplace_back(Func);
- Func->setFunctionIndex(FunctionIndex);
+ uint32_t functionIndex =
+ out.importSec->getNumImportedFunctions() + inputFunctions.size();
+ inputFunctions.emplace_back(func);
+ func->setFunctionIndex(functionIndex);
}
void TableSection::writeBody() {
- uint32_t TableSize = Out.ElemSec->ElemOffset + Out.ElemSec->numEntries();
+ uint32_t tableSize = out.elemSec->elemOffset + out.elemSec->numEntries();
- raw_ostream &OS = BodyOutputStream;
- writeUleb128(OS, 1, "table count");
- WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
- writeTableType(OS, WasmTable{WASM_TYPE_FUNCREF, Limits});
+ raw_ostream &os = bodyOutputStream;
+ writeUleb128(os, 1, "table count");
+ WasmLimits limits = {WASM_LIMITS_FLAG_HAS_MAX, tableSize, tableSize};
+ writeTableType(os, WasmTable{WASM_TYPE_FUNCREF, limits});
}
void MemorySection::writeBody() {
- raw_ostream &OS = BodyOutputStream;
-
- bool HasMax = MaxMemoryPages != 0 || Config->SharedMemory;
- writeUleb128(OS, 1, "memory count");
- unsigned Flags = 0;
- if (HasMax)
- Flags |= WASM_LIMITS_FLAG_HAS_MAX;
- if (Config->SharedMemory)
- Flags |= WASM_LIMITS_FLAG_IS_SHARED;
- writeUleb128(OS, Flags, "memory limits flags");
- writeUleb128(OS, NumMemoryPages, "initial pages");
- if (HasMax)
- writeUleb128(OS, MaxMemoryPages, "max pages");
+ raw_ostream &os = bodyOutputStream;
+
+ bool hasMax = maxMemoryPages != 0 || config->sharedMemory;
+ writeUleb128(os, 1, "memory count");
+ unsigned flags = 0;
+ if (hasMax)
+ flags |= WASM_LIMITS_FLAG_HAS_MAX;
+ if (config->sharedMemory)
+ flags |= WASM_LIMITS_FLAG_IS_SHARED;
+ writeUleb128(os, flags, "memory limits flags");
+ writeUleb128(os, numMemoryPages, "initial pages");
+ if (hasMax)
+ writeUleb128(os, maxMemoryPages, "max pages");
}
void GlobalSection::writeBody() {
- raw_ostream &OS = BodyOutputStream;
-
- writeUleb128(OS, numGlobals(), "global count");
- for (const InputGlobal *G : InputGlobals)
- writeGlobal(OS, G->Global);
- for (const DefinedData *Sym : DefinedFakeGlobals) {
- WasmGlobal Global;
- Global.Type = {WASM_TYPE_I32, false};
- Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- Global.InitExpr.Value.Int32 = Sym->getVirtualAddress();
- writeGlobal(OS, Global);
+ raw_ostream &os = bodyOutputStream;
+
+ writeUleb128(os, numGlobals(), "global count");
+ for (const InputGlobal *g : inputGlobals)
+ writeGlobal(os, g->global);
+ for (const DefinedData *sym : definedFakeGlobals) {
+ WasmGlobal global;
+ global.Type = {WASM_TYPE_I32, false};
+ global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+ global.InitExpr.Value.Int32 = sym->getVirtualAddress();
+ writeGlobal(os, global);
}
}
-void GlobalSection::addGlobal(InputGlobal *Global) {
- if (!Global->Live)
+void GlobalSection::addGlobal(InputGlobal *global) {
+ if (!global->live)
return;
- uint32_t GlobalIndex =
- Out.ImportSec->getNumImportedGlobals() + InputGlobals.size();
- LLVM_DEBUG(dbgs() << "addGlobal: " << GlobalIndex << "\n");
- Global->setGlobalIndex(GlobalIndex);
- Out.GlobalSec->InputGlobals.push_back(Global);
+ uint32_t globalIndex =
+ out.importSec->getNumImportedGlobals() + inputGlobals.size();
+ LLVM_DEBUG(dbgs() << "addGlobal: " << globalIndex << "\n");
+ global->setGlobalIndex(globalIndex);
+ out.globalSec->inputGlobals.push_back(global);
}
void EventSection::writeBody() {
- raw_ostream &OS = BodyOutputStream;
+ raw_ostream &os = bodyOutputStream;
- writeUleb128(OS, InputEvents.size(), "event count");
- for (InputEvent *E : InputEvents) {
- E->Event.Type.SigIndex = Out.TypeSec->lookupType(E->Signature);
- writeEvent(OS, E->Event);
+ writeUleb128(os, inputEvents.size(), "event count");
+ for (InputEvent *e : inputEvents) {
+ e->event.Type.SigIndex = out.typeSec->lookupType(e->signature);
+ writeEvent(os, e->event);
}
}
-void EventSection::addEvent(InputEvent *Event) {
- if (!Event->Live)
+void EventSection::addEvent(InputEvent *event) {
+ if (!event->live)
return;
- uint32_t EventIndex =
- Out.ImportSec->getNumImportedEvents() + InputEvents.size();
- LLVM_DEBUG(dbgs() << "addEvent: " << EventIndex << "\n");
- Event->setEventIndex(EventIndex);
- InputEvents.push_back(Event);
+ uint32_t eventIndex =
+ out.importSec->getNumImportedEvents() + inputEvents.size();
+ LLVM_DEBUG(dbgs() << "addEvent: " << eventIndex << "\n");
+ event->setEventIndex(eventIndex);
+ inputEvents.push_back(event);
}
void ExportSection::writeBody() {
- raw_ostream &OS = BodyOutputStream;
+ raw_ostream &os = bodyOutputStream;
- writeUleb128(OS, Exports.size(), "export count");
- for (const WasmExport &Export : Exports)
- writeExport(OS, Export);
+ writeUleb128(os, exports.size(), "export count");
+ for (const WasmExport &export_ : exports)
+ writeExport(os, export_);
}
-void ElemSection::addEntry(FunctionSymbol *Sym) {
- if (Sym->hasTableIndex())
+void ElemSection::addEntry(FunctionSymbol *sym) {
+ if (sym->hasTableIndex())
return;
- Sym->setTableIndex(ElemOffset + IndirectFunctions.size());
- IndirectFunctions.emplace_back(Sym);
+ sym->setTableIndex(elemOffset + indirectFunctions.size());
+ indirectFunctions.emplace_back(sym);
}
void ElemSection::writeBody() {
- raw_ostream &OS = BodyOutputStream;
-
- writeUleb128(OS, 1, "segment count");
- writeUleb128(OS, 0, "table index");
- WasmInitExpr InitExpr;
- if (Config->Pic) {
- InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
- InitExpr.Value.Global = WasmSym::TableBase->getGlobalIndex();
+ raw_ostream &os = bodyOutputStream;
+
+ writeUleb128(os, 1, "segment count");
+ writeUleb128(os, 0, "table index");
+ WasmInitExpr initExpr;
+ if (config->isPic) {
+ initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
+ initExpr.Value.Global = WasmSym::tableBase->getGlobalIndex();
} else {
- InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- InitExpr.Value.Int32 = ElemOffset;
+ initExpr.Opcode = WASM_OPCODE_I32_CONST;
+ initExpr.Value.Int32 = elemOffset;
}
- writeInitExpr(OS, InitExpr);
- writeUleb128(OS, IndirectFunctions.size(), "elem count");
-
- uint32_t TableIndex = ElemOffset;
- for (const FunctionSymbol *Sym : IndirectFunctions) {
- assert(Sym->getTableIndex() == TableIndex);
- writeUleb128(OS, Sym->getFunctionIndex(), "function index");
- ++TableIndex;
+ writeInitExpr(os, initExpr);
+ writeUleb128(os, indirectFunctions.size(), "elem count");
+
+ uint32_t tableIndex = elemOffset;
+ for (const FunctionSymbol *sym : indirectFunctions) {
+ assert(sym->getTableIndex() == tableIndex);
+ writeUleb128(os, sym->getFunctionIndex(), "function index");
+ ++tableIndex;
}
}
void DataCountSection::writeBody() {
- writeUleb128(BodyOutputStream, NumSegments, "data count");
+ writeUleb128(bodyOutputStream, numSegments, "data count");
}
bool DataCountSection::isNeeded() const {
- return NumSegments && Config->PassiveSegments;
+ return numSegments && config->passiveSegments;
}
-static uint32_t getWasmFlags(const Symbol *Sym) {
- uint32_t Flags = 0;
- if (Sym->isLocal())
- Flags |= WASM_SYMBOL_BINDING_LOCAL;
- if (Sym->isWeak())
- Flags |= WASM_SYMBOL_BINDING_WEAK;
- if (Sym->isHidden())
- Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
- if (Sym->isUndefined())
- Flags |= WASM_SYMBOL_UNDEFINED;
- if (auto *F = dyn_cast<UndefinedFunction>(Sym)) {
- if (F->getName() != F->ImportName)
- Flags |= WASM_SYMBOL_EXPLICIT_NAME;
- } else if (auto *G = dyn_cast<UndefinedGlobal>(Sym)) {
- if (G->getName() != G->ImportName)
- Flags |= WASM_SYMBOL_EXPLICIT_NAME;
+static uint32_t getWasmFlags(const Symbol *sym) {
+ uint32_t flags = 0;
+ if (sym->isLocal())
+ flags |= WASM_SYMBOL_BINDING_LOCAL;
+ if (sym->isWeak())
+ flags |= WASM_SYMBOL_BINDING_WEAK;
+ if (sym->isHidden())
+ flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
+ if (sym->isUndefined())
+ flags |= WASM_SYMBOL_UNDEFINED;
+ if (auto *f = dyn_cast<UndefinedFunction>(sym)) {
+ if (f->getName() != f->importName)
+ flags |= WASM_SYMBOL_EXPLICIT_NAME;
+ } else if (auto *g = dyn_cast<UndefinedGlobal>(sym)) {
+ if (g->getName() != g->importName)
+ flags |= WASM_SYMBOL_EXPLICIT_NAME;
}
- return Flags;
+ return flags;
}
void LinkingSection::writeBody() {
- raw_ostream &OS = BodyOutputStream;
-
- writeUleb128(OS, WasmMetadataVersion, "Version");
-
- if (!SymtabEntries.empty()) {
- SubSection Sub(WASM_SYMBOL_TABLE);
- writeUleb128(Sub.OS, SymtabEntries.size(), "num symbols");
-
- for (const Symbol *Sym : SymtabEntries) {
- assert(Sym->isDefined() || Sym->isUndefined());
- WasmSymbolType Kind = Sym->getWasmType();
- uint32_t Flags = getWasmFlags(Sym);
-
- writeU8(Sub.OS, Kind, "sym kind");
- writeUleb128(Sub.OS, Flags, "sym flags");
-
- if (auto *F = dyn_cast<FunctionSymbol>(Sym)) {
- writeUleb128(Sub.OS, F->getFunctionIndex(), "index");
- if (Sym->isDefined() || (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
- writeStr(Sub.OS, Sym->getName(), "sym name");
- } else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) {
- writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
- if (Sym->isDefined() || (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
- writeStr(Sub.OS, Sym->getName(), "sym name");
- } else if (auto *E = dyn_cast<EventSymbol>(Sym)) {
- writeUleb128(Sub.OS, E->getEventIndex(), "index");
- if (Sym->isDefined() || (Flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
- writeStr(Sub.OS, Sym->getName(), "sym name");
- } else if (isa<DataSymbol>(Sym)) {
- writeStr(Sub.OS, Sym->getName(), "sym name");
- if (auto *DataSym = dyn_cast<DefinedData>(Sym)) {
- writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index");
- writeUleb128(Sub.OS, DataSym->getOutputSegmentOffset(),
+ raw_ostream &os = bodyOutputStream;
+
+ writeUleb128(os, WasmMetadataVersion, "Version");
+
+ if (!symtabEntries.empty()) {
+ SubSection sub(WASM_SYMBOL_TABLE);
+ writeUleb128(sub.os, symtabEntries.size(), "num symbols");
+
+ for (const Symbol *sym : symtabEntries) {
+ assert(sym->isDefined() || sym->isUndefined());
+ WasmSymbolType kind = sym->getWasmType();
+ uint32_t flags = getWasmFlags(sym);
+
+ writeU8(sub.os, kind, "sym kind");
+ writeUleb128(sub.os, flags, "sym flags");
+
+ if (auto *f = dyn_cast<FunctionSymbol>(sym)) {
+ writeUleb128(sub.os, f->getFunctionIndex(), "index");
+ if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
+ writeStr(sub.os, sym->getName(), "sym name");
+ } else if (auto *g = dyn_cast<GlobalSymbol>(sym)) {
+ writeUleb128(sub.os, g->getGlobalIndex(), "index");
+ if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
+ writeStr(sub.os, sym->getName(), "sym name");
+ } else if (auto *e = dyn_cast<EventSymbol>(sym)) {
+ writeUleb128(sub.os, e->getEventIndex(), "index");
+ if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
+ writeStr(sub.os, sym->getName(), "sym name");
+ } else if (isa<DataSymbol>(sym)) {
+ writeStr(sub.os, sym->getName(), "sym name");
+ if (auto *dataSym = dyn_cast<DefinedData>(sym)) {
+ writeUleb128(sub.os, dataSym->getOutputSegmentIndex(), "index");
+ writeUleb128(sub.os, dataSym->getOutputSegmentOffset(),
"data offset");
- writeUleb128(Sub.OS, DataSym->getSize(), "data size");
+ writeUleb128(sub.os, dataSym->getSize(), "data size");
}
} else {
- auto *S = cast<OutputSectionSymbol>(Sym);
- writeUleb128(Sub.OS, S->Section->SectionIndex, "sym section index");
+ auto *s = cast<OutputSectionSymbol>(sym);
+ writeUleb128(sub.os, s->section->sectionIndex, "sym section index");
}
}
- Sub.writeTo(OS);
+ sub.writeTo(os);
}
- if (DataSegments.size()) {
- SubSection Sub(WASM_SEGMENT_INFO);
- writeUleb128(Sub.OS, DataSegments.size(), "num data segments");
- for (const OutputSegment *S : DataSegments) {
- writeStr(Sub.OS, S->Name, "segment name");
- writeUleb128(Sub.OS, S->Alignment, "alignment");
- writeUleb128(Sub.OS, 0, "flags");
+ if (dataSegments.size()) {
+ SubSection sub(WASM_SEGMENT_INFO);
+ writeUleb128(sub.os, dataSegments.size(), "num data segments");
+ for (const OutputSegment *s : dataSegments) {
+ writeStr(sub.os, s->name, "segment name");
+ writeUleb128(sub.os, s->alignment, "alignment");
+ writeUleb128(sub.os, 0, "flags");
}
- Sub.writeTo(OS);
+ sub.writeTo(os);
}
- if (!InitFunctions.empty()) {
- SubSection Sub(WASM_INIT_FUNCS);
- writeUleb128(Sub.OS, InitFunctions.size(), "num init functions");
- for (const WasmInitEntry &F : InitFunctions) {
- writeUleb128(Sub.OS, F.Priority, "priority");
- writeUleb128(Sub.OS, F.Sym->getOutputSymbolIndex(), "function index");
+ if (!initFunctions.empty()) {
+ SubSection sub(WASM_INIT_FUNCS);
+ writeUleb128(sub.os, initFunctions.size(), "num init functions");
+ for (const WasmInitEntry &f : initFunctions) {
+ writeUleb128(sub.os, f.priority, "priority");
+ writeUleb128(sub.os, f.sym->getOutputSymbolIndex(), "function index");
}
- Sub.writeTo(OS);
+ sub.writeTo(os);
}
struct ComdatEntry {
- unsigned Kind;
- uint32_t Index;
+ unsigned kind;
+ uint32_t index;
};
- std::map<StringRef, std::vector<ComdatEntry>> Comdats;
+ std::map<StringRef, std::vector<ComdatEntry>> comdats;
- for (const InputFunction *F : Out.FunctionSec->InputFunctions) {
- StringRef Comdat = F->getComdatName();
- if (!Comdat.empty())
- Comdats[Comdat].emplace_back(
- ComdatEntry{WASM_COMDAT_FUNCTION, F->getFunctionIndex()});
+ for (const InputFunction *f : out.functionSec->inputFunctions) {
+ StringRef comdat = f->getComdatName();
+ if (!comdat.empty())
+ comdats[comdat].emplace_back(
+ ComdatEntry{WASM_COMDAT_FUNCTION, f->getFunctionIndex()});
}
- for (uint32_t I = 0; I < DataSegments.size(); ++I) {
- const auto &InputSegments = DataSegments[I]->InputSegments;
- if (InputSegments.empty())
+ for (uint32_t i = 0; i < dataSegments.size(); ++i) {
+ const auto &inputSegments = dataSegments[i]->inputSegments;
+ if (inputSegments.empty())
continue;
- StringRef Comdat = InputSegments[0]->getComdatName();
+ StringRef comdat = inputSegments[0]->getComdatName();
#ifndef NDEBUG
- for (const InputSegment *IS : InputSegments)
- assert(IS->getComdatName() == Comdat);
+ for (const InputSegment *isec : inputSegments)
+ assert(isec->getComdatName() == comdat);
#endif
- if (!Comdat.empty())
- Comdats[Comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, I});
+ if (!comdat.empty())
+ comdats[comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, i});
}
- if (!Comdats.empty()) {
- SubSection Sub(WASM_COMDAT_INFO);
- writeUleb128(Sub.OS, Comdats.size(), "num comdats");
- for (const auto &C : Comdats) {
- writeStr(Sub.OS, C.first, "comdat name");
- writeUleb128(Sub.OS, 0, "comdat flags"); // flags for future use
- writeUleb128(Sub.OS, C.second.size(), "num entries");
- for (const ComdatEntry &Entry : C.second) {
- writeU8(Sub.OS, Entry.Kind, "entry kind");
- writeUleb128(Sub.OS, Entry.Index, "entry index");
+ if (!comdats.empty()) {
+ SubSection sub(WASM_COMDAT_INFO);
+ writeUleb128(sub.os, comdats.size(), "num comdats");
+ for (const auto &c : comdats) {
+ writeStr(sub.os, c.first, "comdat name");
+ writeUleb128(sub.os, 0, "comdat flags"); // flags for future use
+ writeUleb128(sub.os, c.second.size(), "num entries");
+ for (const ComdatEntry &entry : c.second) {
+ writeU8(sub.os, entry.kind, "entry kind");
+ writeUleb128(sub.os, entry.index, "entry index");
}
}
- Sub.writeTo(OS);
+ sub.writeTo(os);
}
}
-void LinkingSection::addToSymtab(Symbol *Sym) {
- Sym->setOutputSymbolIndex(SymtabEntries.size());
- SymtabEntries.emplace_back(Sym);
+void LinkingSection::addToSymtab(Symbol *sym) {
+ sym->setOutputSymbolIndex(symtabEntries.size());
+ symtabEntries.emplace_back(sym);
}
unsigned NameSection::numNames() const {
- unsigned NumNames = Out.ImportSec->getNumImportedFunctions();
- for (const InputFunction *F : Out.FunctionSec->InputFunctions)
- if (!F->getName().empty() || !F->getDebugName().empty())
- ++NumNames;
+ unsigned numNames = out.importSec->getNumImportedFunctions();
+ for (const InputFunction *f : out.functionSec->inputFunctions)
+ if (!f->getName().empty() || !f->getDebugName().empty())
+ ++numNames;
- return NumNames;
+ return numNames;
}
// Create the custom "name" section containing debug symbol names.
void NameSection::writeBody() {
- SubSection Sub(WASM_NAMES_FUNCTION);
- writeUleb128(Sub.OS, numNames(), "name count");
+ SubSection sub(WASM_NAMES_FUNCTION);
+ writeUleb128(sub.os, numNames(), "name count");
// Names must appear in function index order. As it happens ImportedSymbols
// and InputFunctions are numbered in order with imported functions coming
// first.
- for (const Symbol *S : Out.ImportSec->ImportedSymbols) {
- if (auto *F = dyn_cast<FunctionSymbol>(S)) {
- writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
- writeStr(Sub.OS, toString(*S), "symbol name");
+ for (const Symbol *s : out.importSec->importedSymbols) {
+ if (auto *f = dyn_cast<FunctionSymbol>(s)) {
+ writeUleb128(sub.os, f->getFunctionIndex(), "func index");
+ writeStr(sub.os, toString(*s), "symbol name");
}
}
- for (const InputFunction *F : Out.FunctionSec->InputFunctions) {
- if (!F->getName().empty()) {
- writeUleb128(Sub.OS, F->getFunctionIndex(), "func index");
- if (!F->getDebugName().empty()) {
- writeStr(Sub.OS, F->getDebugName(), "symbol name");
+ for (const InputFunction *f : out.functionSec->inputFunctions) {
+ if (!f->getName().empty()) {
+ writeUleb128(sub.os, f->getFunctionIndex(), "func index");
+ if (!f->getDebugName().empty()) {
+ writeStr(sub.os, f->getDebugName(), "symbol name");
} else {
- writeStr(Sub.OS, maybeDemangleSymbol(F->getName()), "symbol name");
+ writeStr(sub.os, maybeDemangleSymbol(f->getName()), "symbol name");
}
}
}
- Sub.writeTo(BodyOutputStream);
+ sub.writeTo(bodyOutputStream);
}
-void ProducersSection::addInfo(const WasmProducerInfo &Info) {
- for (auto &Producers :
- {std::make_pair(&Info.Languages, &Languages),
- std::make_pair(&Info.Tools, &Tools), std::make_pair(&Info.SDKs, &SDKs)})
- for (auto &Producer : *Producers.first)
- if (Producers.second->end() ==
- llvm::find_if(*Producers.second,
- [&](std::pair<std::string, std::string> Seen) {
- return Seen.first == Producer.first;
+void ProducersSection::addInfo(const WasmProducerInfo &info) {
+ for (auto &producers :
+ {std::make_pair(&info.Languages, &languages),
+ std::make_pair(&info.Tools, &tools), std::make_pair(&info.SDKs, &sDKs)})
+ for (auto &producer : *producers.first)
+ if (producers.second->end() ==
+ llvm::find_if(*producers.second,
+ [&](std::pair<std::string, std::string> seen) {
+ return seen.first == producer.first;
}))
- Producers.second->push_back(Producer);
+ producers.second->push_back(producer);
}
void ProducersSection::writeBody() {
- auto &OS = BodyOutputStream;
- writeUleb128(OS, fieldCount(), "field count");
- for (auto &Field :
- {std::make_pair("language", Languages),
- std::make_pair("processed-by", Tools), std::make_pair("sdk", SDKs)}) {
- if (Field.second.empty())
+ auto &os = bodyOutputStream;
+ writeUleb128(os, fieldCount(), "field count");
+ for (auto &field :
+ {std::make_pair("language", languages),
+ std::make_pair("processed-by", tools), std::make_pair("sdk", sDKs)}) {
+ if (field.second.empty())
continue;
- writeStr(OS, Field.first, "field name");
- writeUleb128(OS, Field.second.size(), "number of entries");
- for (auto &Entry : Field.second) {
- writeStr(OS, Entry.first, "producer name");
- writeStr(OS, Entry.second, "producer version");
+ writeStr(os, field.first, "field name");
+ writeUleb128(os, field.second.size(), "number of entries");
+ for (auto &entry : field.second) {
+ writeStr(os, entry.first, "producer name");
+ writeStr(os, entry.second, "producer version");
}
}
}
void TargetFeaturesSection::writeBody() {
- SmallVector<std::string, 8> Emitted(Features.begin(), Features.end());
- llvm::sort(Emitted);
- auto &OS = BodyOutputStream;
- writeUleb128(OS, Emitted.size(), "feature count");
- for (auto &Feature : Emitted) {
- writeU8(OS, WASM_FEATURE_PREFIX_USED, "feature used prefix");
- writeStr(OS, Feature, "feature name");
+ SmallVector<std::string, 8> emitted(features.begin(), features.end());
+ llvm::sort(emitted);
+ auto &os = bodyOutputStream;
+ writeUleb128(os, emitted.size(), "feature count");
+ for (auto &feature : emitted) {
+ writeU8(os, WASM_FEATURE_PREFIX_USED, "feature used prefix");
+ writeStr(os, feature, "feature name");
}
}
void RelocSection::writeBody() {
- uint32_t Count = Sec->getNumRelocations();
- assert(Sec->SectionIndex != UINT32_MAX);
- writeUleb128(BodyOutputStream, Sec->SectionIndex, "reloc section");
- writeUleb128(BodyOutputStream, Count, "reloc count");
- Sec->writeRelocations(BodyOutputStream);
+ uint32_t count = sec->getNumRelocations();
+ assert(sec->sectionIndex != UINT32_MAX);
+ writeUleb128(bodyOutputStream, sec->sectionIndex, "reloc section");
+ writeUleb128(bodyOutputStream, count, "reloc count");
+ sec->writeRelocations(bodyOutputStream);
}
// An init entry to be written to either the synthetic init func or the
// linking metadata.
struct WasmInitEntry {
- const FunctionSymbol *Sym;
- uint32_t Priority;
+ const FunctionSymbol *sym;
+ uint32_t priority;
};
class SyntheticSection : public OutputSection {
public:
- SyntheticSection(uint32_t Type, std::string Name = "")
- : OutputSection(Type, Name), BodyOutputStream(Body) {
- if (!Name.empty())
- writeStr(BodyOutputStream, Name, "section name");
+ SyntheticSection(uint32_t type, std::string name = "")
+ : OutputSection(type, name), bodyOutputStream(body) {
+ if (!name.empty())
+ writeStr(bodyOutputStream, name, "section name");
}
- void writeTo(uint8_t *Buf) override {
- assert(Offset);
+ void writeTo(uint8_t *buf) override {
+ assert(offset);
log("writing " + toString(*this));
- memcpy(Buf + Offset, Header.data(), Header.size());
- memcpy(Buf + Offset + Header.size(), Body.data(), Body.size());
+ memcpy(buf + offset, header.data(), header.size());
+ memcpy(buf + offset + header.size(), body.data(), body.size());
}
- size_t getSize() const override { return Header.size() + Body.size(); }
+ size_t getSize() const override { return header.size() + body.size(); }
virtual void writeBody() {}
void finalizeContents() override {
writeBody();
- BodyOutputStream.flush();
- createHeader(Body.size());
+ bodyOutputStream.flush();
+ createHeader(body.size());
}
- raw_ostream &getStream() { return BodyOutputStream; }
+ raw_ostream &getStream() { return bodyOutputStream; }
- std::string Body;
+ std::string body;
protected:
- llvm::raw_string_ostream BodyOutputStream;
+ llvm::raw_string_ostream bodyOutputStream;
};
// Create the custom "dylink" section containing information for the dynamic
class DylinkSection : public SyntheticSection {
public:
DylinkSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "dylink") {}
- bool isNeeded() const override { return Config->Pic; }
+ bool isNeeded() const override { return config->isPic; }
void writeBody() override;
- uint32_t MemAlign = 0;
- uint32_t MemSize = 0;
+ uint32_t memAlign = 0;
+ uint32_t memSize = 0;
};
class TypeSection : public SyntheticSection {
public:
TypeSection() : SyntheticSection(llvm::wasm::WASM_SEC_TYPE) {}
- bool isNeeded() const override { return Types.size() > 0; };
+ bool isNeeded() const override { return types.size() > 0; };
void writeBody() override;
- uint32_t registerType(const WasmSignature &Sig);
- uint32_t lookupType(const WasmSignature &Sig);
+ uint32_t registerType(const WasmSignature &sig);
+ uint32_t lookupType(const WasmSignature &sig);
protected:
- std::vector<const WasmSignature *> Types;
- llvm::DenseMap<WasmSignature, int32_t> TypeIndices;
+ std::vector<const WasmSignature *> types;
+ llvm::DenseMap<WasmSignature, int32_t> typeIndices;
};
class ImportSection : public SyntheticSection {
ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {}
bool isNeeded() const override { return getNumImports() > 0; }
void writeBody() override;
- void addImport(Symbol *Sym);
- void addGOTEntry(Symbol *Sym);
- void seal() { IsSealed = true; }
+ void addImport(Symbol *sym);
+ void addGOTEntry(Symbol *sym);
+ void seal() { isSealed = true; }
uint32_t getNumImports() const;
uint32_t getNumImportedGlobals() const {
- assert(IsSealed);
- return NumImportedGlobals;
+ assert(isSealed);
+ return numImportedGlobals;
}
uint32_t getNumImportedFunctions() const {
- assert(IsSealed);
- return NumImportedFunctions;
+ assert(isSealed);
+ return numImportedFunctions;
}
uint32_t getNumImportedEvents() const {
- assert(IsSealed);
- return NumImportedEvents;
+ assert(isSealed);
+ return numImportedEvents;
}
- std::vector<const Symbol *> ImportedSymbols;
+ std::vector<const Symbol *> importedSymbols;
protected:
- bool IsSealed = false;
- unsigned NumImportedGlobals = 0;
- unsigned NumImportedFunctions = 0;
- unsigned NumImportedEvents = 0;
- std::vector<const Symbol *> GOTSymbols;
+ bool isSealed = false;
+ unsigned numImportedGlobals = 0;
+ unsigned numImportedFunctions = 0;
+ unsigned numImportedEvents = 0;
+ std::vector<const Symbol *> gotSymbols;
};
class FunctionSection : public SyntheticSection {
public:
FunctionSection() : SyntheticSection(llvm::wasm::WASM_SEC_FUNCTION) {}
- bool isNeeded() const override { return InputFunctions.size() > 0; };
+ bool isNeeded() const override { return inputFunctions.size() > 0; };
void writeBody() override;
- void addFunction(InputFunction *Func);
+ void addFunction(InputFunction *func);
- std::vector<InputFunction *> InputFunctions;
+ std::vector<InputFunction *> inputFunctions;
protected:
};
public:
MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {}
- bool isNeeded() const override { return !Config->ImportMemory; }
+ bool isNeeded() const override { return !config->importMemory; }
void writeBody() override;
- uint32_t NumMemoryPages = 0;
- uint32_t MaxMemoryPages = 0;
+ uint32_t numMemoryPages = 0;
+ uint32_t maxMemoryPages = 0;
};
class TableSection : public SyntheticSection {
// no address-taken function will fail at validation time since it is
// a validation error to include a call_indirect instruction if there
// is not table.
- return !Config->ImportTable;
+ return !config->importTable;
}
void writeBody() override;
public:
GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {}
uint32_t numGlobals() const {
- return InputGlobals.size() + DefinedFakeGlobals.size();
+ return inputGlobals.size() + definedFakeGlobals.size();
}
bool isNeeded() const override { return numGlobals() > 0; }
void writeBody() override;
- void addGlobal(InputGlobal *Global);
+ void addGlobal(InputGlobal *global);
- std::vector<const DefinedData *> DefinedFakeGlobals;
- std::vector<InputGlobal *> InputGlobals;
+ std::vector<const DefinedData *> definedFakeGlobals;
+ std::vector<InputGlobal *> inputGlobals;
};
// The event section contains a list of declared wasm events associated with the
public:
EventSection() : SyntheticSection(llvm::wasm::WASM_SEC_EVENT) {}
void writeBody() override;
- bool isNeeded() const override { return InputEvents.size() > 0; }
- void addEvent(InputEvent *Event);
+ bool isNeeded() const override { return inputEvents.size() > 0; }
+ void addEvent(InputEvent *event);
- std::vector<InputEvent *> InputEvents;
+ std::vector<InputEvent *> inputEvents;
};
class ExportSection : public SyntheticSection {
public:
ExportSection() : SyntheticSection(llvm::wasm::WASM_SEC_EXPORT) {}
- bool isNeeded() const override { return Exports.size() > 0; }
+ bool isNeeded() const override { return exports.size() > 0; }
void writeBody() override;
- std::vector<llvm::wasm::WasmExport> Exports;
+ std::vector<llvm::wasm::WasmExport> exports;
};
class ElemSection : public SyntheticSection {
public:
- ElemSection(uint32_t Offset)
- : SyntheticSection(llvm::wasm::WASM_SEC_ELEM), ElemOffset(Offset) {}
- bool isNeeded() const override { return IndirectFunctions.size() > 0; };
+ ElemSection(uint32_t offset)
+ : SyntheticSection(llvm::wasm::WASM_SEC_ELEM), elemOffset(offset) {}
+ bool isNeeded() const override { return indirectFunctions.size() > 0; };
void writeBody() override;
- void addEntry(FunctionSymbol *Sym);
- uint32_t numEntries() const { return IndirectFunctions.size(); }
- uint32_t ElemOffset;
+ void addEntry(FunctionSymbol *sym);
+ uint32_t numEntries() const { return indirectFunctions.size(); }
+ uint32_t elemOffset;
protected:
- std::vector<const FunctionSymbol *> IndirectFunctions;
+ std::vector<const FunctionSymbol *> indirectFunctions;
};
class DataCountSection : public SyntheticSection {
public:
- DataCountSection(uint32_t NumSegments)
+ DataCountSection(uint32_t numSegments)
: SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT),
- NumSegments(NumSegments) {}
+ numSegments(numSegments) {}
bool isNeeded() const override;
void writeBody() override;
protected:
- uint32_t NumSegments;
+ uint32_t numSegments;
};
// Create the custom "linking" section containing linker metadata.
// This is only created when relocatable output is requested.
class LinkingSection : public SyntheticSection {
public:
- LinkingSection(const std::vector<WasmInitEntry> &InitFunctions,
- const std::vector<OutputSegment *> &DataSegments)
+ LinkingSection(const std::vector<WasmInitEntry> &initFunctions,
+ const std::vector<OutputSegment *> &dataSegments)
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"),
- InitFunctions(InitFunctions), DataSegments(DataSegments) {}
+ initFunctions(initFunctions), dataSegments(dataSegments) {}
bool isNeeded() const override {
- return Config->Relocatable || Config->EmitRelocs;
+ return config->relocatable || config->emitRelocs;
}
void writeBody() override;
- void addToSymtab(Symbol *Sym);
+ void addToSymtab(Symbol *sym);
protected:
- std::vector<const Symbol *> SymtabEntries;
- llvm::StringMap<uint32_t> SectionSymbolIndices;
- const std::vector<WasmInitEntry> &InitFunctions;
- const std::vector<OutputSegment *> &DataSegments;
+ std::vector<const Symbol *> symtabEntries;
+ llvm::StringMap<uint32_t> sectionSymbolIndices;
+ const std::vector<WasmInitEntry> &initFunctions;
+ const std::vector<OutputSegment *> &dataSegments;
};
// Create the custom "name" section containing debug symbol names.
public:
NameSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name") {}
bool isNeeded() const override {
- return !Config->StripDebug && !Config->StripAll && numNames() > 0;
+ return !config->stripDebug && !config->stripAll && numNames() > 0;
}
void writeBody() override;
unsigned numNames() const;
ProducersSection()
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {}
bool isNeeded() const override {
- return !Config->StripAll && fieldCount() > 0;
+ return !config->stripAll && fieldCount() > 0;
}
void writeBody() override;
- void addInfo(const llvm::wasm::WasmProducerInfo &Info);
+ void addInfo(const llvm::wasm::WasmProducerInfo &info);
protected:
int fieldCount() const {
- return int(!Languages.empty()) + int(!Tools.empty()) + int(!SDKs.empty());
+ return int(!languages.empty()) + int(!tools.empty()) + int(!sDKs.empty());
}
- SmallVector<std::pair<std::string, std::string>, 8> Languages;
- SmallVector<std::pair<std::string, std::string>, 8> Tools;
- SmallVector<std::pair<std::string, std::string>, 8> SDKs;
+ SmallVector<std::pair<std::string, std::string>, 8> languages;
+ SmallVector<std::pair<std::string, std::string>, 8> tools;
+ SmallVector<std::pair<std::string, std::string>, 8> sDKs;
};
class TargetFeaturesSection : public SyntheticSection {
TargetFeaturesSection()
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {}
bool isNeeded() const override {
- return !Config->StripAll && Features.size() > 0;
+ return !config->stripAll && features.size() > 0;
}
void writeBody() override;
- llvm::SmallSet<std::string, 8> Features;
+ llvm::SmallSet<std::string, 8> features;
};
class RelocSection : public SyntheticSection {
public:
- RelocSection(StringRef Name, OutputSection *Sec)
- : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, Name), Sec(Sec) {}
+ RelocSection(StringRef name, OutputSection *sec)
+ : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, name), sec(sec) {}
void writeBody() override;
- bool isNeeded() const override { return Sec->getNumRelocations() > 0; };
+ bool isNeeded() const override { return sec->getNumRelocations() > 0; };
protected:
- OutputSection *Sec;
+ OutputSection *sec;
};
// Linker generated output sections
struct OutStruct {
- DylinkSection *DylinkSec;
- TypeSection *TypeSec;
- FunctionSection *FunctionSec;
- ImportSection *ImportSec;
- TableSection *TableSec;
- MemorySection *MemorySec;
- GlobalSection *GlobalSec;
- EventSection *EventSec;
- ExportSection *ExportSec;
- ElemSection *ElemSec;
- DataCountSection *DataCountSec;
- LinkingSection *LinkingSec;
- NameSection *NameSec;
- ProducersSection *ProducersSec;
- TargetFeaturesSection *TargetFeaturesSec;
+ DylinkSection *dylinkSec;
+ TypeSection *typeSec;
+ FunctionSection *functionSec;
+ ImportSection *importSec;
+ TableSection *tableSec;
+ MemorySection *memorySec;
+ GlobalSection *globalSec;
+ EventSection *eventSec;
+ ExportSection *exportSec;
+ ElemSection *elemSec;
+ DataCountSection *dataCountSec;
+ LinkingSection *linkingSec;
+ NameSection *nameSec;
+ ProducersSection *producersSec;
+ TargetFeaturesSection *targetFeaturesSec;
};
-extern OutStruct Out;
+extern OutStruct out;
} // namespace wasm
} // namespace lld
using namespace lld;
using namespace lld::wasm;
-static constexpr int StackAlignment = 16;
+static constexpr int stackAlignment = 16;
namespace {
void layoutMemory();
void createHeader();
- void addSection(OutputSection *Sec);
+ void addSection(OutputSection *sec);
void addSections();
void writeHeader();
void writeSections();
- uint64_t FileSize = 0;
- uint32_t TableBase = 0;
+ uint64_t fileSize = 0;
+ uint32_t tableBase = 0;
- std::vector<WasmInitEntry> InitFunctions;
- llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping;
+ std::vector<WasmInitEntry> initFunctions;
+ llvm::StringMap<std::vector<InputSection *>> customSectionMapping;
// Elements that are used to construct the final output
- std::string Header;
- std::vector<OutputSection *> OutputSections;
+ std::string header;
+ std::vector<OutputSection *> outputSections;
- std::unique_ptr<FileOutputBuffer> Buffer;
+ std::unique_ptr<FileOutputBuffer> buffer;
- std::vector<OutputSegment *> Segments;
- llvm::SmallDenseMap<StringRef, OutputSegment *> SegmentMap;
+ std::vector<OutputSegment *> segments;
+ llvm::SmallDenseMap<StringRef, OutputSegment *> segmentMap;
};
} // anonymous namespace
void Writer::calculateCustomSections() {
log("calculateCustomSections");
- bool StripDebug = Config->StripDebug || Config->StripAll;
- for (ObjFile *File : Symtab->ObjectFiles) {
- for (InputSection *Section : File->CustomSections) {
- StringRef Name = Section->getName();
+ bool stripDebug = config->stripDebug || config->stripAll;
+ for (ObjFile *file : symtab->objectFiles) {
+ for (InputSection *section : file->customSections) {
+ StringRef name = section->getName();
// These custom sections are known the linker and synthesized rather than
// blindly copied
- if (Name == "linking" || Name == "name" || Name == "producers" ||
- Name == "target_features" || Name.startswith("reloc."))
+ if (name == "linking" || name == "name" || name == "producers" ||
+ name == "target_features" || name.startswith("reloc."))
continue;
// .. or it is a debug section
- if (StripDebug && Name.startswith(".debug_"))
+ if (stripDebug && name.startswith(".debug_"))
continue;
- CustomSectionMapping[Name].push_back(Section);
+ customSectionMapping[name].push_back(section);
}
}
}
void Writer::createCustomSections() {
log("createCustomSections");
- for (auto &Pair : CustomSectionMapping) {
- StringRef Name = Pair.first();
- LLVM_DEBUG(dbgs() << "createCustomSection: " << Name << "\n");
-
- OutputSection *Sec = make<CustomSection>(Name, Pair.second);
- if (Config->Relocatable || Config->EmitRelocs) {
- auto *Sym = make<OutputSectionSymbol>(Sec);
- Out.LinkingSec->addToSymtab(Sym);
- Sec->SectionSym = Sym;
+ for (auto &pair : customSectionMapping) {
+ StringRef name = pair.first();
+ LLVM_DEBUG(dbgs() << "createCustomSection: " << name << "\n");
+
+ OutputSection *sec = make<CustomSection>(name, pair.second);
+ if (config->relocatable || config->emitRelocs) {
+ auto *sym = make<OutputSectionSymbol>(sec);
+ out.linkingSec->addToSymtab(sym);
+ sec->sectionSym = sym;
}
- addSection(Sec);
+ addSection(sec);
}
}
void Writer::createRelocSections() {
log("createRelocSections");
// Don't use iterator here since we are adding to OutputSection
- size_t OrigSize = OutputSections.size();
- for (size_t I = 0; I < OrigSize; I++) {
- LLVM_DEBUG(dbgs() << "check section " << I << "\n");
- OutputSection *Sec = OutputSections[I];
+ size_t origSize = outputSections.size();
+ for (size_t i = 0; i < origSize; i++) {
+ LLVM_DEBUG(dbgs() << "check section " << i << "\n");
+ OutputSection *sec = outputSections[i];
// Count the number of needed sections.
- uint32_t Count = Sec->getNumRelocations();
- if (!Count)
+ uint32_t count = sec->getNumRelocations();
+ if (!count)
continue;
- StringRef Name;
- if (Sec->Type == WASM_SEC_DATA)
- Name = "reloc.DATA";
- else if (Sec->Type == WASM_SEC_CODE)
- Name = "reloc.CODE";
- else if (Sec->Type == WASM_SEC_CUSTOM)
- Name = Saver.save("reloc." + Sec->Name);
+ StringRef name;
+ if (sec->type == WASM_SEC_DATA)
+ name = "reloc.DATA";
+ else if (sec->type == WASM_SEC_CODE)
+ name = "reloc.CODE";
+ else if (sec->type == WASM_SEC_CUSTOM)
+ name = saver.save("reloc." + sec->name);
else
llvm_unreachable(
"relocations only supported for code, data, or custom sections");
- addSection(make<RelocSection>(Name, Sec));
+ addSection(make<RelocSection>(name, sec));
}
}
void Writer::populateProducers() {
- for (ObjFile *File : Symtab->ObjectFiles) {
- const WasmProducerInfo &Info = File->getWasmObj()->getProducerInfo();
- Out.ProducersSec->addInfo(Info);
+ for (ObjFile *file : symtab->objectFiles) {
+ const WasmProducerInfo &info = file->getWasmObj()->getProducerInfo();
+ out.producersSec->addInfo(info);
}
}
void Writer::writeHeader() {
- memcpy(Buffer->getBufferStart(), Header.data(), Header.size());
+ memcpy(buffer->getBufferStart(), header.data(), header.size());
}
void Writer::writeSections() {
- uint8_t *Buf = Buffer->getBufferStart();
- parallelForEach(OutputSections, [Buf](OutputSection *S) {
- assert(S->isNeeded());
- S->writeTo(Buf);
+ uint8_t *buf = buffer->getBufferStart();
+ parallelForEach(outputSections, [buf](OutputSection *s) {
+ assert(s->isNeeded());
+ s->writeTo(buf);
});
}
// rather than overwriting global data, but also increases code size since all
// static data loads and stores requires larger offsets.
void Writer::layoutMemory() {
- uint32_t MemoryPtr = 0;
+ uint32_t memoryPtr = 0;
- auto PlaceStack = [&]() {
- if (Config->Relocatable || Config->Shared)
+ auto placeStack = [&]() {
+ if (config->relocatable || config->shared)
return;
- MemoryPtr = alignTo(MemoryPtr, StackAlignment);
- if (Config->ZStackSize != alignTo(Config->ZStackSize, StackAlignment))
- error("stack size must be " + Twine(StackAlignment) + "-byte aligned");
- log("mem: stack size = " + Twine(Config->ZStackSize));
- log("mem: stack base = " + Twine(MemoryPtr));
- MemoryPtr += Config->ZStackSize;
- auto *SP = cast<DefinedGlobal>(WasmSym::StackPointer);
- SP->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
- log("mem: stack top = " + Twine(MemoryPtr));
+ memoryPtr = alignTo(memoryPtr, stackAlignment);
+ if (config->zStackSize != alignTo(config->zStackSize, stackAlignment))
+ error("stack size must be " + Twine(stackAlignment) + "-byte aligned");
+ log("mem: stack size = " + Twine(config->zStackSize));
+ log("mem: stack base = " + Twine(memoryPtr));
+ memoryPtr += config->zStackSize;
+ auto *sp = cast<DefinedGlobal>(WasmSym::stackPointer);
+ sp->global->global.InitExpr.Value.Int32 = memoryPtr;
+ log("mem: stack top = " + Twine(memoryPtr));
};
- if (Config->StackFirst) {
- PlaceStack();
+ if (config->stackFirst) {
+ placeStack();
} else {
- MemoryPtr = Config->GlobalBase;
- log("mem: global base = " + Twine(Config->GlobalBase));
+ memoryPtr = config->globalBase;
+ log("mem: global base = " + Twine(config->globalBase));
}
- if (WasmSym::GlobalBase)
- WasmSym::GlobalBase->setVirtualAddress(Config->GlobalBase);
+ if (WasmSym::globalBase)
+ WasmSym::globalBase->setVirtualAddress(config->globalBase);
- uint32_t DataStart = MemoryPtr;
+ uint32_t dataStart = memoryPtr;
// Arbitrarily set __dso_handle handle to point to the start of the data
// segments.
- if (WasmSym::DsoHandle)
- WasmSym::DsoHandle->setVirtualAddress(DataStart);
+ if (WasmSym::dsoHandle)
+ WasmSym::dsoHandle->setVirtualAddress(dataStart);
- Out.DylinkSec->MemAlign = 0;
- for (OutputSegment *Seg : Segments) {
- Out.DylinkSec->MemAlign = std::max(Out.DylinkSec->MemAlign, Seg->Alignment);
- MemoryPtr = alignTo(MemoryPtr, 1ULL << Seg->Alignment);
- Seg->StartVA = MemoryPtr;
- log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Seg->Name,
- MemoryPtr, Seg->Size, Seg->Alignment));
- MemoryPtr += Seg->Size;
+ out.dylinkSec->memAlign = 0;
+ for (OutputSegment *seg : segments) {
+ out.dylinkSec->memAlign = std::max(out.dylinkSec->memAlign, seg->alignment);
+ memoryPtr = alignTo(memoryPtr, 1ULL << seg->alignment);
+ seg->startVA = memoryPtr;
+ log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", seg->name,
+ memoryPtr, seg->size, seg->alignment));
+ memoryPtr += seg->size;
}
// TODO: Add .bss space here.
- if (WasmSym::DataEnd)
- WasmSym::DataEnd->setVirtualAddress(MemoryPtr);
+ if (WasmSym::dataEnd)
+ WasmSym::dataEnd->setVirtualAddress(memoryPtr);
- log("mem: static data = " + Twine(MemoryPtr - DataStart));
+ log("mem: static data = " + Twine(memoryPtr - dataStart));
- if (Config->Shared) {
- Out.DylinkSec->MemSize = MemoryPtr;
+ if (config->shared) {
+ out.dylinkSec->memSize = memoryPtr;
return;
}
- if (!Config->StackFirst)
- PlaceStack();
+ if (!config->stackFirst)
+ placeStack();
// Set `__heap_base` to directly follow the end of the stack or global data.
// The fact that this comes last means that a malloc/brk implementation
// can grow the heap at runtime.
- log("mem: heap base = " + Twine(MemoryPtr));
- if (WasmSym::HeapBase)
- WasmSym::HeapBase->setVirtualAddress(MemoryPtr);
+ log("mem: heap base = " + Twine(memoryPtr));
+ if (WasmSym::heapBase)
+ WasmSym::heapBase->setVirtualAddress(memoryPtr);
- if (Config->InitialMemory != 0) {
- if (Config->InitialMemory != alignTo(Config->InitialMemory, WasmPageSize))
+ if (config->initialMemory != 0) {
+ if (config->initialMemory != alignTo(config->initialMemory, WasmPageSize))
error("initial memory must be " + Twine(WasmPageSize) + "-byte aligned");
- if (MemoryPtr > Config->InitialMemory)
- error("initial memory too small, " + Twine(MemoryPtr) + " bytes needed");
+ if (memoryPtr > config->initialMemory)
+ error("initial memory too small, " + Twine(memoryPtr) + " bytes needed");
else
- MemoryPtr = Config->InitialMemory;
+ memoryPtr = config->initialMemory;
}
- Out.DylinkSec->MemSize = MemoryPtr;
- Out.MemorySec->NumMemoryPages =
- alignTo(MemoryPtr, WasmPageSize) / WasmPageSize;
- log("mem: total pages = " + Twine(Out.MemorySec->NumMemoryPages));
+ out.dylinkSec->memSize = memoryPtr;
+ out.memorySec->numMemoryPages =
+ alignTo(memoryPtr, WasmPageSize) / WasmPageSize;
+ log("mem: total pages = " + Twine(out.memorySec->numMemoryPages));
// Check max if explicitly supplied or required by shared memory
- if (Config->MaxMemory != 0 || Config->SharedMemory) {
- if (Config->MaxMemory != alignTo(Config->MaxMemory, WasmPageSize))
+ if (config->maxMemory != 0 || config->sharedMemory) {
+ if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize))
error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned");
- if (MemoryPtr > Config->MaxMemory)
- error("maximum memory too small, " + Twine(MemoryPtr) + " bytes needed");
- Out.MemorySec->MaxMemoryPages = Config->MaxMemory / WasmPageSize;
- log("mem: max pages = " + Twine(Out.MemorySec->MaxMemoryPages));
+ if (memoryPtr > config->maxMemory)
+ error("maximum memory too small, " + Twine(memoryPtr) + " bytes needed");
+ out.memorySec->maxMemoryPages = config->maxMemory / WasmPageSize;
+ log("mem: max pages = " + Twine(out.memorySec->maxMemoryPages));
}
}
-void Writer::addSection(OutputSection *Sec) {
- if (!Sec->isNeeded())
+void Writer::addSection(OutputSection *sec) {
+ if (!sec->isNeeded())
return;
- log("addSection: " + toString(*Sec));
- Sec->SectionIndex = OutputSections.size();
- OutputSections.push_back(Sec);
+ log("addSection: " + toString(*sec));
+ sec->sectionIndex = outputSections.size();
+ outputSections.push_back(sec);
}
// If a section name is valid as a C identifier (which is rare because of
// __stop_<secname> symbols. They are at beginning and end of the section,
// respectively. This is not requested by the ELF standard, but GNU ld and
// gold provide the feature, and used by many programs.
-static void addStartStopSymbols(const OutputSegment *Seg) {
- StringRef Name = Seg->Name;
- if (!isValidCIdentifier(Name))
+static void addStartStopSymbols(const OutputSegment *seg) {
+ StringRef name = seg->name;
+ if (!isValidCIdentifier(name))
return;
- LLVM_DEBUG(dbgs() << "addStartStopSymbols: " << Name << "\n");
- uint32_t Start = Seg->StartVA;
- uint32_t Stop = Start + Seg->Size;
- Symtab->addOptionalDataSymbol(Saver.save("__start_" + Name), Start);
- Symtab->addOptionalDataSymbol(Saver.save("__stop_" + Name), Stop);
+ LLVM_DEBUG(dbgs() << "addStartStopSymbols: " << name << "\n");
+ uint32_t start = seg->startVA;
+ uint32_t stop = start + seg->size;
+ symtab->addOptionalDataSymbol(saver.save("__start_" + name), start);
+ symtab->addOptionalDataSymbol(saver.save("__stop_" + name), stop);
}
void Writer::addSections() {
- addSection(Out.DylinkSec);
- addSection(Out.TypeSec);
- addSection(Out.ImportSec);
- addSection(Out.FunctionSec);
- addSection(Out.TableSec);
- addSection(Out.MemorySec);
- addSection(Out.GlobalSec);
- addSection(Out.EventSec);
- addSection(Out.ExportSec);
- addSection(Out.ElemSec);
- addSection(Out.DataCountSec);
-
- addSection(make<CodeSection>(Out.FunctionSec->InputFunctions));
- addSection(make<DataSection>(Segments));
+ addSection(out.dylinkSec);
+ addSection(out.typeSec);
+ addSection(out.importSec);
+ addSection(out.functionSec);
+ addSection(out.tableSec);
+ addSection(out.memorySec);
+ addSection(out.globalSec);
+ addSection(out.eventSec);
+ addSection(out.exportSec);
+ addSection(out.elemSec);
+ addSection(out.dataCountSec);
+
+ addSection(make<CodeSection>(out.functionSec->inputFunctions));
+ addSection(make<DataSection>(segments));
createCustomSections();
- addSection(Out.LinkingSec);
- if (Config->EmitRelocs || Config->Relocatable) {
+ addSection(out.linkingSec);
+ if (config->emitRelocs || config->relocatable) {
createRelocSections();
}
- addSection(Out.NameSec);
- addSection(Out.ProducersSec);
- addSection(Out.TargetFeaturesSec);
+ addSection(out.nameSec);
+ addSection(out.producersSec);
+ addSection(out.targetFeaturesSec);
}
void Writer::finalizeSections() {
- for (OutputSection *S : OutputSections) {
- S->setOffset(FileSize);
- S->finalizeContents();
- FileSize += S->getSize();
+ for (OutputSection *s : outputSections) {
+ s->setOffset(fileSize);
+ s->finalizeContents();
+ fileSize += s->getSize();
}
}
void Writer::populateTargetFeatures() {
- StringMap<std::string> Used;
- StringMap<std::string> Required;
- StringMap<std::string> Disallowed;
+ StringMap<std::string> used;
+ StringMap<std::string> required;
+ StringMap<std::string> disallowed;
// Only infer used features if user did not specify features
- bool InferFeatures = !Config->Features.hasValue();
+ bool inferFeatures = !config->features.hasValue();
- if (!InferFeatures) {
- for (auto &Feature : Config->Features.getValue())
- Out.TargetFeaturesSec->Features.insert(Feature);
+ if (!inferFeatures) {
+ for (auto &feature : config->features.getValue())
+ out.targetFeaturesSec->features.insert(feature);
// No need to read or check features
- if (!Config->CheckFeatures)
+ if (!config->checkFeatures)
return;
}
// Find the sets of used, required, and disallowed features
- for (ObjFile *File : Symtab->ObjectFiles) {
- StringRef FileName(File->getName());
- for (auto &Feature : File->getWasmObj()->getTargetFeatures()) {
- switch (Feature.Prefix) {
+ for (ObjFile *file : symtab->objectFiles) {
+ StringRef fileName(file->getName());
+ for (auto &feature : file->getWasmObj()->getTargetFeatures()) {
+ switch (feature.Prefix) {
case WASM_FEATURE_PREFIX_USED:
- Used.insert({Feature.Name, FileName});
+ used.insert({feature.Name, fileName});
break;
case WASM_FEATURE_PREFIX_REQUIRED:
- Used.insert({Feature.Name, FileName});
- Required.insert({Feature.Name, FileName});
+ used.insert({feature.Name, fileName});
+ required.insert({feature.Name, fileName});
break;
case WASM_FEATURE_PREFIX_DISALLOWED:
- Disallowed.insert({Feature.Name, FileName});
+ disallowed.insert({feature.Name, fileName});
break;
default:
error("Unrecognized feature policy prefix " +
- std::to_string(Feature.Prefix));
+ std::to_string(feature.Prefix));
}
}
}
- if (InferFeatures)
- Out.TargetFeaturesSec->Features.insert(Used.keys().begin(),
- Used.keys().end());
+ if (inferFeatures)
+ out.targetFeaturesSec->features.insert(used.keys().begin(),
+ used.keys().end());
- if (Out.TargetFeaturesSec->Features.count("atomics") &&
- !Config->SharedMemory) {
- if (InferFeatures)
- error(Twine("'atomics' feature is used by ") + Used["atomics"] +
+ if (out.targetFeaturesSec->features.count("atomics") &&
+ !config->sharedMemory) {
+ if (inferFeatures)
+ error(Twine("'atomics' feature is used by ") + used["atomics"] +
", so --shared-memory must be used");
else
error("'atomics' feature is used, so --shared-memory must be used");
}
- if (!Config->CheckFeatures)
+ if (!config->checkFeatures)
return;
- if (Disallowed.count("atomics") && Config->SharedMemory)
- error("'atomics' feature is disallowed by " + Disallowed["atomics"] +
+ if (disallowed.count("atomics") && config->sharedMemory)
+ error("'atomics' feature is disallowed by " + disallowed["atomics"] +
", so --shared-memory must not be used");
- if (!Used.count("bulk-memory") && Config->PassiveSegments)
+ if (!used.count("bulk-memory") && config->passiveSegments)
error("'bulk-memory' feature must be used in order to emit passive "
"segments");
// Validate that used features are allowed in output
- if (!InferFeatures) {
- for (auto &Feature : Used.keys()) {
- if (!Out.TargetFeaturesSec->Features.count(Feature))
- error(Twine("Target feature '") + Feature + "' used by " +
- Used[Feature] + " is not allowed.");
+ if (!inferFeatures) {
+ for (auto &feature : used.keys()) {
+ if (!out.targetFeaturesSec->features.count(feature))
+ error(Twine("Target feature '") + feature + "' used by " +
+ used[feature] + " is not allowed.");
}
}
// Validate the required and disallowed constraints for each file
- for (ObjFile *File : Symtab->ObjectFiles) {
- StringRef FileName(File->getName());
- SmallSet<std::string, 8> ObjectFeatures;
- for (auto &Feature : File->getWasmObj()->getTargetFeatures()) {
- if (Feature.Prefix == WASM_FEATURE_PREFIX_DISALLOWED)
+ for (ObjFile *file : symtab->objectFiles) {
+ StringRef fileName(file->getName());
+ SmallSet<std::string, 8> objectFeatures;
+ for (auto &feature : file->getWasmObj()->getTargetFeatures()) {
+ if (feature.Prefix == WASM_FEATURE_PREFIX_DISALLOWED)
continue;
- ObjectFeatures.insert(Feature.Name);
- if (Disallowed.count(Feature.Name))
- error(Twine("Target feature '") + Feature.Name + "' used in " +
- FileName + " is disallowed by " + Disallowed[Feature.Name] +
+ objectFeatures.insert(feature.Name);
+ if (disallowed.count(feature.Name))
+ error(Twine("Target feature '") + feature.Name + "' used in " +
+ fileName + " is disallowed by " + disallowed[feature.Name] +
". Use --no-check-features to suppress.");
}
- for (auto &Feature : Required.keys()) {
- if (!ObjectFeatures.count(Feature))
- error(Twine("Missing target feature '") + Feature + "' in " + FileName +
- ", required by " + Required[Feature] +
+ for (auto &feature : required.keys()) {
+ if (!objectFeatures.count(feature))
+ error(Twine("Missing target feature '") + feature + "' in " + fileName +
+ ", required by " + required[feature] +
". Use --no-check-features to suppress.");
}
}
}
void Writer::calculateImports() {
- for (Symbol *Sym : Symtab->getSymbols()) {
- if (!Sym->isUndefined())
+ for (Symbol *sym : symtab->getSymbols()) {
+ if (!sym->isUndefined())
continue;
- if (Sym->isWeak() && !Config->Relocatable)
+ if (sym->isWeak() && !config->relocatable)
continue;
- if (!Sym->isLive())
+ if (!sym->isLive())
continue;
- if (!Sym->IsUsedInRegularObj)
+ if (!sym->isUsedInRegularObj)
continue;
// We don't generate imports for data symbols. They however can be imported
// as GOT entries.
- if (isa<DataSymbol>(Sym))
+ if (isa<DataSymbol>(sym))
continue;
- LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
- Out.ImportSec->addImport(Sym);
+ LLVM_DEBUG(dbgs() << "import: " << sym->getName() << "\n");
+ out.importSec->addImport(sym);
}
}
void Writer::calculateExports() {
- if (Config->Relocatable)
+ if (config->relocatable)
return;
- if (!Config->Relocatable && !Config->ImportMemory)
- Out.ExportSec->Exports.push_back(
+ if (!config->relocatable && !config->importMemory)
+ out.exportSec->exports.push_back(
WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
- if (!Config->Relocatable && Config->ExportTable)
- Out.ExportSec->Exports.push_back(
- WasmExport{FunctionTableName, WASM_EXTERNAL_TABLE, 0});
+ if (!config->relocatable && config->exportTable)
+ out.exportSec->exports.push_back(
+ WasmExport{functionTableName, WASM_EXTERNAL_TABLE, 0});
- unsigned FakeGlobalIndex = Out.ImportSec->getNumImportedGlobals() +
- Out.GlobalSec->InputGlobals.size();
+ unsigned fakeGlobalIndex = out.importSec->getNumImportedGlobals() +
+ out.globalSec->inputGlobals.size();
- for (Symbol *Sym : Symtab->getSymbols()) {
- if (!Sym->isExported())
+ for (Symbol *sym : symtab->getSymbols()) {
+ if (!sym->isExported())
continue;
- if (!Sym->isLive())
+ if (!sym->isLive())
continue;
- StringRef Name = Sym->getName();
- WasmExport Export;
- if (auto *F = dyn_cast<DefinedFunction>(Sym)) {
- Export = {Name, WASM_EXTERNAL_FUNCTION, F->getFunctionIndex()};
- } else if (auto *G = dyn_cast<DefinedGlobal>(Sym)) {
+ StringRef name = sym->getName();
+ WasmExport export_;
+ if (auto *f = dyn_cast<DefinedFunction>(sym)) {
+ export_ = {name, WASM_EXTERNAL_FUNCTION, f->getFunctionIndex()};
+ } else if (auto *g = dyn_cast<DefinedGlobal>(sym)) {
// TODO(sbc): Remove this check once to mutable global proposal is
// implement in all major browsers.
// See: https://github.com/WebAssembly/mutable-global
- if (G->getGlobalType()->Mutable) {
+ if (g->getGlobalType()->Mutable) {
// Only the __stack_pointer should ever be create as mutable.
- assert(G == WasmSym::StackPointer);
+ assert(g == WasmSym::stackPointer);
continue;
}
- Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
- } else if (auto *E = dyn_cast<DefinedEvent>(Sym)) {
- Export = {Name, WASM_EXTERNAL_EVENT, E->getEventIndex()};
+ export_ = {name, WASM_EXTERNAL_GLOBAL, g->getGlobalIndex()};
+ } else if (auto *e = dyn_cast<DefinedEvent>(sym)) {
+ export_ = {name, WASM_EXTERNAL_EVENT, e->getEventIndex()};
} else {
- auto *D = cast<DefinedData>(Sym);
- Out.GlobalSec->DefinedFakeGlobals.emplace_back(D);
- Export = {Name, WASM_EXTERNAL_GLOBAL, FakeGlobalIndex++};
+ auto *d = cast<DefinedData>(sym);
+ out.globalSec->definedFakeGlobals.emplace_back(d);
+ export_ = {name, WASM_EXTERNAL_GLOBAL, fakeGlobalIndex++};
}
- LLVM_DEBUG(dbgs() << "Export: " << Name << "\n");
- Out.ExportSec->Exports.push_back(Export);
+ LLVM_DEBUG(dbgs() << "Export: " << name << "\n");
+ out.exportSec->exports.push_back(export_);
}
}
void Writer::populateSymtab() {
- if (!Config->Relocatable && !Config->EmitRelocs)
+ if (!config->relocatable && !config->emitRelocs)
return;
- for (Symbol *Sym : Symtab->getSymbols())
- if (Sym->IsUsedInRegularObj && Sym->isLive())
- Out.LinkingSec->addToSymtab(Sym);
+ for (Symbol *sym : symtab->getSymbols())
+ if (sym->isUsedInRegularObj && sym->isLive())
+ out.linkingSec->addToSymtab(sym);
- for (ObjFile *File : Symtab->ObjectFiles) {
- LLVM_DEBUG(dbgs() << "Local symtab entries: " << File->getName() << "\n");
- for (Symbol *Sym : File->getSymbols())
- if (Sym->isLocal() && !isa<SectionSymbol>(Sym) && Sym->isLive())
- Out.LinkingSec->addToSymtab(Sym);
+ for (ObjFile *file : symtab->objectFiles) {
+ LLVM_DEBUG(dbgs() << "Local symtab entries: " << file->getName() << "\n");
+ for (Symbol *sym : file->getSymbols())
+ if (sym->isLocal() && !isa<SectionSymbol>(sym) && sym->isLive())
+ out.linkingSec->addToSymtab(sym);
}
}
// 4. The signatures of all imported events
// 5. The signatures of all defined events
- for (ObjFile *File : Symtab->ObjectFiles) {
- ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
- for (uint32_t I = 0; I < Types.size(); I++)
- if (File->TypeIsUsed[I])
- File->TypeMap[I] = Out.TypeSec->registerType(Types[I]);
+ for (ObjFile *file : symtab->objectFiles) {
+ ArrayRef<WasmSignature> types = file->getWasmObj()->types();
+ for (uint32_t i = 0; i < types.size(); i++)
+ if (file->typeIsUsed[i])
+ file->typeMap[i] = out.typeSec->registerType(types[i]);
}
- for (const Symbol *Sym : Out.ImportSec->ImportedSymbols) {
- if (auto *F = dyn_cast<FunctionSymbol>(Sym))
- Out.TypeSec->registerType(*F->Signature);
- else if (auto *E = dyn_cast<EventSymbol>(Sym))
- Out.TypeSec->registerType(*E->Signature);
+ for (const Symbol *sym : out.importSec->importedSymbols) {
+ if (auto *f = dyn_cast<FunctionSymbol>(sym))
+ out.typeSec->registerType(*f->signature);
+ else if (auto *e = dyn_cast<EventSymbol>(sym))
+ out.typeSec->registerType(*e->signature);
}
- for (const InputFunction *F : Out.FunctionSec->InputFunctions)
- Out.TypeSec->registerType(F->Signature);
+ for (const InputFunction *f : out.functionSec->inputFunctions)
+ out.typeSec->registerType(f->signature);
- for (const InputEvent *E : Out.EventSec->InputEvents)
- Out.TypeSec->registerType(E->Signature);
+ for (const InputEvent *e : out.eventSec->inputEvents)
+ out.typeSec->registerType(e->signature);
}
static void scanRelocations() {
- for (ObjFile *File : Symtab->ObjectFiles) {
- LLVM_DEBUG(dbgs() << "scanRelocations: " << File->getName() << "\n");
- for (InputChunk *Chunk : File->Functions)
- scanRelocations(Chunk);
- for (InputChunk *Chunk : File->Segments)
- scanRelocations(Chunk);
- for (auto &P : File->CustomSections)
- scanRelocations(P);
+ for (ObjFile *file : symtab->objectFiles) {
+ LLVM_DEBUG(dbgs() << "scanRelocations: " << file->getName() << "\n");
+ for (InputChunk *chunk : file->functions)
+ scanRelocations(chunk);
+ for (InputChunk *chunk : file->segments)
+ scanRelocations(chunk);
+ for (auto &p : file->customSections)
+ scanRelocations(p);
}
}
void Writer::assignIndexes() {
// Seal the import section, since other index spaces such as function and
// global are effected by the number of imports.
- Out.ImportSec->seal();
+ out.importSec->seal();
- for (InputFunction *Func : Symtab->SyntheticFunctions)
- Out.FunctionSec->addFunction(Func);
+ for (InputFunction *func : symtab->syntheticFunctions)
+ out.functionSec->addFunction(func);
- for (ObjFile *File : Symtab->ObjectFiles) {
- LLVM_DEBUG(dbgs() << "Functions: " << File->getName() << "\n");
- for (InputFunction *Func : File->Functions)
- Out.FunctionSec->addFunction(Func);
+ for (ObjFile *file : symtab->objectFiles) {
+ LLVM_DEBUG(dbgs() << "Functions: " << file->getName() << "\n");
+ for (InputFunction *func : file->functions)
+ out.functionSec->addFunction(func);
}
- for (InputGlobal *Global : Symtab->SyntheticGlobals)
- Out.GlobalSec->addGlobal(Global);
+ for (InputGlobal *global : symtab->syntheticGlobals)
+ out.globalSec->addGlobal(global);
- for (ObjFile *File : Symtab->ObjectFiles) {
- LLVM_DEBUG(dbgs() << "Globals: " << File->getName() << "\n");
- for (InputGlobal *Global : File->Globals)
- Out.GlobalSec->addGlobal(Global);
+ for (ObjFile *file : symtab->objectFiles) {
+ LLVM_DEBUG(dbgs() << "Globals: " << file->getName() << "\n");
+ for (InputGlobal *global : file->globals)
+ out.globalSec->addGlobal(global);
}
- for (ObjFile *File : Symtab->ObjectFiles) {
- LLVM_DEBUG(dbgs() << "Events: " << File->getName() << "\n");
- for (InputEvent *Event : File->Events)
- Out.EventSec->addEvent(Event);
+ for (ObjFile *file : symtab->objectFiles) {
+ LLVM_DEBUG(dbgs() << "Events: " << file->getName() << "\n");
+ for (InputEvent *event : file->events)
+ out.eventSec->addEvent(event);
}
}
-static StringRef getOutputDataSegmentName(StringRef Name) {
+static StringRef getOutputDataSegmentName(StringRef name) {
// With PIC code we currently only support a single data segment since
// we only have a single __memory_base to use as our base address.
- if (Config->Pic)
+ if (config->isPic)
return ".data";
- if (!Config->MergeDataSegments)
- return Name;
- if (Name.startswith(".text."))
+ if (!config->mergeDataSegments)
+ return name;
+ if (name.startswith(".text."))
return ".text";
- if (Name.startswith(".data."))
+ if (name.startswith(".data."))
return ".data";
- if (Name.startswith(".bss."))
+ if (name.startswith(".bss."))
return ".bss";
- if (Name.startswith(".rodata."))
+ if (name.startswith(".rodata."))
return ".rodata";
- return Name;
+ return name;
}
void Writer::createOutputSegments() {
- for (ObjFile *File : Symtab->ObjectFiles) {
- for (InputSegment *Segment : File->Segments) {
- if (!Segment->Live)
+ for (ObjFile *file : symtab->objectFiles) {
+ for (InputSegment *segment : file->segments) {
+ if (!segment->live)
continue;
- StringRef Name = getOutputDataSegmentName(Segment->getName());
- OutputSegment *&S = SegmentMap[Name];
- if (S == nullptr) {
- LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n");
- S = make<OutputSegment>(Name, Segments.size());
- if (Config->PassiveSegments)
- S->InitFlags = WASM_SEGMENT_IS_PASSIVE;
- Segments.push_back(S);
+ StringRef name = getOutputDataSegmentName(segment->getName());
+ OutputSegment *&s = segmentMap[name];
+ if (s == nullptr) {
+ LLVM_DEBUG(dbgs() << "new segment: " << name << "\n");
+ s = make<OutputSegment>(name, segments.size());
+ if (config->passiveSegments)
+ s->initFlags = WASM_SEGMENT_IS_PASSIVE;
+ segments.push_back(s);
}
- S->addInputSegment(Segment);
- LLVM_DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n");
+ s->addInputSegment(segment);
+ LLVM_DEBUG(dbgs() << "added data: " << name << ": " << s->size << "\n");
}
}
}
-static void createFunction(DefinedFunction *Func, StringRef BodyContent) {
- std::string FunctionBody;
+static void createFunction(DefinedFunction *func, StringRef bodyContent) {
+ std::string functionBody;
{
- raw_string_ostream OS(FunctionBody);
- writeUleb128(OS, BodyContent.size(), "function size");
- OS << BodyContent;
+ raw_string_ostream os(functionBody);
+ writeUleb128(os, bodyContent.size(), "function size");
+ os << bodyContent;
}
- ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
- cast<SyntheticFunction>(Func->Function)->setBody(Body);
+ ArrayRef<uint8_t> body = arrayRefFromStringRef(saver.save(functionBody));
+ cast<SyntheticFunction>(func->function)->setBody(body);
}
void Writer::createInitMemoryFunction() {
LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
- std::string BodyContent;
+ std::string bodyContent;
{
- raw_string_ostream OS(BodyContent);
- writeUleb128(OS, 0, "num locals");
+ raw_string_ostream os(bodyContent);
+ writeUleb128(os, 0, "num locals");
// initialize passive data segments
- for (const OutputSegment *S : Segments) {
- if (S->InitFlags & WASM_SEGMENT_IS_PASSIVE) {
+ for (const OutputSegment *s : segments) {
+ if (s->initFlags & WASM_SEGMENT_IS_PASSIVE) {
// destination address
- writeU8(OS, WASM_OPCODE_I32_CONST, "i32.const");
- writeUleb128(OS, S->StartVA, "destination address");
+ writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
+ writeUleb128(os, s->startVA, "destination address");
// source segment offset
- writeU8(OS, WASM_OPCODE_I32_CONST, "i32.const");
- writeUleb128(OS, 0, "segment offset");
+ writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
+ writeUleb128(os, 0, "segment offset");
// memory region size
- writeU8(OS, WASM_OPCODE_I32_CONST, "i32.const");
- writeUleb128(OS, S->Size, "memory region size");
+ writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
+ writeUleb128(os, s->size, "memory region size");
// memory.init instruction
- writeU8(OS, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
- writeUleb128(OS, WASM_OPCODE_MEMORY_INIT, "MEMORY.INIT");
- writeUleb128(OS, S->Index, "segment index immediate");
- writeU8(OS, 0, "memory index immediate");
+ writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
+ writeUleb128(os, WASM_OPCODE_MEMORY_INIT, "MEMORY.INIT");
+ writeUleb128(os, s->index, "segment index immediate");
+ writeU8(os, 0, "memory index immediate");
// data.drop instruction
- writeU8(OS, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
- writeUleb128(OS, WASM_OPCODE_DATA_DROP, "DATA.DROP");
- writeUleb128(OS, S->Index, "segment index immediate");
+ writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
+ writeUleb128(os, WASM_OPCODE_DATA_DROP, "DATA.DROP");
+ writeUleb128(os, s->index, "segment index immediate");
}
}
- writeU8(OS, WASM_OPCODE_END, "END");
+ writeU8(os, WASM_OPCODE_END, "END");
}
- createFunction(WasmSym::InitMemory, BodyContent);
+ createFunction(WasmSym::initMemory, bodyContent);
}
// For -shared (PIC) output, we create create a synthetic function which will
void Writer::createApplyRelocationsFunction() {
LLVM_DEBUG(dbgs() << "createApplyRelocationsFunction\n");
// First write the body's contents to a string.
- std::string BodyContent;
+ std::string bodyContent;
{
- raw_string_ostream OS(BodyContent);
- writeUleb128(OS, 0, "num locals");
- for (const OutputSegment *Seg : Segments)
- for (const InputSegment *InSeg : Seg->InputSegments)
- InSeg->generateRelocationCode(OS);
- writeU8(OS, WASM_OPCODE_END, "END");
+ raw_string_ostream os(bodyContent);
+ writeUleb128(os, 0, "num locals");
+ for (const OutputSegment *seg : segments)
+ for (const InputSegment *inSeg : seg->inputSegments)
+ inSeg->generateRelocationCode(os);
+ writeU8(os, WASM_OPCODE_END, "END");
}
- createFunction(WasmSym::ApplyRelocs, BodyContent);
+ createFunction(WasmSym::applyRelocs, bodyContent);
}
// Create synthetic "__wasm_call_ctors" function based on ctor functions
// in input object.
void Writer::createCallCtorsFunction() {
- if (!WasmSym::CallCtors->isLive())
+ if (!WasmSym::callCtors->isLive())
return;
// First write the body's contents to a string.
- std::string BodyContent;
+ std::string bodyContent;
{
- raw_string_ostream OS(BodyContent);
- writeUleb128(OS, 0, "num locals");
+ raw_string_ostream os(bodyContent);
+ writeUleb128(os, 0, "num locals");
- if (Config->PassiveSegments) {
- writeU8(OS, WASM_OPCODE_CALL, "CALL");
- writeUleb128(OS, WasmSym::InitMemory->getFunctionIndex(),
+ if (config->passiveSegments) {
+ writeU8(os, WASM_OPCODE_CALL, "CALL");
+ writeUleb128(os, WasmSym::initMemory->getFunctionIndex(),
"function index");
}
- if (Config->Pic) {
- writeU8(OS, WASM_OPCODE_CALL, "CALL");
- writeUleb128(OS, WasmSym::ApplyRelocs->getFunctionIndex(),
+ if (config->isPic) {
+ writeU8(os, WASM_OPCODE_CALL, "CALL");
+ writeUleb128(os, WasmSym::applyRelocs->getFunctionIndex(),
"function index");
}
// Call constructors
- for (const WasmInitEntry &F : InitFunctions) {
- writeU8(OS, WASM_OPCODE_CALL, "CALL");
- writeUleb128(OS, F.Sym->getFunctionIndex(), "function index");
+ for (const WasmInitEntry &f : initFunctions) {
+ writeU8(os, WASM_OPCODE_CALL, "CALL");
+ writeUleb128(os, f.sym->getFunctionIndex(), "function index");
}
- writeU8(OS, WASM_OPCODE_END, "END");
+ writeU8(os, WASM_OPCODE_END, "END");
}
- createFunction(WasmSym::CallCtors, BodyContent);
+ createFunction(WasmSym::callCtors, bodyContent);
}
// Populate InitFunctions vector with init functions from all input objects.
// This is then used either when creating the output linking section or to
// synthesize the "__wasm_call_ctors" function.
void Writer::calculateInitFunctions() {
- if (!Config->Relocatable && !WasmSym::CallCtors->isLive())
+ if (!config->relocatable && !WasmSym::callCtors->isLive())
return;
- for (ObjFile *File : Symtab->ObjectFiles) {
- const WasmLinkingData &L = File->getWasmObj()->linkingData();
- for (const WasmInitFunc &F : L.InitFunctions) {
- FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol);
+ for (ObjFile *file : symtab->objectFiles) {
+ const WasmLinkingData &l = file->getWasmObj()->linkingData();
+ for (const WasmInitFunc &f : l.InitFunctions) {
+ FunctionSymbol *sym = file->getFunctionSymbol(f.Symbol);
// comdat exclusions can cause init functions be discarded.
- if (Sym->isDiscarded())
+ if (sym->isDiscarded())
continue;
- assert(Sym->isLive());
- if (*Sym->Signature != WasmSignature{{}, {}})
- error("invalid signature for init func: " + toString(*Sym));
- InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority});
+ assert(sym->isLive());
+ if (*sym->signature != WasmSignature{{}, {}})
+ error("invalid signature for init func: " + toString(*sym));
+ initFunctions.emplace_back(WasmInitEntry{sym, f.Priority});
}
}
// Sort in order of priority (lowest first) so that they are called
// in the correct order.
- llvm::stable_sort(InitFunctions,
- [](const WasmInitEntry &L, const WasmInitEntry &R) {
- return L.Priority < R.Priority;
+ llvm::stable_sort(initFunctions,
+ [](const WasmInitEntry &l, const WasmInitEntry &r) {
+ return l.priority < r.priority;
});
}
void Writer::createSyntheticSections() {
- Out.DylinkSec = make<DylinkSection>();
- Out.TypeSec = make<TypeSection>();
- Out.ImportSec = make<ImportSection>();
- Out.FunctionSec = make<FunctionSection>();
- Out.TableSec = make<TableSection>();
- Out.MemorySec = make<MemorySection>();
- Out.GlobalSec = make<GlobalSection>();
- Out.EventSec = make<EventSection>();
- Out.ExportSec = make<ExportSection>();
- Out.ElemSec = make<ElemSection>(TableBase);
- Out.DataCountSec = make<DataCountSection>(Segments.size());
- Out.LinkingSec = make<LinkingSection>(InitFunctions, Segments);
- Out.NameSec = make<NameSection>();
- Out.ProducersSec = make<ProducersSection>();
- Out.TargetFeaturesSec = make<TargetFeaturesSection>();
+ out.dylinkSec = make<DylinkSection>();
+ out.typeSec = make<TypeSection>();
+ out.importSec = make<ImportSection>();
+ out.functionSec = make<FunctionSection>();
+ out.tableSec = make<TableSection>();
+ out.memorySec = make<MemorySection>();
+ out.globalSec = make<GlobalSection>();
+ out.eventSec = make<EventSection>();
+ out.exportSec = make<ExportSection>();
+ out.elemSec = make<ElemSection>(tableBase);
+ out.dataCountSec = make<DataCountSection>(segments.size());
+ out.linkingSec = make<LinkingSection>(initFunctions, segments);
+ out.nameSec = make<NameSection>();
+ out.producersSec = make<ProducersSection>();
+ out.targetFeaturesSec = make<TargetFeaturesSection>();
}
void Writer::run() {
- if (Config->Relocatable || Config->Pic)
- Config->GlobalBase = 0;
+ if (config->relocatable || config->isPic)
+ config->globalBase = 0;
// For PIC code the table base is assigned dynamically by the loader.
// For non-PIC, we start at 1 so that accessing table index 0 always traps.
- if (!Config->Pic)
- TableBase = 1;
+ if (!config->isPic)
+ tableBase = 1;
log("-- createOutputSegments");
createOutputSegments();
log("-- layoutMemory");
layoutMemory();
- if (!Config->Relocatable) {
+ if (!config->relocatable) {
// Create linker synthesized __start_SECNAME/__stop_SECNAME symbols
// This has to be done after memory layout is performed.
- for (const OutputSegment *Seg : Segments)
- addStartStopSymbols(Seg);
+ for (const OutputSegment *seg : segments)
+ addStartStopSymbols(seg);
}
log("-- scanRelocations");
log("-- calculateInitFunctions");
calculateInitFunctions();
- if (!Config->Relocatable) {
+ if (!config->relocatable) {
// Create linker synthesized functions
- if (Config->PassiveSegments)
+ if (config->passiveSegments)
createInitMemoryFunction();
- if (Config->Pic)
+ if (config->isPic)
createApplyRelocationsFunction();
createCallCtorsFunction();
}
log("-- addSections");
addSections();
- if (errorHandler().Verbose) {
- log("Defined Functions: " + Twine(Out.FunctionSec->InputFunctions.size()));
- log("Defined Globals : " + Twine(Out.GlobalSec->InputGlobals.size()));
- log("Defined Events : " + Twine(Out.EventSec->InputEvents.size()));
+ if (errorHandler().verbose) {
+ log("Defined Functions: " + Twine(out.functionSec->inputFunctions.size()));
+ log("Defined Globals : " + Twine(out.globalSec->inputGlobals.size()));
+ log("Defined Events : " + Twine(out.eventSec->inputEvents.size()));
log("Function Imports : " +
- Twine(Out.ImportSec->getNumImportedFunctions()));
- log("Global Imports : " + Twine(Out.ImportSec->getNumImportedGlobals()));
- log("Event Imports : " + Twine(Out.ImportSec->getNumImportedEvents()));
- for (ObjFile *File : Symtab->ObjectFiles)
- File->dumpInfo();
+ Twine(out.importSec->getNumImportedFunctions()));
+ log("Global Imports : " + Twine(out.importSec->getNumImportedGlobals()));
+ log("Event Imports : " + Twine(out.importSec->getNumImportedEvents()));
+ for (ObjFile *file : symtab->objectFiles)
+ file->dumpInfo();
}
createHeader();
if (errorCount())
return;
- if (Error E = Buffer->commit())
- fatal("failed to write the output file: " + toString(std::move(E)));
+ if (Error e = buffer->commit())
+ fatal("failed to write the output file: " + toString(std::move(e)));
}
// Open a result file.
void Writer::openFile() {
- log("writing: " + Config->OutputFile);
+ log("writing: " + config->outputFile);
- Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
- FileOutputBuffer::create(Config->OutputFile, FileSize,
+ Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
+ FileOutputBuffer::create(config->outputFile, fileSize,
FileOutputBuffer::F_executable);
- if (!BufferOrErr)
- error("failed to open " + Config->OutputFile + ": " +
- toString(BufferOrErr.takeError()));
+ if (!bufferOrErr)
+ error("failed to open " + config->outputFile + ": " +
+ toString(bufferOrErr.takeError()));
else
- Buffer = std::move(*BufferOrErr);
+ buffer = std::move(*bufferOrErr);
}
void Writer::createHeader() {
- raw_string_ostream OS(Header);
- writeBytes(OS, WasmMagic, sizeof(WasmMagic), "wasm magic");
- writeU32(OS, WasmVersion, "wasm version");
- OS.flush();
- FileSize += Header.size();
+ raw_string_ostream os(header);
+ writeBytes(os, WasmMagic, sizeof(WasmMagic), "wasm magic");
+ writeU32(os, WasmVersion, "wasm version");
+ os.flush();
+ fileSize += header.size();
}
void lld::wasm::writeResult() { Writer().run(); }
namespace lld {
-void wasm::debugWrite(uint64_t Offset, const Twine &Msg) {
- LLVM_DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n");
+void wasm::debugWrite(uint64_t offset, const Twine &msg) {
+ LLVM_DEBUG(dbgs() << format(" | %08lld: ", offset) << msg << "\n");
}
-void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
- debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]");
- encodeULEB128(Number, OS);
+void wasm::writeUleb128(raw_ostream &os, uint32_t number, const Twine &msg) {
+ debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]");
+ encodeULEB128(number, os);
}
-void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg) {
- debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]");
- encodeSLEB128(Number, OS);
+void wasm::writeSleb128(raw_ostream &os, int32_t number, const Twine &msg) {
+ debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]");
+ encodeSLEB128(number, os);
}
-void wasm::writeBytes(raw_ostream &OS, const char *Bytes, size_t Count,
- const Twine &Msg) {
- debugWrite(OS.tell(), Msg + " [data[" + Twine(Count) + "]]");
- OS.write(Bytes, Count);
+void wasm::writeBytes(raw_ostream &os, const char *bytes, size_t count,
+ const Twine &msg) {
+ debugWrite(os.tell(), msg + " [data[" + Twine(count) + "]]");
+ os.write(bytes, count);
}
-void wasm::writeStr(raw_ostream &OS, StringRef String, const Twine &Msg) {
- debugWrite(OS.tell(),
- Msg + " [str[" + Twine(String.size()) + "]: " + String + "]");
- encodeULEB128(String.size(), OS);
- OS.write(String.data(), String.size());
+void wasm::writeStr(raw_ostream &os, StringRef string, const Twine &msg) {
+ debugWrite(os.tell(),
+ msg + " [str[" + Twine(string.size()) + "]: " + string + "]");
+ encodeULEB128(string.size(), os);
+ os.write(string.data(), string.size());
}
-void wasm::writeU8(raw_ostream &OS, uint8_t Byte, const Twine &Msg) {
- debugWrite(OS.tell(), Msg + " [0x" + utohexstr(Byte) + "]");
- OS << Byte;
+void wasm::writeU8(raw_ostream &os, uint8_t byte, const Twine &msg) {
+ debugWrite(os.tell(), msg + " [0x" + utohexstr(byte) + "]");
+ os << byte;
}
-void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
- debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]");
- support::endian::write(OS, Number, support::little);
+void wasm::writeU32(raw_ostream &os, uint32_t number, const Twine &msg) {
+ debugWrite(os.tell(), msg + "[0x" + utohexstr(number) + "]");
+ support::endian::write(os, number, support::little);
}
-void wasm::writeValueType(raw_ostream &OS, ValType Type, const Twine &Msg) {
- writeU8(OS, static_cast<uint8_t>(Type),
- Msg + "[type: " + toString(Type) + "]");
+void wasm::writeValueType(raw_ostream &os, ValType type, const Twine &msg) {
+ writeU8(os, static_cast<uint8_t>(type),
+ msg + "[type: " + toString(type) + "]");
}
-void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) {
- writeU8(OS, WASM_TYPE_FUNC, "signature type");
- writeUleb128(OS, Sig.Params.size(), "param Count");
- for (ValType ParamType : Sig.Params) {
- writeValueType(OS, ParamType, "param type");
+void wasm::writeSig(raw_ostream &os, const WasmSignature &sig) {
+ writeU8(os, WASM_TYPE_FUNC, "signature type");
+ writeUleb128(os, sig.Params.size(), "param Count");
+ for (ValType paramType : sig.Params) {
+ writeValueType(os, paramType, "param type");
}
- writeUleb128(OS, Sig.Returns.size(), "result Count");
- if (Sig.Returns.size()) {
- writeValueType(OS, Sig.Returns[0], "result type");
+ writeUleb128(os, sig.Returns.size(), "result Count");
+ if (sig.Returns.size()) {
+ writeValueType(os, sig.Returns[0], "result type");
}
}
-void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) {
- writeU8(OS, InitExpr.Opcode, "opcode");
- switch (InitExpr.Opcode) {
+void wasm::writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) {
+ writeU8(os, initExpr.Opcode, "opcode");
+ switch (initExpr.Opcode) {
case WASM_OPCODE_I32_CONST:
- writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)");
+ writeSleb128(os, initExpr.Value.Int32, "literal (i32)");
break;
case WASM_OPCODE_I64_CONST:
- writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)");
+ writeSleb128(os, initExpr.Value.Int64, "literal (i64)");
break;
case WASM_OPCODE_GLOBAL_GET:
- writeUleb128(OS, InitExpr.Value.Global, "literal (global index)");
+ writeUleb128(os, initExpr.Value.Global, "literal (global index)");
break;
default:
- fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode));
+ fatal("unknown opcode in init expr: " + Twine(initExpr.Opcode));
}
- writeU8(OS, WASM_OPCODE_END, "opcode:end");
+ writeU8(os, WASM_OPCODE_END, "opcode:end");
}
-void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) {
- writeU8(OS, Limits.Flags, "limits flags");
- writeUleb128(OS, Limits.Initial, "limits initial");
- if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
- writeUleb128(OS, Limits.Maximum, "limits max");
+void wasm::writeLimits(raw_ostream &os, const WasmLimits &limits) {
+ writeU8(os, limits.Flags, "limits flags");
+ writeUleb128(os, limits.Initial, "limits initial");
+ if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
+ writeUleb128(os, limits.Maximum, "limits max");
}
-void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) {
+void wasm::writeGlobalType(raw_ostream &os, const WasmGlobalType &type) {
// TODO: Update WasmGlobalType to use ValType and remove this cast.
- writeValueType(OS, ValType(Type.Type), "global type");
- writeU8(OS, Type.Mutable, "global mutable");
+ writeValueType(os, ValType(type.Type), "global type");
+ writeU8(os, type.Mutable, "global mutable");
}
-void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
- writeGlobalType(OS, Global.Type);
- writeInitExpr(OS, Global.InitExpr);
+void wasm::writeGlobal(raw_ostream &os, const WasmGlobal &global) {
+ writeGlobalType(os, global.Type);
+ writeInitExpr(os, global.InitExpr);
}
-void wasm::writeEventType(raw_ostream &OS, const WasmEventType &Type) {
- writeUleb128(OS, Type.Attribute, "event attribute");
- writeUleb128(OS, Type.SigIndex, "sig index");
+void wasm::writeEventType(raw_ostream &os, const WasmEventType &type) {
+ writeUleb128(os, type.Attribute, "event attribute");
+ writeUleb128(os, type.SigIndex, "sig index");
}
-void wasm::writeEvent(raw_ostream &OS, const WasmEvent &Event) {
- writeEventType(OS, Event.Type);
+void wasm::writeEvent(raw_ostream &os, const WasmEvent &event) {
+ writeEventType(os, event.Type);
}
-void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) {
- writeU8(OS, WASM_TYPE_FUNCREF, "table type");
- writeLimits(OS, Type.Limits);
+void wasm::writeTableType(raw_ostream &os, const llvm::wasm::WasmTable &type) {
+ writeU8(os, WASM_TYPE_FUNCREF, "table type");
+ writeLimits(os, type.Limits);
}
-void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
- writeStr(OS, Import.Module, "import module name");
- writeStr(OS, Import.Field, "import field name");
- writeU8(OS, Import.Kind, "import kind");
- switch (Import.Kind) {
+void wasm::writeImport(raw_ostream &os, const WasmImport &import) {
+ writeStr(os, import.Module, "import module name");
+ writeStr(os, import.Field, "import field name");
+ writeU8(os, import.Kind, "import kind");
+ switch (import.Kind) {
case WASM_EXTERNAL_FUNCTION:
- writeUleb128(OS, Import.SigIndex, "import sig index");
+ writeUleb128(os, import.SigIndex, "import sig index");
break;
case WASM_EXTERNAL_GLOBAL:
- writeGlobalType(OS, Import.Global);
+ writeGlobalType(os, import.Global);
break;
case WASM_EXTERNAL_EVENT:
- writeEventType(OS, Import.Event);
+ writeEventType(os, import.Event);
break;
case WASM_EXTERNAL_MEMORY:
- writeLimits(OS, Import.Memory);
+ writeLimits(os, import.Memory);
break;
case WASM_EXTERNAL_TABLE:
- writeTableType(OS, Import.Table);
+ writeTableType(os, import.Table);
break;
default:
- fatal("unsupported import type: " + Twine(Import.Kind));
+ fatal("unsupported import type: " + Twine(import.Kind));
}
}
-void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) {
- writeStr(OS, Export.Name, "export name");
- writeU8(OS, Export.Kind, "export kind");
- switch (Export.Kind) {
+void wasm::writeExport(raw_ostream &os, const WasmExport &export_) {
+ writeStr(os, export_.Name, "export name");
+ writeU8(os, export_.Kind, "export kind");
+ switch (export_.Kind) {
case WASM_EXTERNAL_FUNCTION:
- writeUleb128(OS, Export.Index, "function index");
+ writeUleb128(os, export_.Index, "function index");
break;
case WASM_EXTERNAL_GLOBAL:
- writeUleb128(OS, Export.Index, "global index");
+ writeUleb128(os, export_.Index, "global index");
break;
case WASM_EXTERNAL_MEMORY:
- writeUleb128(OS, Export.Index, "memory index");
+ writeUleb128(os, export_.Index, "memory index");
break;
case WASM_EXTERNAL_TABLE:
- writeUleb128(OS, Export.Index, "table index");
+ writeUleb128(os, export_.Index, "table index");
break;
default:
- fatal("unsupported export type: " + Twine(Export.Kind));
+ fatal("unsupported export type: " + Twine(export_.Kind));
}
}
} // namespace lld
-std::string lld::toString(ValType Type) {
- switch (Type) {
+std::string lld::toString(ValType type) {
+ switch (type) {
case ValType::I32:
return "i32";
case ValType::I64:
llvm_unreachable("Invalid wasm::ValType");
}
-std::string lld::toString(const WasmSignature &Sig) {
- SmallString<128> S("(");
- for (ValType Type : Sig.Params) {
- if (S.size() != 1)
- S += ", ";
- S += toString(Type);
+std::string lld::toString(const WasmSignature &sig) {
+ SmallString<128> s("(");
+ for (ValType type : sig.Params) {
+ if (s.size() != 1)
+ s += ", ";
+ s += toString(type);
}
- S += ") -> ";
- if (Sig.Returns.empty())
- S += "void";
+ s += ") -> ";
+ if (sig.Returns.empty())
+ s += "void";
else
- S += toString(Sig.Returns[0]);
- return S.str();
+ s += toString(sig.Returns[0]);
+ return s.str();
}
-std::string lld::toString(const WasmGlobalType &Type) {
- return (Type.Mutable ? "var " : "const ") +
- toString(static_cast<ValType>(Type.Type));
+std::string lld::toString(const WasmGlobalType &type) {
+ return (type.Mutable ? "var " : "const ") +
+ toString(static_cast<ValType>(type.Type));
}
-std::string lld::toString(const WasmEventType &Type) {
- if (Type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION)
+std::string lld::toString(const WasmEventType &type) {
+ if (type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION)
return "exception";
return "unknown";
}
namespace lld {
namespace wasm {
-void debugWrite(uint64_t Offset, const Twine &Msg);
+void debugWrite(uint64_t offset, const Twine &msg);
-void writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg);
+void writeUleb128(raw_ostream &os, uint32_t number, const Twine &msg);
-void writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg);
+void writeSleb128(raw_ostream &os, int32_t number, const Twine &msg);
-void writeBytes(raw_ostream &OS, const char *Bytes, size_t count,
- const Twine &Msg);
+void writeBytes(raw_ostream &os, const char *bytes, size_t count,
+ const Twine &msg);
-void writeStr(raw_ostream &OS, StringRef String, const Twine &Msg);
+void writeStr(raw_ostream &os, StringRef string, const Twine &msg);
-void writeU8(raw_ostream &OS, uint8_t byte, const Twine &Msg);
+void writeU8(raw_ostream &os, uint8_t byte, const Twine &msg);
-void writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg);
+void writeU32(raw_ostream &os, uint32_t number, const Twine &msg);
-void writeValueType(raw_ostream &OS, llvm::wasm::ValType Type,
- const Twine &Msg);
+void writeValueType(raw_ostream &os, llvm::wasm::ValType type,
+ const Twine &msg);
-void writeSig(raw_ostream &OS, const llvm::wasm::WasmSignature &Sig);
+void writeSig(raw_ostream &os, const llvm::wasm::WasmSignature &sig);
-void writeInitExpr(raw_ostream &OS, const llvm::wasm::WasmInitExpr &InitExpr);
+void writeInitExpr(raw_ostream &os, const llvm::wasm::WasmInitExpr &initExpr);
-void writeLimits(raw_ostream &OS, const llvm::wasm::WasmLimits &Limits);
+void writeLimits(raw_ostream &os, const llvm::wasm::WasmLimits &limits);
-void writeGlobalType(raw_ostream &OS, const llvm::wasm::WasmGlobalType &Type);
+void writeGlobalType(raw_ostream &os, const llvm::wasm::WasmGlobalType &type);
-void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global);
+void writeGlobal(raw_ostream &os, const llvm::wasm::WasmGlobal &global);
-void writeEventType(raw_ostream &OS, const llvm::wasm::WasmEventType &Type);
+void writeEventType(raw_ostream &os, const llvm::wasm::WasmEventType &type);
-void writeEvent(raw_ostream &OS, const llvm::wasm::WasmEvent &Event);
+void writeEvent(raw_ostream &os, const llvm::wasm::WasmEvent &event);
-void writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type);
+void writeTableType(raw_ostream &os, const llvm::wasm::WasmTable &type);
-void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import);
+void writeImport(raw_ostream &os, const llvm::wasm::WasmImport &import);
-void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export);
+void writeExport(raw_ostream &os, const llvm::wasm::WasmExport &export_);
} // namespace wasm
-std::string toString(llvm::wasm::ValType Type);
-std::string toString(const llvm::wasm::WasmSignature &Sig);
-std::string toString(const llvm::wasm::WasmGlobalType &Type);
-std::string toString(const llvm::wasm::WasmEventType &Type);
+std::string toString(llvm::wasm::ValType type);
+std::string toString(const llvm::wasm::WasmSignature &sig);
+std::string toString(const llvm::wasm::WasmGlobalType &type);
+std::string toString(const llvm::wasm::WasmEventType &type);
} // namespace lld