/** * Output a TLS symbol for Mach-O. * * A TLS variable in the Mach-O format consists of two symbols. * One symbol for the data, which contains the initializer, if any. * The name of this symbol is the same as the variable, but with the * "$tlv$init" suffix. If the variable has an initializer it's placed in * the __thread_data section. Otherwise it's placed in the __thread_bss * section. * * The other symbol is for the TLV descriptor. The symbol has the same * name as the variable and is placed in the __thread_vars section. * A TLV descriptor has the following structure, where T is the type of * the variable: * * struct TLVDescriptor(T) * { * extern(C) T* function(TLVDescriptor*) thunk; * size_t key; * size_t offset; * } * * Input: * vd the variable declaration for the symbol * s the symbol to output */ void tlsToDt(VarDeclaration *vd, Symbol *s, DtBuilder& dtb) { assert(config.objfmt == OBJ_MACH && I64 && (s->ty() & mTYLINK) == mTYthread); Symbol *tlvInit = createTLVDataSymbol(vd, s); DtBuilder tlvInitDtb; if (vd->_init) initializerToDt(vd, tlvInitDtb); else Type_toDt(vd->type, &tlvInitDtb); tlvInit->Sdt = tlvInitDtb.finish(); outdata(tlvInit); if (I64) tlvInit->Sclass = SCextern; Symbol* tlvBootstrap = objmod->tlv_bootstrap(); dtb.xoff(tlvBootstrap, 0, TYnptr); dtb.size(0); dtb.xoff(tlvInit, 0, TYnptr); }
void visit(VarDeclaration *vd) { //printf("VarDeclaration::toObjFile(%p '%s' type=%s) protection %d\n", vd, vd->toChars(), vd->type->toChars(), vd->protection); //printf("\talign = %d\n", vd->alignment); if (vd->type->ty == Terror) { vd->error("had semantic errors when compiling"); return; } if (vd->aliassym) { visitNoMultiObj(vd->toAlias()); return; } // Do not store variables we cannot take the address of if (!vd->canTakeAddressOf()) { return; } if (!vd->isDataseg() || vd->storage_class & STCextern) return; Symbol *s = toSymbol(vd); unsigned sz = vd->type->size(); Dsymbol *parent = vd->toParent(); s->Sclass = SCglobal; do { /* Global template data members need to be in comdat's * in case multiple .obj files instantiate the same * template with the same types. */ if (parent->isTemplateInstance() && !parent->isTemplateMixin()) { s->Sclass = SCcomdat; break; } parent = parent->parent; } while (parent); s->Sfl = FLdata; if (vd->init) { s->Sdt = Initializer_toDt(vd->init); // Look for static array that is block initialized ExpInitializer *ie = vd->init->isExpInitializer(); Type *tb = vd->type->toBasetype(); if (tb->ty == Tsarray && ie && !tb->nextOf()->equals(ie->exp->type->toBasetype()->nextOf()) && ie->exp->implicitConvTo(tb->nextOf()) ) { size_t dim = ((TypeSArray *)tb)->dim->toInteger(); // Duplicate Sdt 'dim-1' times, as we already have the first one dt_t **pdt = &s->Sdt; while (--dim > 0) { pdt = Expression_toDt(ie->exp, pdt); } } } else { Type_toDt(vd->type, &s->Sdt); } dt_optimize(s->Sdt); // See if we can convert a comdat to a comdef, // which saves on exe file space. if (s->Sclass == SCcomdat && s->Sdt && dtallzeros(s->Sdt) && !vd->isThreadlocal()) { s->Sclass = SCglobal; dt2common(&s->Sdt); } if (!sz && vd->type->toBasetype()->ty != Tsarray) assert(0); // this shouldn't be possible if (sz || objmod->allowZeroSize()) { outdata(s); if (vd->isExport()) objmod->export_symbol(s, 0); } }
void visit(VarDeclaration *vd) { //printf("VarDeclaration::toObjFile(%p '%s' type=%s) protection %d\n", vd, vd->toChars(), vd->type->toChars(), vd->protection); //printf("\talign = %d\n", vd->alignment); if (vd->type->ty == Terror) { vd->error("had semantic errors when compiling"); return; } if (vd->aliassym) { visitNoMultiObj(vd->toAlias()); return; } // Do not store variables we cannot take the address of if (!vd->canTakeAddressOf()) { return; } if (!vd->isDataseg() || vd->storage_class & STCextern) return; Symbol *s = toSymbol(vd); d_uns64 sz64 = vd->type->size(vd->loc); if (sz64 == SIZE_INVALID) { vd->error("size overflow"); return; } if (sz64 >= 0x1000000) // there has to be some 'reasonable' limit on the size { vd->error("size of x%llx exceeds max allowed size 0x100_0000", sz64); } unsigned sz = (unsigned)sz64; Dsymbol *parent = vd->toParent(); s->Sclass = SCglobal; do { /* Global template data members need to be in comdat's * in case multiple .obj files instantiate the same * template with the same types. */ if (parent->isTemplateInstance() && !parent->isTemplateMixin()) { s->Sclass = SCcomdat; break; } parent = parent->parent; } while (parent); s->Sfl = FLdata; if (config.objfmt == OBJ_MACH && I64 && (s->ty() & mTYLINK) == mTYthread) { DtBuilder dtb; tlsToDt(vd, s, dtb); s->Sdt = dtb.finish(); } else if (vd->_init) { DtBuilder dtb; initializerToDt(vd, dtb); s->Sdt = dtb.finish(); } else { DtBuilder dtb; Type_toDt(vd->type, &dtb); s->Sdt = dtb.finish(); } // See if we can convert a comdat to a comdef, // which saves on exe file space. if (s->Sclass == SCcomdat && s->Sdt && dtallzeros(s->Sdt) && !vd->isThreadlocal()) { s->Sclass = SCglobal; dt2common(&s->Sdt); } if (!sz && vd->type->toBasetype()->ty != Tsarray) assert(0); // this shouldn't be possible if (sz || objmod->allowZeroSize()) { outdata(s); if (vd->isExport()) objmod->export_symbol(s, 0); } }