Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save nahuakang/47a016129ad6a37748f13146827f587b to your computer and use it in GitHub Desktop.
Save nahuakang/47a016129ad6a37748f13146827f587b to your computer and use it in GitHub Desktop.
// Failed experiment for a hotreload system. Instead of passing a big global struct pointer, try copying DLL global data sections.
copy_dll_data_sections :: proc(
dst: windows.HMODULE,
src: windows.HMODULE,
) -> bool {
dst_header := get_dll_nt_header(dst) or_return
src_header := get_dll_nt_header(src) or_return
dst_sections := cast([^]windows_IMAGE_SECTION_HEADER)windows_image_first_section(dst_header)
src_sections := cast([^]windows_IMAGE_SECTION_HEADER)windows_image_first_section(src_header)
for dst_section_index in 0..<dst_header.FileHeader.NumberOfSections {
dst_section := dst_sections[dst_section_index]
dst_addr := rawptr(uintptr(dst) + uintptr(dst_section.VirtualAddress))
fmt.printfln("[%i] %8s:\taddr: %8p, data_ptr: %8p, data_size: %8i bytes (%M)",
dst_section_index,
transmute(string)dst_section.Name[:],
dst_addr,
rawptr(uintptr(dst_section.PointerToRawData)),
dst_section.SizeOfRawData,
dst_section.SizeOfRawData,
)
name := transmute(string)dst_section.Name[:]
// Section name whitelist
// Can use `@(link_section=".hotrel")`
switch dst_section.Name {
case
// {'.', 'b', 's', 's', 0, 0, 0, 0},
// {'.', 'd', 'a', 't', 'a', 0, 0, 0}:
{'.', 'h', 'o', 't', 'r', 'e', 'l', 0}:
for src_section_index in 0..<src_header.FileHeader.NumberOfSections {
src_section := src_sections[src_section_index]
if src_section.Name != dst_section.Name {
continue
}
// Found valid section, now make sure it's valid
// Note: the sizes can vary by few bytes due to alignment
size := min(src_section.Misc.VirtualSize, dst_section.Misc.VirtualSize)
fmt.println("Src size:", src_section.Misc.VirtualSize)
fmt.println("Dst size:", dst_section.Misc.VirtualSize)
// Arbitrary threshold
if abs(int(src_section.Misc.VirtualSize) - int(dst_section.Misc.VirtualSize)) > 64 {
fmt.printfln("Error: section {} size doesn't match", name)
return false
}
fmt.printfln("Copying data of size %i bytes (%M) to address %p",
size, size,
dst_addr,
)
// Note: assume the memory pages are accessible for a DLL like ours...
runtime.mem_copy_non_overlapping(
dst = dst_addr,
src = rawptr(uintptr(src) + uintptr(src_section.VirtualAddress)),
len = int(size),
)
break
}
}
}
return true
}
get_dll_nt_header :: proc(lib: windows.HMODULE) -> (^windows.IMAGE_NT_HEADERS64, bool) {
dos_header := cast(^windows.IMAGE_DOS_HEADER)lib
if dos_header.e_magic != windows_IMAGE_DOS_SIGNATURE {
fmt.println("Not a DOS Header")
return nil, false
}
nt_header := cast(^windows.IMAGE_NT_HEADERS64)(uintptr(lib) + uintptr(dos_header.e_lfanew))
if nt_header.Signature != windows_IMAGE_NT_SIGNATURE {
fmt.println("No NT Signature")
return nil, false
}
return nt_header, true
}
// Win32 shit
windows_IMAGE_DOS_SIGNATURE :: 0x5A4D // MZ
windows_IMAGE_OS2_SIGNATURE :: 0x454E // NE
windows_IMAGE_OS2_SIGNATURE_LE :: 0x454C // LE
windows_IMAGE_VXD_SIGNATURE :: 0x454C // LE
windows_IMAGE_NT_SIGNATURE :: 0x00004550 // PE00
windows_image_first_section :: proc(ntheader: ^windows.IMAGE_NT_HEADERS64) -> ^windows_IMAGE_SECTION_HEADER {
return cast(^windows_IMAGE_SECTION_HEADER)(
uintptr(ntheader) +
offset_of(windows.IMAGE_NT_HEADERS64, OptionalHeader) +
uintptr(ntheader.FileHeader.SizeOfOptionalHeader))
}
windows_IMAGE_SIZEOF_SHORT_NAME :: 8
windows_IMAGE_SECTION_HEADER :: struct {
Name: [windows_IMAGE_SIZEOF_SHORT_NAME]windows.BYTE,
Misc: struct #raw_union {
PhysicalAddress: windows.DWORD,
VirtualSize: windows.DWORD,
},
VirtualAddress: windows.DWORD,
SizeOfRawData: windows.DWORD,
PointerToRawData: windows.DWORD,
PointerToRelocations: windows.DWORD,
PointerToLinenumbers: windows.DWORD,
NumberOfRelocations: windows.WORD,
NumberOfLinenumbers: windows.WORD,
Characteristics: windows.DWORD,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment