static void do_relocations( unsigned int load_addr, IMAGE_BASE_RELOCATION *r ) { int delta = load_addr - PE_HEADER(load_addr)->OptionalHeader.ImageBase; int hdelta = (delta >> 16) & 0xFFFF; int ldelta = delta & 0xFFFF; if(delta == 0) return; while(r->VirtualAddress) { char *page = (char*) RVA(r->VirtualAddress); int count = (r->SizeOfBlock - 8)/2; int i; TRACE_(fixup)("%x relocations for page %lx\n", count, r->VirtualAddress); for(i=0;i<count;i++) { int offset = r->TypeOffset[i] & 0xFFF; int type = r->TypeOffset[i] >> 12; // TRACE_(fixup)("patching %x type %x\n", offset, type); switch(type) { case IMAGE_REL_BASED_ABSOLUTE: break; case IMAGE_REL_BASED_HIGH: *(short*)(page+offset) += hdelta; break; case IMAGE_REL_BASED_LOW: *(short*)(page+offset) += ldelta; break; case IMAGE_REL_BASED_HIGHLOW: *(int*)(page+offset) += delta; break; case IMAGE_REL_BASED_HIGHADJ: FIXME("Don't know what to do with IMAGE_REL_BASED_HIGHADJ\n"); break; case IMAGE_REL_BASED_MIPS_JMPADDR: FIXME("Is this a MIPS machine ???\n"); break; default: FIXME("Unknown fixup type\n"); break; } } r = (IMAGE_BASE_RELOCATION*)((char*)r + r->SizeOfBlock); } }
/********************************************************************** * get_data_file_ptr * * Get a pointer to a given offset in a file mapped as data file. */ static const void *get_data_file_ptr( const void *base, DWORD offset ) { const IMAGE_NT_HEADERS *nt = PE_HEADER(base); const IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + nt->FileHeader.SizeOfOptionalHeader); int i; /* find the section containing the virtual address */ for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) { if ((sec->VirtualAddress <= offset) && (sec->VirtualAddress + sec->SizeOfRawData > offset)) return (char *)base + sec->PointerToRawData + (offset - sec->VirtualAddress); } return NULL; }
/********************************************************************** * get_resdir * * Get the resource directory of a PE module */ static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod ) { const IMAGE_DATA_DIRECTORY *dir; const IMAGE_RESOURCE_DIRECTORY *ret = NULL; const void *base = get_module_base( hmod ); if (base) { dir = &PE_HEADER(base)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]; if (dir->Size && dir->VirtualAddress) { if (is_data_file_module(hmod)) ret = get_data_file_ptr( base, dir->VirtualAddress ); else ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)base + dir->VirtualAddress); } } return ret; }
/********************************************************************** * PE_CreateModule * * Create WINE_MODREF structure for loaded HMODULE32, link it into * process modref_list, and fixup all imports. * * Note: hModule must point to a correctly allocated PE image, * with base relocations applied; the 16-bit dummy module * associated to hModule must already exist. * * Note: This routine must always be called in the context of the * process that is to own the module to be created. */ WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags, WIN_BOOL builtin ) { DWORD load_addr = (DWORD)hModule; IMAGE_NT_HEADERS *nt = PE_HEADER(hModule); IMAGE_DATA_DIRECTORY *dir; IMAGE_IMPORT_DESCRIPTOR *pe_import = NULL; IMAGE_EXPORT_DIRECTORY *pe_export = NULL; IMAGE_RESOURCE_DIRECTORY *pe_resource = NULL; WINE_MODREF *wm; dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXPORT; if (dir->Size) pe_export = (PIMAGE_EXPORT_DIRECTORY)RVA(dir->VirtualAddress); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IMPORT; if (dir->Size) pe_import = (PIMAGE_IMPORT_DESCRIPTOR)RVA(dir->VirtualAddress); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_RESOURCE; if (dir->Size) pe_resource = (PIMAGE_RESOURCE_DIRECTORY)RVA(dir->VirtualAddress); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXCEPTION; if (dir->Size) FIXME("Exception directory ignored\n" ); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_SECURITY; if (dir->Size) FIXME("Security directory ignored\n" ); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_DEBUG; if (dir->Size) TRACE("Debug directory ignored\n" ); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_COPYRIGHT; if (dir->Size) FIXME("Copyright string ignored\n" ); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_GLOBALPTR; if (dir->Size) FIXME("Global Pointer (MIPS) ignored\n" ); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG; if (dir->Size) FIXME("Load Configuration directory ignored\n" ); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT; if (dir->Size) TRACE("Bound Import directory ignored\n" ); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IAT; if (dir->Size) TRACE("Import Address Table directory ignored\n" ); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT; if (dir->Size) { TRACE("Delayed import, stub calls LoadLibrary\n" ); /* * Nothing to do here. */ #ifdef ImgDelayDescr /* * This code is useful to observe what the heck is going on. */ { ImgDelayDescr *pe_delay = NULL; pe_delay = (PImgDelayDescr)RVA(dir->VirtualAddress); TRACE_(delayhlp)("pe_delay->grAttrs = %08x\n", pe_delay->grAttrs); TRACE_(delayhlp)("pe_delay->szName = %s\n", pe_delay->szName); TRACE_(delayhlp)("pe_delay->phmod = %08x\n", pe_delay->phmod); TRACE_(delayhlp)("pe_delay->pIAT = %08x\n", pe_delay->pIAT); TRACE_(delayhlp)("pe_delay->pINT = %08x\n", pe_delay->pINT); TRACE_(delayhlp)("pe_delay->pBoundIAT = %08x\n", pe_delay->pBoundIAT); TRACE_(delayhlp)("pe_delay->pUnloadIAT = %08x\n", pe_delay->pUnloadIAT); TRACE_(delayhlp)("pe_delay->dwTimeStamp = %08x\n", pe_delay->dwTimeStamp); } #endif } dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR; if (dir->Size) FIXME("Unknown directory 14 ignored\n" ); dir = nt->OptionalHeader.DataDirectory+15; if (dir->Size) FIXME("Unknown directory 15 ignored\n" ); wm = (WINE_MODREF *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ); wm->module = hModule; if ( builtin ) wm->flags |= WINE_MODREF_INTERNAL; if ( flags & DONT_RESOLVE_DLL_REFERENCES ) wm->flags |= WINE_MODREF_DONT_RESOLVE_REFS; if ( flags & LOAD_LIBRARY_AS_DATAFILE ) wm->flags |= WINE_MODREF_LOAD_AS_DATAFILE; wm->type = MODULE32_PE; wm->binfmt.pe.pe_export = pe_export; wm->binfmt.pe.pe_import = pe_import; wm->binfmt.pe.pe_resource = pe_resource; wm->binfmt.pe.tlsindex = -1; wm->filename = malloc(strlen(filename)+1); strcpy(wm->filename, filename ); wm->modname = strrchr( wm->filename, '\\' ); if (!wm->modname) wm->modname = wm->filename; else wm->modname++; if ( pe_export ) dump_exports( hModule ); /* Fixup Imports */ if ( pe_import && !( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE ) && !( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS ) && fixup_imports( wm ) ) { /* remove entry from modref chain */ return NULL; } return wm; }
/********************************************************************** * PE_LoadImage * Load one PE format DLL/EXE into memory * * Unluckily we can't just mmap the sections where we want them, for * (at least) Linux does only support offsets which are page-aligned. * * BUT we have to map the whole image anyway, for Win32 programs sometimes * want to access them. (HMODULE32 point to the start of it) */ HMODULE PE_LoadImage( int handle, LPCSTR filename, WORD *version ) { HMODULE hModule; HANDLE mapping; IMAGE_NT_HEADERS *nt; IMAGE_SECTION_HEADER *pe_sec; IMAGE_DATA_DIRECTORY *dir; // BY_HANDLE_FILE_INFORMATION bhfi; int i, rawsize, lowest_va, vma_size, file_size = 0; DWORD load_addr = 0, aoep, reloc = 0; // struct get_read_fd_request *req = get_req_buffer(); int unix_handle = handle; int page_size = getpagesize(); // if ( GetFileInformationByHandle( hFile, &bhfi ) ) // file_size = bhfi.nFileSizeLow; file_size=lseek(handle, 0, SEEK_END); lseek(handle, 0, SEEK_SET); // fix CreateFileMappingA mapping = CreateFileMappingA( handle, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL ); if (!mapping) { WARN("CreateFileMapping error %ld\n", GetLastError() ); return 0; } // hModule = (HMODULE)MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); hModule=(HMODULE)mapping; // CloseHandle( mapping ); if (!hModule) { WARN("MapViewOfFile error %ld\n", GetLastError() ); return 0; } if ( *(WORD*)hModule !=IMAGE_DOS_SIGNATURE) { WARN("%s image doesn't have DOS signature, but 0x%04x\n", filename,*(WORD*)hModule); goto error; } nt = PE_HEADER( hModule ); if ( nt->Signature != IMAGE_NT_SIGNATURE ) { WARN("%s image doesn't have PE signature, but 0x%08lx\n", filename, nt->Signature ); goto error; } if ( nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386 ) { dbg_printf("Trying to load PE image for unsupported architecture ("); switch (nt->FileHeader.Machine) { case IMAGE_FILE_MACHINE_UNKNOWN: dbg_printf("Unknown"); break; case IMAGE_FILE_MACHINE_I860: dbg_printf("I860"); break; case IMAGE_FILE_MACHINE_R3000: dbg_printf("R3000"); break; case IMAGE_FILE_MACHINE_R4000: dbg_printf("R4000"); break; case IMAGE_FILE_MACHINE_R10000: dbg_printf("R10000"); break; case IMAGE_FILE_MACHINE_ALPHA: dbg_printf("Alpha"); break; case IMAGE_FILE_MACHINE_POWERPC: dbg_printf("PowerPC"); break; default: dbg_printf("Unknown-%04x", nt->FileHeader.Machine); break; } dbg_printf(")\n"); goto error; } pe_sec = PE_SECTIONS( hModule ); rawsize = 0; lowest_va = 0x10000; for (i = 0; i < nt->FileHeader.NumberOfSections; i++) { if (lowest_va > pe_sec[i].VirtualAddress) lowest_va = pe_sec[i].VirtualAddress; if (pe_sec[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue; if (pe_sec[i].PointerToRawData+pe_sec[i].SizeOfRawData > rawsize) rawsize = pe_sec[i].PointerToRawData+pe_sec[i].SizeOfRawData; } if ( file_size && file_size < rawsize ) { ERR("PE module is too small (header: %d, filesize: %d), " "probably truncated download?\n", rawsize, file_size ); goto error; } aoep = nt->OptionalHeader.AddressOfEntryPoint; if (aoep && (aoep < lowest_va)) FIXME("VIRUS WARNING: '%s' has an invalid entrypoint (0x%08lx) " "below the first virtual address (0x%08x) " "(possibly infected by Tchernobyl/SpaceFiller virus)!\n", filename, aoep, lowest_va ); /* FIXME: Hack! While we don't really support shared sections yet, * this checks for those special cases where the whole DLL * consists only of shared sections and is mapped into the * shared address space > 2GB. In this case, we assume that * the module got mapped at its base address. Thus we simply * check whether the module has actually been mapped there * and use it, if so. This is needed to get Win95 USER32.DLL * to work (until we support shared sections properly). */ if ( nt->OptionalHeader.ImageBase & 0x80000000 && !strstr(filename, "xanlib.dll")) { HMODULE sharedMod = (HMODULE)nt->OptionalHeader.ImageBase; IMAGE_NT_HEADERS *sharedNt = (PIMAGE_NT_HEADERS) ( (LPBYTE)sharedMod + ((LPBYTE)nt - (LPBYTE)hModule) ); /* Well, this check is not really comprehensive, but should be good enough for now ... */ if ( !IsBadReadPtr( (LPBYTE)sharedMod, sizeof(IMAGE_DOS_HEADER) ) && memcmp( (LPBYTE)sharedMod, (LPBYTE)hModule, sizeof(IMAGE_DOS_HEADER) ) == 0 && !IsBadReadPtr( sharedNt, sizeof(IMAGE_NT_HEADERS) ) && memcmp( sharedNt, nt, sizeof(IMAGE_NT_HEADERS) ) == 0 ) { UnmapViewOfFile( (LPVOID)hModule ); return sharedMod; } } load_addr = nt->OptionalHeader.ImageBase; vma_size = calc_vma_size( hModule ); load_addr = (DWORD)VirtualAlloc( (void*)load_addr, vma_size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if (load_addr == 0) { FIXME("We need to perform base relocations for %s\n", filename); dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BASERELOC; if (dir->Size) reloc = dir->VirtualAddress; else { FIXME( "FATAL: Need to relocate %s, but no relocation records present (%s). Try to run that file directly !\n", filename, (nt->FileHeader.Characteristics&IMAGE_FILE_RELOCS_STRIPPED)? "stripped during link" : "unknown reason" ); goto error; } /* FIXME: If we need to relocate a system DLL (base > 2GB) we should * really make sure that the *new* base address is also > 2GB. * Some DLLs really check the MSB of the module handle :-/ */ if ( nt->OptionalHeader.ImageBase & 0x80000000 ) ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" ); load_addr = (DWORD)VirtualAlloc( NULL, vma_size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if (!load_addr) { FIXME_(win32)( "FATAL: Couldn't load module %s (out of memory, %d needed)!\n", filename, vma_size); goto error; } } TRACE("Load addr is %lx (base %lx), range %x\n", load_addr, nt->OptionalHeader.ImageBase, vma_size ); TRACE_(segment)("Loading %s at %lx, range %x\n", filename, load_addr, vma_size ); #if 0 *(PIMAGE_DOS_HEADER)load_addr = *(PIMAGE_DOS_HEADER)hModule; *PE_HEADER( load_addr ) = *nt; memcpy( PE_SECTIONS(load_addr), PE_SECTIONS(hModule), sizeof(IMAGE_SECTION_HEADER) * nt->FileHeader.NumberOfSections ); memcpy( load_addr, hModule, lowest_fa ); #endif if ((void*)FILE_dommap( handle, (void *)load_addr, 0, nt->OptionalHeader.SizeOfHeaders, 0, 0, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_FIXED ) != (void*)load_addr) { ERR_(win32)( "Critical Error: failed to map PE header to necessary address.\n"); goto error; } pe_sec = PE_SECTIONS( hModule ); for (i = 0; i < nt->FileHeader.NumberOfSections; i++, pe_sec++) { if (!pe_sec->SizeOfRawData || !pe_sec->PointerToRawData) continue; TRACE("%s: mmaping section %s at %p off %lx size %lx/%lx\n", filename, pe_sec->Name, (void*)RVA(pe_sec->VirtualAddress), pe_sec->PointerToRawData, pe_sec->SizeOfRawData, pe_sec->Misc.VirtualSize ); if ((void*)FILE_dommap( unix_handle, (void*)RVA(pe_sec->VirtualAddress), 0, pe_sec->SizeOfRawData, 0, pe_sec->PointerToRawData, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_FIXED ) != (void*)RVA(pe_sec->VirtualAddress)) { ERR_(win32)( "Critical Error: failed to map PE section to necessary address.\n"); goto error; } if ((pe_sec->SizeOfRawData < pe_sec->Misc.VirtualSize) && (pe_sec->SizeOfRawData & (page_size-1))) { DWORD end = (pe_sec->SizeOfRawData & ~(page_size-1)) + page_size; if (end > pe_sec->Misc.VirtualSize) end = pe_sec->Misc.VirtualSize; TRACE("clearing %p - %p\n", RVA(pe_sec->VirtualAddress) + pe_sec->SizeOfRawData, RVA(pe_sec->VirtualAddress) + end ); memset( (char*)RVA(pe_sec->VirtualAddress) + pe_sec->SizeOfRawData, 0, end - pe_sec->SizeOfRawData ); } } if ( reloc ) do_relocations( load_addr, (IMAGE_BASE_RELOCATION *)RVA(reloc) ); *version = ( (nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) | (nt->OptionalHeader.MinorSubsystemVersion & 0xff); UnmapViewOfFile( (LPVOID)hModule ); return (HMODULE)load_addr; error: if (unix_handle != -1) close( unix_handle ); if (load_addr) VirtualFree( (LPVOID)load_addr, 0, MEM_RELEASE ); UnmapViewOfFile( (LPVOID)hModule ); return 0; }
/* Look up the specified function or ordinal in the exportlist: * If it is a string: * - look up the name in the Name list. * - look up the ordinal with that index. * - use the ordinal as offset into the functionlist * If it is a ordinal: * - use ordinal-pe_export->Base as offset into the functionlist */ FARPROC PE_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName, WIN_BOOL snoop ) { unsigned short * ordinals; unsigned long * function; unsigned char ** name; const char *ename = NULL; int i, ordinal; PE_MODREF *pem = &(wm->binfmt.pe); IMAGE_EXPORT_DIRECTORY *exports = pem->pe_export; unsigned int load_addr = wm->module; unsigned long rva_start, rva_end, addr; char * forward; if (HIWORD(funcName)) TRACE("(%s)\n",funcName); else TRACE("(%d)\n",(int)funcName); if (!exports) { /* Not a fatal problem, some apps do * GetProcAddress(0,"RegisterPenApp") which triggers this * case. */ WARN("Module %08x(%s)/MODREF %p doesn't have a exports table.\n",wm->module,wm->modname,pem); return NULL; } ordinals= (unsigned short*) RVA(exports->AddressOfNameOrdinals); function= (unsigned long*) RVA(exports->AddressOfFunctions); name = (unsigned char **) RVA(exports->AddressOfNames); forward = NULL; rva_start = PE_HEADER(wm->module)->OptionalHeader .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; rva_end = rva_start + PE_HEADER(wm->module)->OptionalHeader .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; if (HIWORD(funcName)) { int min = 0, max = exports->NumberOfNames - 1; while (min <= max) { int res, pos = (min + max) / 2; ename = (const char*) RVA(name[pos]); if (!(res = strcmp( ename, funcName ))) { ordinal = ordinals[pos]; goto found; } if (res > 0) max = pos - 1; else min = pos + 1; } for (i = 0; i < exports->NumberOfNames; i++) { ename = (const char*) RVA(name[i]); if (!strcmp( ename, funcName )) { ERR( "%s.%s required a linear search\n", wm->modname, funcName ); ordinal = ordinals[i]; goto found; } } return NULL; } else { ordinal = LOWORD(funcName) - exports->Base; if (snoop && name) { for (i = 0; i < exports->NumberOfNames; i++) if (ordinals[i] == ordinal) { ename = RVA(name[i]); break; } } } found: if (ordinal >= exports->NumberOfFunctions) { TRACE(" ordinal %ld out of range!\n", ordinal + exports->Base ); return NULL; } addr = function[ordinal]; if (!addr) return NULL; if ((addr < rva_start) || (addr >= rva_end)) { FARPROC proc = RVA(addr); if (snoop) { if (!ename) ename = "@"; // proc = SNOOP_GetProcAddress(wm->module,ename,ordinal,proc); TRACE("SNOOP_GetProcAddress n/a\n"); } return proc; } else { WINE_MODREF *wm; char *forward = RVA(addr); char module[256]; char *end = strchr(forward, '.'); if (!end) return NULL; if (end - forward >= sizeof(module)) return NULL; memcpy( module, forward, end - forward ); module[end-forward] = 0; if (!(wm = MODULE_FindModule( module ))) { ERR("module not found for forward '%s'\n", forward ); return NULL; } return MODULE_GetProcAddress( wm->module, end + 1, snoop ); } }
void WINAPI VXD_Win32s( CONTEXT86 *context ) { switch (AX_reg(context)) { case 0x0000: /* Get Version */ /* * Input: None * * Output: EAX: LoWord: Win32s Version (1.30) * HiWord: VxD Version (200) * * EBX: Build (172) * * ECX: ??? (1) * * EDX: Debugging Flags * * EDI: Error Flag * 0 if OK, * 1 if VMCPD VxD not found */ TRACE("GetVersion()\n"); context->Eax = VXD_WinVersion() | (200 << 16); context->Ebx = 0; context->Ecx = 0; context->Edx = 0; context->Edi = 0; /* * If this is the first time we are called for this process, * hack the memory image of WIN32S16 so that it doesn't try * to access the GDT directly ... * * The first code segment of WIN32S16 (version 1.30) contains * an unexported function somewhere between the exported functions * SetFS and StackLinearToSegmented that tries to find a selector * in the LDT that maps to the memory image of the LDT itself. * If it succeeds, it stores this selector into a global variable * which will be used to speed up execution by using this selector * to modify the LDT directly instead of using the DPMI calls. * * To perform this search of the LDT, this function uses the * sgdt and sldt instructions to find the linear address of * the (GDT and then) LDT. While those instructions themselves * execute without problem, the linear address that sgdt returns * points (at least under Linux) to the kernel address space, so * that any subsequent access leads to a segfault. * * Fortunately, WIN32S16 still contains as a fallback option the * mechanism of using DPMI calls to modify LDT selectors instead * of direct writes to the LDT. Thus we can circumvent the problem * by simply replacing the first byte of the offending function * with an 'retf' instruction. This means that the global variable * supposed to contain the LDT alias selector will remain zero, * and hence WIN32S16 will fall back to using DPMI calls. * * The heuristic we employ to _find_ that function is as follows: * We search between the addresses of the exported symbols SetFS * and StackLinearToSegmented for the byte sequence '0F 01 04' * (this is the opcode of 'sgdt [si]'). We then search backwards * from this address for the last occurrence of 'CB' (retf) that marks * the end of the preceeding function. The following byte (which * should now be the first byte of the function we are looking for) * will be replaced by 'CB' (retf). * * This heuristic works for the retail as well as the debug version * of Win32s version 1.30. For versions earlier than that this * hack should not be necessary at all, since the whole mechanism * ('PERF130') was introduced only in 1.30 to improve the overall * performance of Win32s. */ if (!W32S_offset) { HMODULE16 hModule = GetModuleHandle16("win32s16"); SEGPTR func1 = (SEGPTR)GetProcAddress16(hModule, "SetFS"); SEGPTR func2 = (SEGPTR)GetProcAddress16(hModule, "StackLinearToSegmented"); if ( hModule && func1 && func2 && SELECTOROF(func1) == SELECTOROF(func2)) { BYTE *start = MapSL(func1); BYTE *end = MapSL(func2); BYTE *p, *retv = NULL; int found = 0; for (p = start; p < end; p++) if (*p == 0xCB) found = 0, retv = p; else if (*p == 0x0F) found = 1; else if (*p == 0x01 && found == 1) found = 2; else if (*p == 0x04 && found == 2) { found = 3; break; } else found = 0; if (found == 3 && retv) { TRACE("PERF130 hack: " "Replacing byte %02X at offset %04X:%04X\n", *(retv+1), SELECTOROF(func1), OFFSETOF(func1) + retv+1-start); *(retv+1) = (BYTE)0xCB; } } } /* * Mark process as Win32s, so that subsequent DPMI calls * will perform the W32S_APP2WINE/W32S_WINE2APP address shift. */ W32S_offset = 0x10000; break; case 0x0001: /* Install Exception Handling */ /* * Input: EBX: Flat address of W32SKRNL Exception Data * * ECX: LoWord: Flat Code Selector * HiWord: Flat Data Selector * * EDX: Flat address of W32SKRNL Exception Handler * (this is equal to W32S_BackTo32 + 0x40) * * ESI: SEGPTR KERNEL.HASGPHANDLER * * EDI: SEGPTR phCurrentTask (KERNEL.THHOOK + 0x10) * * Output: EAX: 0 if OK */ TRACE("[0001] EBX=%lx ECX=%lx EDX=%lx ESI=%lx EDI=%lx\n", context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi); /* FIXME */ context->Eax = 0; break; case 0x0002: /* Set Page Access Flags */ /* * Input: EBX: New access flags * Bit 2: User Page if set, Supervisor Page if clear * Bit 1: Read-Write if set, Read-Only if clear * * ECX: Size of memory area to change * * EDX: Flat start address of memory area * * Output: EAX: Size of area changed */ TRACE("[0002] EBX=%lx ECX=%lx EDX=%lx\n", context->Ebx, context->Ecx, context->Edx); /* FIXME */ context->Eax = context->Ecx; break; case 0x0003: /* Get Page Access Flags */ /* * Input: EDX: Flat address of page to query * * Output: EAX: Page access flags * Bit 2: User Page if set, Supervisor Page if clear * Bit 1: Read-Write if set, Read-Only if clear */ TRACE("[0003] EDX=%lx\n", context->Edx); /* FIXME */ context->Eax = 6; break; case 0x0004: /* Map Module */ /* * Input: ECX: IMTE (offset in Module Table) of new module * * EDX: Flat address of Win32s Module Table * * Output: EAX: 0 if OK */ if (!context->Edx || CX_reg(context) == 0xFFFF) { TRACE("MapModule: Initialization call\n"); context->Eax = 0; } else { /* * Structure of a Win32s Module Table Entry: */ struct Win32sModule { DWORD flags; DWORD flatBaseAddr; LPCSTR moduleName; LPCSTR pathName; LPCSTR unknown; LPBYTE baseAddr; DWORD hModule; DWORD relocDelta; }; /* * Note: This function should set up a demand-paged memory image * of the given module. Since mmap does not allow file offsets * not aligned at 1024 bytes, we simply load the image fully * into memory. */ struct Win32sModule *moduleTable = (struct Win32sModule *)W32S_APP2WINE(context->Edx); struct Win32sModule *module = moduleTable + context->Ecx; IMAGE_NT_HEADERS *nt_header = PE_HEADER(module->baseAddr); IMAGE_SECTION_HEADER *pe_seg = PE_SECTIONS(module->baseAddr); HFILE image = _lopen(module->pathName, OF_READ); BOOL error = (image == HFILE_ERROR); UINT i; TRACE("MapModule: Loading %s\n", module->pathName); for (i = 0; !error && i < nt_header->FileHeader.NumberOfSections; i++, pe_seg++) if(!(pe_seg->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) { DWORD off = pe_seg->PointerToRawData; DWORD len = pe_seg->SizeOfRawData; LPBYTE addr = module->baseAddr + pe_seg->VirtualAddress; TRACE("MapModule: " "Section %d at %08lx from %08lx len %08lx\n", i, (DWORD)addr, off, len); if ( _llseek(image, off, SEEK_SET) != off || _lread(image, addr, len) != len) error = TRUE; } _lclose(image); if (error) ERR("MapModule: Unable to load %s\n", module->pathName); else if (module->relocDelta != 0) { IMAGE_DATA_DIRECTORY *dir = nt_header->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_BASERELOC; IMAGE_BASE_RELOCATION *r = (IMAGE_BASE_RELOCATION *) (dir->Size? module->baseAddr + dir->VirtualAddress : 0); TRACE("MapModule: Reloc delta %08lx\n", module->relocDelta); while (r && r->VirtualAddress) { LPBYTE page = module->baseAddr + r->VirtualAddress; WORD *TypeOffset = (WORD *)(r + 1); int count = (r->SizeOfBlock - sizeof(*r)) / sizeof(*TypeOffset); TRACE("MapModule: %d relocations for page %08lx\n", count, (DWORD)page); for(i = 0; i < count; i++) { int offset = TypeOffset[i] & 0xFFF; int type = TypeOffset[i] >> 12; switch(type) { case IMAGE_REL_BASED_ABSOLUTE: break; case IMAGE_REL_BASED_HIGH: *(WORD *)(page+offset) += HIWORD(module->relocDelta); break; case IMAGE_REL_BASED_LOW: *(WORD *)(page+offset) += LOWORD(module->relocDelta); break; case IMAGE_REL_BASED_HIGHLOW: *(DWORD*)(page+offset) += module->relocDelta; break; default: WARN("MapModule: Unsupported fixup type\n"); break; } } r = (IMAGE_BASE_RELOCATION *)((LPBYTE)r + r->SizeOfBlock); } } context->Eax = 0; RESET_CFLAG(context); } break; case 0x0005: /* UnMap Module */ /* * Input: EDX: Flat address of module image * * Output: EAX: 1 if OK */ TRACE("UnMapModule: %lx\n", (DWORD)W32S_APP2WINE(context->Edx)); /* As we didn't map anything, there's nothing to unmap ... */ context->Eax = 1; break; case 0x0006: /* VirtualAlloc */ /* * Input: ECX: Current Process * * EDX: Flat address of arguments on stack * * DWORD *retv [out] Flat base address of allocated region * LPVOID base [in] Flat address of region to reserve/commit * DWORD size [in] Size of region * DWORD type [in] Type of allocation * DWORD prot [in] Type of access protection * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); DWORD size = stack[2]; DWORD type = stack[3]; DWORD prot = stack[4]; DWORD result; TRACE("VirtualAlloc(%lx, %lx, %lx, %lx, %lx)\n", (DWORD)retv, (DWORD)base, size, type, prot); if (type & 0x80000000) { WARN("VirtualAlloc: strange type %lx\n", type); type &= 0x7fffffff; } if (!base && (type & MEM_COMMIT) && prot == PAGE_READONLY) { WARN("VirtualAlloc: NLS hack, allowing write access!\n"); prot = PAGE_READWRITE; } result = (DWORD)VirtualAlloc(base, size, type, prot); if (W32S_WINE2APP(result)) *retv = W32S_WINE2APP(result), context->Eax = STATUS_SUCCESS; else *retv = 0, context->Eax = STATUS_NO_MEMORY; /* FIXME */ } break; case 0x0007: /* VirtualFree */ /* * Input: ECX: Current Process * * EDX: Flat address of arguments on stack * * DWORD *retv [out] TRUE if success, FALSE if failure * LPVOID base [in] Flat address of region * DWORD size [in] Size of region * DWORD type [in] Type of operation * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); DWORD size = stack[2]; DWORD type = stack[3]; DWORD result; TRACE("VirtualFree(%lx, %lx, %lx, %lx)\n", (DWORD)retv, (DWORD)base, size, type); result = VirtualFree(base, size, type); if (result) *retv = TRUE, context->Eax = STATUS_SUCCESS; else *retv = FALSE, context->Eax = STATUS_NO_MEMORY; /* FIXME */ } break; case 0x0008: /* VirtualProtect */ /* * Input: ECX: Current Process * * EDX: Flat address of arguments on stack * * DWORD *retv [out] TRUE if success, FALSE if failure * LPVOID base [in] Flat address of region * DWORD size [in] Size of region * DWORD new_prot [in] Desired access protection * DWORD *old_prot [out] Previous access protection * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); DWORD size = stack[2]; DWORD new_prot = stack[3]; DWORD *old_prot = (DWORD *)W32S_APP2WINE(stack[4]); DWORD result; TRACE("VirtualProtect(%lx, %lx, %lx, %lx, %lx)\n", (DWORD)retv, (DWORD)base, size, new_prot, (DWORD)old_prot); result = VirtualProtect(base, size, new_prot, old_prot); if (result) *retv = TRUE, context->Eax = STATUS_SUCCESS; else *retv = FALSE, context->Eax = STATUS_NO_MEMORY; /* FIXME */ } break; case 0x0009: /* VirtualQuery */ /* * Input: ECX: Current Process * * EDX: Flat address of arguments on stack * * DWORD *retv [out] Nr. bytes returned * LPVOID base [in] Flat address of region * LPMEMORY_BASIC_INFORMATION info [out] Info buffer * DWORD len [in] Size of buffer * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); LPMEMORY_BASIC_INFORMATION info = (LPMEMORY_BASIC_INFORMATION)W32S_APP2WINE(stack[2]); DWORD len = stack[3]; DWORD result; TRACE("VirtualQuery(%lx, %lx, %lx, %lx)\n", (DWORD)retv, (DWORD)base, (DWORD)info, len); result = VirtualQuery(base, info, len); *retv = result; context->Eax = STATUS_SUCCESS; } break; case 0x000A: /* SetVirtMemProcess */ /* * Input: ECX: Process Handle * * EDX: Flat address of region * * Output: EAX: NtStatus */ TRACE("[000a] ECX=%lx EDX=%lx\n", context->Ecx, context->Edx); /* FIXME */ context->Eax = STATUS_SUCCESS; break; case 0x000B: /* ??? some kind of cleanup */ /* * Input: ECX: Process Handle * * Output: EAX: NtStatus */ TRACE("[000b] ECX=%lx\n", context->Ecx); /* FIXME */ context->Eax = STATUS_SUCCESS; break; case 0x000C: /* Set Debug Flags */ /* * Input: EDX: Debug Flags * * Output: EDX: Previous Debug Flags */ FIXME("[000c] EDX=%lx\n", context->Edx); /* FIXME */ context->Edx = 0; break; case 0x000D: /* NtCreateSection */ /* * Input: EDX: Flat address of arguments on stack * * HANDLE32 *retv [out] Handle of Section created * DWORD flags1 [in] (?? unknown ??) * DWORD atom [in] Name of Section to create * LARGE_INTEGER *size [in] Size of Section * DWORD protect [in] Access protection * DWORD flags2 [in] (?? unknown ??) * HFILE32 hFile [in] Handle of file to map * DWORD psp [in] (Win32s: PSP that hFile belongs to) * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *) W32S_APP2WINE(context->Edx); HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]); DWORD flags1 = stack[1]; DWORD atom = stack[2]; LARGE_INTEGER *size = (LARGE_INTEGER *)W32S_APP2WINE(stack[3]); DWORD protect = stack[4]; DWORD flags2 = stack[5]; HANDLE hFile = DosFileHandleToWin32Handle(stack[6]); DWORD psp = stack[7]; HANDLE result = INVALID_HANDLE_VALUE; char name[128]; TRACE("NtCreateSection(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n", (DWORD)retv, flags1, atom, (DWORD)size, protect, flags2, (DWORD)hFile, psp); if (!atom || GlobalGetAtomNameA(atom, name, sizeof(name))) { TRACE("NtCreateSection: name=%s\n", atom? name : NULL); result = CreateFileMappingA(hFile, NULL, protect, size? size->s.HighPart : 0, size? size->s.LowPart : 0, atom? name : NULL); } if (result == INVALID_HANDLE_VALUE) WARN("NtCreateSection: failed!\n"); else TRACE("NtCreateSection: returned %lx\n", (DWORD)result); if (result != INVALID_HANDLE_VALUE) *retv = result, context->Eax = STATUS_SUCCESS; else *retv = result, context->Eax = STATUS_NO_MEMORY; /* FIXME */ } break; case 0x000E: /* NtOpenSection */ /* * Input: EDX: Flat address of arguments on stack * * HANDLE32 *retv [out] Handle of Section opened * DWORD protect [in] Access protection * DWORD atom [in] Name of Section to create * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); HANDLE *retv = (HANDLE *)W32S_APP2WINE(stack[0]); DWORD protect = stack[1]; DWORD atom = stack[2]; HANDLE result = INVALID_HANDLE_VALUE; char name[128]; TRACE("NtOpenSection(%lx, %lx, %lx)\n", (DWORD)retv, protect, atom); if (atom && GlobalGetAtomNameA(atom, name, sizeof(name))) { TRACE("NtOpenSection: name=%s\n", name); result = OpenFileMappingA(protect, FALSE, name); } if (result == INVALID_HANDLE_VALUE) WARN("NtOpenSection: failed!\n"); else TRACE("NtOpenSection: returned %lx\n", (DWORD)result); if (result != INVALID_HANDLE_VALUE) *retv = result, context->Eax = STATUS_SUCCESS; else *retv = result, context->Eax = STATUS_NO_MEMORY; /* FIXME */ } break; case 0x000F: /* NtCloseSection */ /* * Input: EDX: Flat address of arguments on stack * * HANDLE32 handle [in] Handle of Section to close * DWORD *id [out] Unique ID (?? unclear ??) * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); HANDLE handle = stack[0]; DWORD *id = (DWORD *)W32S_APP2WINE(stack[1]); TRACE("NtCloseSection(%lx, %lx)\n", (DWORD)handle, (DWORD)id); CloseHandle(handle); if (id) *id = 0; /* FIXME */ context->Eax = STATUS_SUCCESS; } break; case 0x0010: /* NtDupSection */ /* * Input: EDX: Flat address of arguments on stack * * HANDLE32 handle [in] Handle of Section to duplicate * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); HANDLE handle = stack[0]; HANDLE new_handle; TRACE("NtDupSection(%lx)\n", (DWORD)handle); DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS ); context->Eax = STATUS_SUCCESS; } break; case 0x0011: /* NtMapViewOfSection */ /* * Input: EDX: Flat address of arguments on stack * * HANDLE32 SectionHandle [in] Section to be mapped * DWORD ProcessHandle [in] Process to be mapped into * DWORD * BaseAddress [in/out] Address to be mapped at * DWORD ZeroBits [in] (?? unclear ??) * DWORD CommitSize [in] (?? unclear ??) * LARGE_INTEGER *SectionOffset [in] Offset within section * DWORD * ViewSize [in] Size of view * DWORD InheritDisposition [in] (?? unclear ??) * DWORD AllocationType [in] (?? unclear ??) * DWORD Protect [in] Access protection * * Output: EAX: NtStatus */ { DWORD * stack = (DWORD *)W32S_APP2WINE(context->Edx); HANDLE SectionHandle = stack[0]; DWORD ProcessHandle = stack[1]; /* ignored */ DWORD * BaseAddress = (DWORD *)W32S_APP2WINE(stack[2]); DWORD ZeroBits = stack[3]; DWORD CommitSize = stack[4]; LARGE_INTEGER *SectionOffset = (LARGE_INTEGER *)W32S_APP2WINE(stack[5]); DWORD * ViewSize = (DWORD *)W32S_APP2WINE(stack[6]); DWORD InheritDisposition = stack[7]; DWORD AllocationType = stack[8]; DWORD Protect = stack[9]; LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0); DWORD access = 0, result; switch (Protect & ~(PAGE_GUARD|PAGE_NOCACHE)) { case PAGE_READONLY: access = FILE_MAP_READ; break; case PAGE_READWRITE: access = FILE_MAP_WRITE; break; case PAGE_WRITECOPY: access = FILE_MAP_COPY; break; case PAGE_EXECUTE_READ: access = FILE_MAP_READ; break; case PAGE_EXECUTE_READWRITE: access = FILE_MAP_WRITE; break; case PAGE_EXECUTE_WRITECOPY: access = FILE_MAP_COPY; break; } TRACE("NtMapViewOfSection" "(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx)\n", (DWORD)SectionHandle, ProcessHandle, (DWORD)BaseAddress, ZeroBits, CommitSize, (DWORD)SectionOffset, (DWORD)ViewSize, InheritDisposition, AllocationType, Protect); TRACE("NtMapViewOfSection: " "base=%lx, offset=%lx, size=%lx, access=%lx\n", (DWORD)address, SectionOffset? SectionOffset->s.LowPart : 0, ViewSize? *ViewSize : 0, access); result = (DWORD)MapViewOfFileEx(SectionHandle, access, SectionOffset? SectionOffset->s.HighPart : 0, SectionOffset? SectionOffset->s.LowPart : 0, ViewSize? *ViewSize : 0, address); TRACE("NtMapViewOfSection: result=%lx\n", result); if (W32S_WINE2APP(result)) { if (BaseAddress) *BaseAddress = W32S_WINE2APP(result); context->Eax = STATUS_SUCCESS; } else context->Eax = STATUS_NO_MEMORY; /* FIXME */ } break; case 0x0012: /* NtUnmapViewOfSection */ /* * Input: EDX: Flat address of arguments on stack * * DWORD ProcessHandle [in] Process (defining address space) * LPBYTE BaseAddress [in] Base address of view to be unmapped * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); DWORD ProcessHandle = stack[0]; /* ignored */ LPBYTE BaseAddress = (LPBYTE)W32S_APP2WINE(stack[1]); TRACE("NtUnmapViewOfSection(%lx, %lx)\n", ProcessHandle, (DWORD)BaseAddress); UnmapViewOfFile(BaseAddress); context->Eax = STATUS_SUCCESS; } break; case 0x0013: /* NtFlushVirtualMemory */ /* * Input: EDX: Flat address of arguments on stack * * DWORD ProcessHandle [in] Process (defining address space) * LPBYTE *BaseAddress [in?] Base address of range to be flushed * DWORD *ViewSize [in?] Number of bytes to be flushed * DWORD *unknown [???] (?? unknown ??) * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); DWORD ProcessHandle = stack[0]; /* ignored */ DWORD *BaseAddress = (DWORD *)W32S_APP2WINE(stack[1]); DWORD *ViewSize = (DWORD *)W32S_APP2WINE(stack[2]); DWORD *unknown = (DWORD *)W32S_APP2WINE(stack[3]); LPBYTE address = (LPBYTE)(BaseAddress? W32S_APP2WINE(*BaseAddress) : 0); DWORD size = ViewSize? *ViewSize : 0; TRACE("NtFlushVirtualMemory(%lx, %lx, %lx, %lx)\n", ProcessHandle, (DWORD)BaseAddress, (DWORD)ViewSize, (DWORD)unknown); TRACE("NtFlushVirtualMemory: base=%lx, size=%lx\n", (DWORD)address, size); FlushViewOfFile(address, size); context->Eax = STATUS_SUCCESS; } break; case 0x0014: /* Get/Set Debug Registers */ /* * Input: ECX: 0 if Get, 1 if Set * * EDX: Get: Flat address of buffer to receive values of * debug registers DR0 .. DR7 * Set: Flat address of buffer containing values of * debug registers DR0 .. DR7 to be set * Output: None */ FIXME("[0014] ECX=%lx EDX=%lx\n", context->Ecx, context->Edx); /* FIXME */ break; case 0x0015: /* Set Coprocessor Emulation Flag */ /* * Input: EDX: 0 to deactivate, 1 to activate coprocessor emulation * * Output: None */ TRACE("[0015] EDX=%lx\n", context->Edx); /* We don't care, as we always have a coprocessor anyway */ break; case 0x0016: /* Init Win32S VxD PSP */ /* * If called to query required PSP size: * * Input: EBX: 0 * Output: EDX: Required size of Win32s VxD PSP * * If called to initialize allocated PSP: * * Input: EBX: LoWord: Selector of Win32s VxD PSP * HiWord: Paragraph of Win32s VxD PSP (DOSMEM) * Output: None */ if (context->Ebx == 0) context->Edx = 0x80; else { PDB16 *psp = MapSL( MAKESEGPTR( BX_reg(context), 0 )); psp->nbFiles = 32; psp->fileHandlesPtr = MAKELONG(HIWORD(context->Ebx), 0x5c); memset((LPBYTE)psp + 0x5c, '\xFF', 32); } break; case 0x0017: /* Set Break Point */ /* * Input: EBX: Offset of Break Point * CX: Selector of Break Point * * Output: None */ FIXME("[0017] EBX=%lx CX=%x\n", context->Ebx, CX_reg(context)); /* FIXME */ break; case 0x0018: /* VirtualLock */ /* * Input: ECX: Current Process * * EDX: Flat address of arguments on stack * * DWORD *retv [out] TRUE if success, FALSE if failure * LPVOID base [in] Flat address of range to lock * DWORD size [in] Size of range * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); DWORD size = stack[2]; DWORD result; TRACE("VirtualLock(%lx, %lx, %lx)\n", (DWORD)retv, (DWORD)base, size); result = VirtualLock(base, size); if (result) *retv = TRUE, context->Eax = STATUS_SUCCESS; else *retv = FALSE, context->Eax = STATUS_NO_MEMORY; /* FIXME */ } break; case 0x0019: /* VirtualUnlock */ /* * Input: ECX: Current Process * * EDX: Flat address of arguments on stack * * DWORD *retv [out] TRUE if success, FALSE if failure * LPVOID base [in] Flat address of range to unlock * DWORD size [in] Size of range * * Output: EAX: NtStatus */ { DWORD *stack = (DWORD *)W32S_APP2WINE(context->Edx); DWORD *retv = (DWORD *)W32S_APP2WINE(stack[0]); LPVOID base = (LPVOID) W32S_APP2WINE(stack[1]); DWORD size = stack[2]; DWORD result; TRACE("VirtualUnlock(%lx, %lx, %lx)\n", (DWORD)retv, (DWORD)base, size); result = VirtualUnlock(base, size); if (result) *retv = TRUE, context->Eax = STATUS_SUCCESS; else *retv = FALSE, context->Eax = STATUS_NO_MEMORY; /* FIXME */ } break; case 0x001A: /* KGetSystemInfo */ /* * Input: None * * Output: ECX: Start of sparse memory arena * EDX: End of sparse memory arena */ TRACE("KGetSystemInfo()\n"); /* * Note: Win32s reserves 0GB - 2GB for Win 3.1 and uses 2GB - 4GB as * sparse memory arena. We do it the other way around, since * we have to reserve 3GB - 4GB for Linux, and thus use * 0GB - 3GB as sparse memory arena. * * FIXME: What about other OSes ? */ context->Ecx = W32S_WINE2APP(0x00000000); context->Edx = W32S_WINE2APP(0xbfffffff); break; case 0x001B: /* KGlobalMemStat */ /* * Input: ESI: Flat address of buffer to receive memory info * * Output: None */ { struct Win32sMemoryInfo { DWORD DIPhys_Count; /* Total physical pages */ DWORD DIFree_Count; /* Free physical pages */ DWORD DILin_Total_Count; /* Total virtual pages (private arena) */ DWORD DILin_Total_Free; /* Free virtual pages (private arena) */ DWORD SparseTotal; /* Total size of sparse arena (bytes ?) */ DWORD SparseFree; /* Free size of sparse arena (bytes ?) */ }; struct Win32sMemoryInfo *info = (struct Win32sMemoryInfo *)W32S_APP2WINE(context->Esi); FIXME("KGlobalMemStat(%lx)\n", (DWORD)info); /* FIXME */ } break; case 0x001C: /* Enable/Disable Exceptions */ /* * Input: ECX: 0 to disable, 1 to enable exception handling * * Output: None */ TRACE("[001c] ECX=%lx\n", context->Ecx); /* FIXME */ break; case 0x001D: /* VirtualAlloc called from 16-bit code */ /* * Input: EDX: Segmented address of arguments on stack * * LPVOID base [in] Flat address of region to reserve/commit * DWORD size [in] Size of region * DWORD type [in] Type of allocation * DWORD prot [in] Type of access protection * * Output: EAX: NtStatus * EDX: Flat base address of allocated region */ { DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) )); LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]); DWORD size = stack[1]; DWORD type = stack[2]; DWORD prot = stack[3]; DWORD result; TRACE("VirtualAlloc16(%lx, %lx, %lx, %lx)\n", (DWORD)base, size, type, prot); if (type & 0x80000000) { WARN("VirtualAlloc16: strange type %lx\n", type); type &= 0x7fffffff; } result = (DWORD)VirtualAlloc(base, size, type, prot); if (W32S_WINE2APP(result)) context->Edx = W32S_WINE2APP(result), context->Eax = STATUS_SUCCESS; else context->Edx = 0, context->Eax = STATUS_NO_MEMORY; /* FIXME */ TRACE("VirtualAlloc16: returning base %lx\n", context->Edx); } break; case 0x001E: /* VirtualFree called from 16-bit code */ /* * Input: EDX: Segmented address of arguments on stack * * LPVOID base [in] Flat address of region * DWORD size [in] Size of region * DWORD type [in] Type of operation * * Output: EAX: NtStatus * EDX: TRUE if success, FALSE if failure */ { DWORD *stack = MapSL( MAKESEGPTR( LOWORD(context->Edx), HIWORD(context->Edx) )); LPVOID base = (LPVOID)W32S_APP2WINE(stack[0]); DWORD size = stack[1]; DWORD type = stack[2]; DWORD result; TRACE("VirtualFree16(%lx, %lx, %lx)\n", (DWORD)base, size, type); result = VirtualFree(base, size, type); if (result) context->Edx = TRUE, context->Eax = STATUS_SUCCESS; else context->Edx = FALSE, context->Eax = STATUS_NO_MEMORY; /* FIXME */ } break; case 0x001F: /* FWorkingSetSize */ /* * Input: EDX: 0 if Get, 1 if Set * * ECX: Get: Buffer to receive Working Set Size * Set: Buffer containing Working Set Size * * Output: NtStatus */ { DWORD *ptr = (DWORD *)W32S_APP2WINE(context->Ecx); BOOL set = context->Edx; TRACE("FWorkingSetSize(%lx, %lx)\n", (DWORD)ptr, (DWORD)set); if (set) /* We do it differently ... */; else *ptr = 0x100; context->Eax = STATUS_SUCCESS; } break; default: VXD_BARF( context, "W32S" ); }
/** * Read header and get resource directory offset in a Windows library * (AKA module). */ bool Win32ResExtractor::read_library(WinLibrary *fi) { /* check for DOS header signature `MZ' */ RETURN_IF_BAD_POINTER(false, MZ_HEADER(fi->memory)->magic); if (FROM_LE_16(MZ_HEADER(fi->memory)->magic) == IMAGE_DOS_SIGNATURE) { DOSImageHeader *mz_header = MZ_HEADER(fi->memory); RETURN_IF_BAD_POINTER(false, mz_header->lfanew); // Apply endian fix (currently only lfanew is used from the DOSImageHeader, // so we don't bother to 'fix' the rest). LE32(mz_header->lfanew); if (mz_header->lfanew < sizeof(DOSImageHeader)) { error("%s: not a Windows library", _fileName.c_str()); return false; } } /* check for NT header signature `PE' */ RETURN_IF_BAD_POINTER(false, PE_HEADER(fi->memory)->signature); if (FROM_LE_32(PE_HEADER(fi->memory)->signature) == IMAGE_NT_SIGNATURE) { Win32ImageNTHeaders *pe_header; int d; // Fix image header endianess fix_win32_image_header_endian(PE_HEADER(fi->memory)); /* allocate new memory */ fi->total_size = calc_vma_size(fi); if (fi->total_size == 0) { /* calc_vma_size has reported error */ return false; } byte *ptr = (byte *)realloc(fi->memory, fi->total_size); assert(ptr); fi->memory = ptr; /* relocate memory, start from last section */ pe_header = PE_HEADER(fi->memory); RETURN_IF_BAD_POINTER(false, pe_header->file_header.number_of_sections); /* we don't need to do OFFSET checking for the sections. * calc_vma_size has already done that */ for (d = pe_header->file_header.number_of_sections - 1; d >= 0 ; d--) { Win32ImageSectionHeader *pe_sec = PE_SECTIONS(fi->memory) + d; if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue; //if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size) RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->virtual_address, pe_sec->size_of_raw_data); RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data); if (FROM_LE_32(pe_sec->virtual_address) != pe_sec->pointer_to_raw_data) { memmove(fi->memory + pe_sec->virtual_address, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data); } } /* find resource directory */ RETURN_IF_BAD_POINTER(false, pe_header->optional_header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]); Win32ImageDataDirectory *dir = pe_header->optional_header.data_directory + IMAGE_DIRECTORY_ENTRY_RESOURCE; if (dir->size == 0) { error("%s: file contains no resources", _fileName.c_str()); return false; } fix_win32_image_data_directory(dir); fi->first_resource = fi->memory + dir->virtual_address; return true; } /* other (unknown) header signature was found */ error("%s: not a Windows library", _fileName.c_str()); return false; }