/******************************************************************* * BuildPendingEventCheck * * Build a function that checks whether there are any * pending DPMI events. * * Stack layout: * * (sp+12) long eflags * (sp+6) long cs * (sp+2) long ip * (sp) word fs * * On entry to function, fs register points to a valid TEB. * On exit from function, stack will be popped. */ static void BuildPendingEventCheck(void) { /* Function header */ function_header( "DPMI_PendingEventCheck" ); /* Check for pending events. */ output( "\t.byte 0x64\n\ttestl $0xffffffff,(%d)\n", STRUCTOFFSET(TEB,GdiTebBatch) + STRUCTOFFSET(WINE_VM86_TEB_INFO,vm86_pending) ); output( "\tje %s\n", asm_name("DPMI_PendingEventCheck_Cleanup") ); output( "\t.byte 0x64\n\ttestl $0xffffffff,(%d)\n", STRUCTOFFSET(TEB,GdiTebBatch) + STRUCTOFFSET(WINE_VM86_TEB_INFO,dpmi_vif) ); output( "\tje %s\n", asm_name("DPMI_PendingEventCheck_Cleanup") ); /* Process pending events. */ output( "\tsti\n" ); /* Start cleanup. Restore fs register. */ output( "%s\n", asm_globl("DPMI_PendingEventCheck_Cleanup") ); output( "\tpopw %%fs\n" ); /* Return from function. */ output( "%s\n", asm_globl("DPMI_PendingEventCheck_Return") ); output( "\tiret\n" ); output_function_size( "DPMI_PendingEventCheck" ); }
/******************************************************************* * BuildRelays16 * * Build all the 16-bit relay callbacks */ void BuildRelays16(void) { if (target_cpu != CPU_x86) { output( "/* File not used with this architecture. Do not edit! */\n\n" ); return; } /* File header */ output( "/* File generated automatically. Do not edit! */\n\n" ); output( "\t.text\n" ); output( "%s:\n\n", asm_name("__wine_spec_thunk_text_16") ); output( "%s\n", asm_globl("__wine_call16_start") ); /* Standard CallFrom16 routine */ BuildCallFrom16Core( FALSE, FALSE ); /* Register CallFrom16 routine */ BuildCallFrom16Core( TRUE, FALSE ); /* C16ThkSL CallFrom16 routine */ BuildCallFrom16Core( FALSE, TRUE ); /* Standard CallTo16 routine */ BuildCallTo16Core( 0 ); /* Register CallTo16 routine */ BuildCallTo16Core( 1 ); /* Standard CallTo16 return stub */ BuildRet16Func(); /* CBClientThunkSL routine */ BuildCallTo32CBClient( FALSE ); /* CBClientThunkSLEx routine */ BuildCallTo32CBClient( TRUE ); /* Pending DPMI events check stub */ BuildPendingEventCheck(); output( "%s\n", asm_globl("__wine_call16_end") ); output_function_size( "__wine_spec_thunk_text_16" ); /* Declare the return address and data selector variables */ output( "\n\t.data\n\t.align %d\n", get_alignment(4) ); output( "%s\n\t.long 0\n", asm_globl("CallTo16_DataSelector") ); output( "%s\n\t.long 0\n", asm_globl("CallTo16_TebSelector") ); if (UsePIC) output( "wine_ldt_copy_ptr:\t.long %s\n", asm_name("wine_ldt_copy") ); output_gnu_stack_note(); }
/* output a single import thunk */ static void output_import_thunk( const char *name, const char *table, int pos ) { output( "\n\t.align %d\n", get_alignment(4) ); output( "\t%s\n", func_declaration(name) ); output( "%s\n", asm_globl(name) ); output_cfi( ".cfi_startproc" ); switch(target_cpu) { case CPU_x86: if (!UsePIC) { output( "\tjmp *(%s+%d)\n", table, pos ); } else { output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos ); } break; case CPU_x86_64: output( "\tjmpq *%s+%d(%%rip)\n", table, pos ); break; case CPU_ARM: output( "\tldr IP,1f\n"); output( "\tldr PC,[PC,IP]\n" ); output( "1:\t.long %s+%u-(1b+4)\n", table, pos ); break; case CPU_ARM64: output( "\tadr x9, 1f\n" ); output( "\tldur x9, [x9, #0]\n" ); if (pos & 0xf000) output( "\tadd x9, x9, #%u\n", pos & 0xf000 ); if (pos & 0x0f00) output( "\tadd x9, x9, #%u\n", pos & 0x0f00 ); if (pos & 0x00f0) output( "\tadd x9, x9, #%u\n", pos & 0x00f0 ); if (pos & 0x000f) output( "\tadd x9, x9, #%u\n", pos & 0x000f ); output( "\tldur x9, [x9, #0]\n" ); output( "\tbr x9\n" ); output( "1:\t.quad %s\n", table ); break; case CPU_POWERPC: output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(31) ); if (target_platform == PLATFORM_APPLE) { output( "\tlis %s, ha16(%s+%d+32768)\n", ppc_reg(31), table, pos ); output( "\tla %s, lo16(%s+%d)(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) ); } else { output( "\tlis %s, (%s+%d+32768)@h\n", ppc_reg(31), table, pos ); output( "\tla %s, (%s+%d)@l(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) ); } output( "\tlwz %s, 0(%s)\n", ppc_reg(31), ppc_reg(31) ); output( "\tmtctr %s\n", ppc_reg(31) ); output( "\tmr %s, %s\n", ppc_reg(31), ppc_reg(0) ); output( "\tbctr\n" ); break; } output_cfi( ".cfi_endproc" ); output_function_size( name ); }
/******************************************************************* * output_asm_relays16 * * Build all the 16-bit relay callbacks */ void output_asm_relays16(void) { /* File header */ output( "\t.text\n" ); output( "%s:\n\n", asm_name("__wine_spec_thunk_text_16") ); output( "%s\n", asm_globl("__wine_call16_start") ); /* Standard CallFrom16 routine */ BuildCallFrom16Core( 0, 0 ); /* Register CallFrom16 routine */ BuildCallFrom16Core( 1, 0 ); /* C16ThkSL CallFrom16 routine */ BuildCallFrom16Core( 0, 1 ); /* Standard CallTo16 routine */ BuildCallTo16Core( 0 ); /* Register CallTo16 routine */ BuildCallTo16Core( 1 ); /* Standard CallTo16 return stub */ BuildRet16Func(); /* CBClientThunkSL routine */ BuildCallTo32CBClient( 0 ); /* CBClientThunkSLEx routine */ BuildCallTo32CBClient( 1 ); output( "%s\n", asm_globl("__wine_call16_end") ); output_function_size( "__wine_spec_thunk_text_16" ); /* Declare the return address and data selector variables */ output( "\n\t.data\n\t.align %d\n", get_alignment(4) ); output( "%s\n\t.long 0\n", asm_globl("CallTo16_DataSelector") ); output( "%s\n\t.long 0\n", asm_globl("CallTo16_TebSelector") ); }
/* output the delayed import table of a Win32 module */ static void output_delayed_imports( const DLLSPEC *spec ) { int i, j, mod; if (!nb_delayed) return; output( "\n/* delayed imports */\n\n" ); output( "\t.data\n" ); output( "\t.align %d\n", get_alignment(get_ptr_size()) ); output( "%s\n", asm_globl("__wine_spec_delay_imports") ); /* list of dlls */ for (i = j = mod = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */ output( "\t%s .L__wine_delay_name_%d\n", /* szName */ get_asm_ptr_keyword(), i ); output( "\t%s .L__wine_delay_modules+%d\n", /* phmod */ get_asm_ptr_keyword(), mod * get_ptr_size() ); output( "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */ get_asm_ptr_keyword(), j * get_ptr_size() ); output( "\t%s .L__wine_delay_INT+%d\n", /* pINT */ get_asm_ptr_keyword(), j * get_ptr_size() ); output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */ j += dll_imports[i]->nb_imports; mod++; } output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */ output( "\n.L__wine_delay_IAT:\n" ); for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; const char *name = odp->name ? odp->name : odp->export_name; output( "\t%s .L__wine_delay_imp_%d_%s\n", get_asm_ptr_keyword(), i, name ); } } output( "\n.L__wine_delay_INT:\n" ); for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; if (!odp->name) output( "\t%s %d\n", get_asm_ptr_keyword(), odp->ordinal ); else output( "\t%s .L__wine_delay_data_%d_%s\n", get_asm_ptr_keyword(), i, odp->name ); } } output( "\n.L__wine_delay_modules:\n" ); for (i = 0; i < nb_imports; i++) { if (dll_imports[i]->delay) output( "\t%s 0\n", get_asm_ptr_keyword() ); } for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; output( ".L__wine_delay_name_%d:\n", i ); output( "\t%s \"%s\"\n", get_asm_string_keyword(), dll_imports[i]->spec->file_name ); } for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; if (!odp->name) continue; output( ".L__wine_delay_data_%d_%s:\n", i, odp->name ); output( "\t%s \"%s\"\n", get_asm_string_keyword(), odp->name ); } } output_function_size( "__wine_spec_delay_imports" ); }
/* output a single import thunk */ static void output_import_thunk( const char *name, const char *table, int pos ) { output( "\n\t.align %d\n", get_alignment(4) ); output( "\t%s\n", func_declaration(name) ); output( "%s\n", asm_globl(name) ); output_cfi( ".cfi_startproc" ); switch(target_cpu) { case CPU_x86: if (!UsePIC) { output( "\tjmp *(%s+%d)\n", table, pos ); } else { output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos ); } break; case CPU_x86_64: output( "\tjmpq *%s+%d(%%rip)\n", table, pos ); break; case CPU_SPARC: if ( !UsePIC ) { output( "\tsethi %%hi(%s+%d), %%g1\n", table, pos ); output( "\tld [%%g1+%%lo(%s+%d)], %%g1\n", table, pos ); output( "\tjmp %%g1\n" ); output( "\tnop\n" ); } else { /* Hmpf. Stupid sparc assembler always interprets global variable names as GOT offsets, so we have to do it the long way ... */ output( "\tsave %%sp, -96, %%sp\n" ); output( "0:\tcall 1f\n" ); output( "\tnop\n" ); output( "1:\tsethi %%hi(%s+%d-0b), %%g1\n", table, pos ); output( "\tor %%g1, %%lo(%s+%d-0b), %%g1\n", table, pos ); output( "\tld [%%g1+%%o7], %%g1\n" ); output( "\tjmp %%g1\n" ); output( "\trestore\n" ); } break; case CPU_ARM: output( "\tldr IP,[PC,#0]\n"); output( "\tldr PC,[IP,#%d]\n", pos); output( "\t.long %s\n", table ); break; case CPU_ARM64: output( "\tadr x9, 1f\n" ); output( "\tldur x9, [x9, #0]\n" ); if (pos & 0xf000) output( "\tadd x9, x9, #%u\n", pos & 0xf000 ); if (pos & 0x0f00) output( "\tadd x9, x9, #%u\n", pos & 0x0f00 ); if (pos & 0x00f0) output( "\tadd x9, x9, #%u\n", pos & 0x00f0 ); if (pos & 0x000f) output( "\tadd x9, x9, #%u\n", pos & 0x000f ); output( "\tldur x9, [x9, #0]\n" ); output( "\tbr x9\n" ); output( "1:\t.quad %s\n", table ); break; case CPU_POWERPC: output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(31) ); if (target_platform == PLATFORM_APPLE) { output( "\tlis %s, ha16(%s+%d+32768)\n", ppc_reg(31), table, pos ); output( "\tla %s, lo16(%s+%d)(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) ); } else { output( "\tlis %s, (%s+%d+32768)@h\n", ppc_reg(31), table, pos ); output( "\tla %s, (%s+%d)@l(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) ); } output( "\tlwz %s, 0(%s)\n", ppc_reg(31), ppc_reg(31) ); output( "\tmtctr %s\n", ppc_reg(31) ); output( "\tmr %s, %s\n", ppc_reg(31), ppc_reg(0) ); output( "\tbctr\n" ); break; } output_cfi( ".cfi_endproc" ); output_function_size( name ); }
static void function_header( const char *name ) { output( "\n\t.align %d\n", get_alignment(4) ); output( "\t%s\n", func_declaration(name) ); output( "%s\n", asm_globl(name) ); }
/******************************************************************* * output_module * * Output the module data. */ void output_module( DLLSPEC *spec ) { int machine = 0; unsigned int page_size = get_page_size(); /* Reserve some space for the PE header */ switch (target_platform) { case PLATFORM_APPLE: output( "\t.text\n" ); output( "\t.align %d\n", get_alignment(page_size) ); output( "__wine_spec_pe_header:\n" ); output( "\t.space 65536\n" ); break; case PLATFORM_SOLARIS: output( "\n\t.section \".text\",\"ax\"\n" ); output( "__wine_spec_pe_header:\n" ); output( "\t.skip %u\n", 65536 + page_size ); break; default: output( "\n\t.section \".init\",\"ax\"\n" ); switch(target_cpu) { case CPU_x86: case CPU_x86_64: case CPU_SPARC: output( "\tjmp 1f\n" ); break; case CPU_ARM: case CPU_POWERPC: output( "\tb 1f\n" ); break; } output( "__wine_spec_pe_header:\n" ); output( "\t.skip %u\n", 65536 + page_size ); output( "1:\n" ); break; } /* Output the NT header */ output( "\n\t.data\n" ); output( "\t.align %d\n", get_alignment(get_ptr_size()) ); output( "%s\n", asm_globl("__wine_spec_nt_header") ); output( ".L__wine_spec_rva_base:\n" ); output( "\t.long 0x4550\n" ); /* Signature */ switch(target_cpu) { case CPU_x86: machine = IMAGE_FILE_MACHINE_I386; break; case CPU_x86_64: machine = IMAGE_FILE_MACHINE_AMD64; break; case CPU_ARM: machine = IMAGE_FILE_MACHINE_ARMV7; break; case CPU_POWERPC: machine = IMAGE_FILE_MACHINE_POWERPC; break; case CPU_SPARC: machine = IMAGE_FILE_MACHINE_SPARC; break; } output( "\t%s 0x%04x\n", /* Machine */ get_asm_short_keyword(), machine ); output( "\t%s 0\n", /* NumberOfSections */ get_asm_short_keyword() ); output( "\t.long 0\n" ); /* TimeDateStamp */ output( "\t.long 0\n" ); /* PointerToSymbolTable */ output( "\t.long 0\n" ); /* NumberOfSymbols */ output( "\t%s %d\n", /* SizeOfOptionalHeader */ get_asm_short_keyword(), get_ptr_size() == 8 ? IMAGE_SIZEOF_NT_OPTIONAL64_HEADER : IMAGE_SIZEOF_NT_OPTIONAL32_HEADER ); output( "\t%s 0x%04x\n", /* Characteristics */ get_asm_short_keyword(), spec->characteristics ); output( "\t%s 0x%04x\n", /* Magic */ get_asm_short_keyword(), get_ptr_size() == 8 ? IMAGE_NT_OPTIONAL_HDR64_MAGIC : IMAGE_NT_OPTIONAL_HDR32_MAGIC ); output( "\t.byte 0\n" ); /* MajorLinkerVersion */ output( "\t.byte 0\n" ); /* MinorLinkerVersion */ output( "\t.long 0\n" ); /* SizeOfCode */ output( "\t.long 0\n" ); /* SizeOfInitializedData */ output( "\t.long 0\n" ); /* SizeOfUninitializedData */ /* note: we expand the AddressOfEntryPoint field on 64-bit by overwriting the BaseOfCode field */ output( "\t%s %s\n", /* AddressOfEntryPoint */ get_asm_ptr_keyword(), spec->init_func ? asm_name(spec->init_func) : "0" ); if (get_ptr_size() == 4) { output( "\t.long 0\n" ); /* BaseOfCode */ output( "\t.long 0\n" ); /* BaseOfData */ } output( "\t%s __wine_spec_pe_header\n", /* ImageBase */ get_asm_ptr_keyword() ); output( "\t.long %u\n", page_size ); /* SectionAlignment */ output( "\t.long %u\n", page_size ); /* FileAlignment */ output( "\t%s 1,0\n", /* Major/MinorOperatingSystemVersion */ get_asm_short_keyword() ); output( "\t%s 0,0\n", /* Major/MinorImageVersion */ get_asm_short_keyword() ); output( "\t%s %u,%u\n", /* Major/MinorSubsystemVersion */ get_asm_short_keyword(), spec->subsystem_major, spec->subsystem_minor ); output( "\t.long 0\n" ); /* Win32VersionValue */ output( "\t.long %s-.L__wine_spec_rva_base\n", /* SizeOfImage */ asm_name("_end") ); output( "\t.long %u\n", page_size ); /* SizeOfHeaders */ output( "\t.long 0\n" ); /* CheckSum */ output( "\t%s 0x%04x\n", /* Subsystem */ get_asm_short_keyword(), spec->subsystem ); output( "\t%s 0x%04x\n", /* DllCharacteristics */ get_asm_short_keyword(), spec->dll_characteristics ); output( "\t%s %u,%u\n", /* SizeOfStackReserve/Commit */ get_asm_ptr_keyword(), (spec->stack_size ? spec->stack_size : 1024) * 1024, page_size ); output( "\t%s %u,%u\n", /* SizeOfHeapReserve/Commit */ get_asm_ptr_keyword(), (spec->heap_size ? spec->heap_size : 1024) * 1024, page_size ); output( "\t.long 0\n" ); /* LoaderFlags */ output( "\t.long 16\n" ); /* NumberOfRvaAndSizes */ if (spec->base <= spec->limit) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */ output( "\t.long .L__wine_spec_exports-.L__wine_spec_rva_base," ".L__wine_spec_exports_end-.L__wine_spec_exports\n" ); else output( "\t.long 0,0\n" ); if (has_imports()) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */ output( "\t.long .L__wine_spec_imports-.L__wine_spec_rva_base," ".L__wine_spec_imports_end-.L__wine_spec_imports\n" ); else output( "\t.long 0,0\n" ); if (spec->nb_resources) /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */ output( "\t.long .L__wine_spec_resources-.L__wine_spec_rva_base," ".L__wine_spec_resources_end-.L__wine_spec_resources\n" ); else output( "\t.long 0,0\n" ); output( "\t.long 0,0\n" ); /* DataDirectory[3] */ output( "\t.long 0,0\n" ); /* DataDirectory[4] */ output( "\t.long 0,0\n" ); /* DataDirectory[5] */ output( "\t.long 0,0\n" ); /* DataDirectory[6] */ output( "\t.long 0,0\n" ); /* DataDirectory[7] */ output( "\t.long 0,0\n" ); /* DataDirectory[8] */ output( "\t.long 0,0\n" ); /* DataDirectory[9] */ output( "\t.long 0,0\n" ); /* DataDirectory[10] */ output( "\t.long 0,0\n" ); /* DataDirectory[11] */ output( "\t.long 0,0\n" ); /* DataDirectory[12] */ output( "\t.long 0,0\n" ); /* DataDirectory[13] */ output( "\t.long 0,0\n" ); /* DataDirectory[14] */ output( "\t.long 0,0\n" ); /* DataDirectory[15] */ output( "\n\t%s\n", get_asm_string_section() ); output( "%s\n", asm_globl("__wine_spec_file_name") ); output( ".L__wine_spec_file_name:\n" ); output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name ); if (target_platform == PLATFORM_APPLE) output( "\t.lcomm %s,4\n", asm_name("_end") ); output_asm_constructor( "__wine_spec_init_ctor" ); }