gcc/libphobos/libdruntime/rt/sections_win64.d

312 lines
8.1 KiB
D

/**
* Written in the D programming language.
* This module provides Win32-specific support for sections.
*
* Copyright: Copyright Digital Mars 2008 - 2012.
* License: Distributed under the
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Walter Bright, Sean Kelly, Martin Nowak
* Source: $(DRUNTIMESRC src/rt/_sections_win64.d)
*/
module rt.sections_win64;
version (CRuntime_Microsoft):
// debug = PRINTF;
debug(PRINTF) import core.stdc.stdio;
import core.stdc.stdlib : malloc, free;
import rt.deh, rt.minfo;
struct SectionGroup
{
static int opApply(scope int delegate(ref SectionGroup) dg)
{
return dg(_sections);
}
static int opApplyReverse(scope int delegate(ref SectionGroup) dg)
{
return dg(_sections);
}
@property immutable(ModuleInfo*)[] modules() const nothrow @nogc
{
return _moduleGroup.modules;
}
@property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc
{
return _moduleGroup;
}
version (Win64)
@property immutable(FuncTable)[] ehTables() const
{
auto pbeg = cast(immutable(FuncTable)*)&_deh_beg;
auto pend = cast(immutable(FuncTable)*)&_deh_end;
return pbeg[0 .. pend - pbeg];
}
@property inout(void[])[] gcRanges() inout nothrow @nogc
{
return _gcRanges[];
}
private:
ModuleGroup _moduleGroup;
void[][] _gcRanges;
}
shared(bool) conservative;
void initSections() nothrow @nogc
{
_sections._moduleGroup = ModuleGroup(getModuleInfos());
// the ".data" image section includes both object file sections ".data" and ".bss"
void[] dataSection = findImageSection(".data");
debug(PRINTF) printf("found .data section: [%p,+%llx]\n", dataSection.ptr,
cast(ulong)dataSection.length);
import rt.sections;
conservative = !scanDataSegPrecisely();
if (conservative)
{
_sections._gcRanges = (cast(void[]*) malloc((void[]).sizeof))[0..1];
_sections._gcRanges[0] = dataSection;
}
else
{
size_t count = &_DP_end - &_DP_beg;
auto ranges = cast(void[]*) malloc(count * (void[]).sizeof);
size_t r = 0;
void* prev = null;
for (size_t i = 0; i < count; i++)
{
auto off = (&_DP_beg)[i];
if (off == 0) // skip zero entries added by incremental linking
continue; // assumes there is no D-pointer at the very beginning of .data
void* addr = dataSection.ptr + off;
debug(PRINTF) printf(" scan %p\n", addr);
// combine consecutive pointers into single range
if (prev + (void*).sizeof == addr)
ranges[r-1] = ranges[r-1].ptr[0 .. ranges[r-1].length + (void*).sizeof];
else
ranges[r++] = (cast(void**)addr)[0..1];
prev = addr;
}
_sections._gcRanges = ranges[0..r];
}
}
void finiSections() nothrow @nogc
{
.free(cast(void*)_sections.modules.ptr);
.free(_sections._gcRanges.ptr);
}
void[] initTLSRanges() nothrow @nogc
{
void* pbeg;
void* pend;
// with VS2017 15.3.1, the linker no longer puts TLS segments into a
// separate image section. That way _tls_start and _tls_end no
// longer generate offsets into .tls, but DATA.
// Use the TEB entry to find the start of TLS instead and read the
// length from the TLS directory
version (D_InlineAsm_X86)
{
asm @nogc nothrow
{
mov EAX, _tls_index;
mov ECX, FS:[0x2C]; // _tls_array
mov EAX, [ECX+4*EAX];
mov pbeg, EAX;
add EAX, [_tls_used+4]; // end
sub EAX, [_tls_used+0]; // start
mov pend, EAX;
}
}
else version (D_InlineAsm_X86_64)
{
asm @nogc nothrow
{
xor RAX, RAX;
mov EAX, _tls_index;
mov RCX, 0x58;
mov RCX, GS:[RCX]; // _tls_array (immediate value causes fixup)
mov RAX, [RCX+8*RAX];
mov pbeg, RAX;
add RAX, [_tls_used+8]; // end
sub RAX, [_tls_used+0]; // start
mov pend, RAX;
}
}
else
static assert(false, "Architecture not supported.");
return pbeg[0 .. pend - pbeg];
}
void finiTLSRanges(void[] rng) nothrow @nogc
{
}
void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
{
if (conservative)
{
dg(rng.ptr, rng.ptr + rng.length);
}
else
{
for (auto p = &_TP_beg; p < &_TP_end; )
{
uint beg = *p++;
uint end = beg + cast(uint)((void*).sizeof);
while (p < &_TP_end && *p == end)
{
end += (void*).sizeof;
p++;
}
dg(rng.ptr + beg, rng.ptr + end);
}
}
}
private:
__gshared SectionGroup _sections;
extern(C)
{
extern __gshared void* _minfo_beg;
extern __gshared void* _minfo_end;
}
immutable(ModuleInfo*)[] getModuleInfos() nothrow @nogc
out (result)
{
foreach (m; result)
assert(m !is null);
}
body
{
auto m = (cast(immutable(ModuleInfo*)*)&_minfo_beg)[1 .. &_minfo_end - &_minfo_beg];
/* Because of alignment inserted by the linker, various null pointers
* are there. We need to filter them out.
*/
auto p = m.ptr;
auto pend = m.ptr + m.length;
// count non-null pointers
size_t cnt;
for (; p < pend; ++p)
{
if (*p !is null) ++cnt;
}
auto result = (cast(immutable(ModuleInfo)**).malloc(cnt * size_t.sizeof))[0 .. cnt];
p = m.ptr;
cnt = 0;
for (; p < pend; ++p)
if (*p !is null) result[cnt++] = *p;
return cast(immutable)result;
}
extern(C)
{
/* Symbols created by the compiler/linker and inserted into the
* object file that 'bracket' sections.
*/
extern __gshared
{
void* __ImageBase;
void* _deh_beg;
void* _deh_end;
uint _DP_beg;
uint _DP_end;
uint _TP_beg;
uint _TP_end;
void*[2] _tls_used; // start, end
int _tls_index;
}
}
/////////////////////////////////////////////////////////////////////
enum IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ
struct IMAGE_DOS_HEADER // DOS .EXE header
{
ushort e_magic; // Magic number
ushort[29] e_res2; // Reserved ushorts
int e_lfanew; // File address of new exe header
}
struct IMAGE_FILE_HEADER
{
ushort Machine;
ushort NumberOfSections;
uint TimeDateStamp;
uint PointerToSymbolTable;
uint NumberOfSymbols;
ushort SizeOfOptionalHeader;
ushort Characteristics;
}
struct IMAGE_NT_HEADERS
{
uint Signature;
IMAGE_FILE_HEADER FileHeader;
// optional header follows
}
struct IMAGE_SECTION_HEADER
{
char[8] Name;
union {
uint PhysicalAddress;
uint VirtualSize;
}
uint VirtualAddress;
uint SizeOfRawData;
uint PointerToRawData;
uint PointerToRelocations;
uint PointerToLinenumbers;
ushort NumberOfRelocations;
ushort NumberOfLinenumbers;
uint Characteristics;
}
bool compareSectionName(ref IMAGE_SECTION_HEADER section, string name) nothrow @nogc
{
if (name[] != section.Name[0 .. name.length])
return false;
return name.length == 8 || section.Name[name.length] == 0;
}
void[] findImageSection(string name) nothrow @nogc
{
if (name.length > 8) // section name from string table not supported
return null;
IMAGE_DOS_HEADER* doshdr = cast(IMAGE_DOS_HEADER*) &__ImageBase;
if (doshdr.e_magic != IMAGE_DOS_SIGNATURE)
return null;
auto nthdr = cast(IMAGE_NT_HEADERS*)(cast(void*)doshdr + doshdr.e_lfanew);
auto sections = cast(IMAGE_SECTION_HEADER*)(cast(void*)nthdr + IMAGE_NT_HEADERS.sizeof + nthdr.FileHeader.SizeOfOptionalHeader);
for (ushort i = 0; i < nthdr.FileHeader.NumberOfSections; i++)
if (compareSectionName (sections[i], name))
return (cast(void*)&__ImageBase + sections[i].VirtualAddress)[0 .. sections[i].VirtualSize];
return null;
}