From: Andy Polyakov Date: Tue, 25 May 2004 20:31:03 +0000 (+0000) Subject: Framework for glueing BIO layer and Win32 compiler run-time. Goal is to X-Git-Tag: BEN_FIPS_TEST_6~14^2~233 X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=3fc378aa0b464d6296fbf4f0d84b66a207b3f8a2;hp=f2bfbcef76d4a5d5cd8bccb51efd2441aaf88254 Framework for glueing BIO layer and Win32 compiler run-time. Goal is to make it possible to produce for a unified binary build, which can be used with a variety of Win32 compilers. --- diff --git a/ms/applink.c b/ms/applink.c new file mode 100644 index 0000000000..4333d2639d --- /dev/null +++ b/ms/applink.c @@ -0,0 +1,45 @@ +#define APPLINK_STDIN 1 +#define APPLINK_STDOUT 2 +#define APPLINK_STDERR 3 +#define APPLINK_FPRINTF 4 +#define APPLINK_FGETS 5 +#define APPLINK_FREAD 6 +#define APPLINK_FWRITE 7 +#define APPLINK_FSETMOD 8 +#define APPLINK_FEOF 9 +#define APPLINK_FCLOSE 10 /* should not be used */ +#define APPLINK_MAX 10 /* always same as last macro */ + +#ifndef APPMACROS_ONLY +#include +#include +#include + +static void *app_stdin() { return stdin; } +static void *app_stdout() { return stdout; } +static void *app_stderr() { return stderr; } +static int app_feof(FILE *fp) { return feof(fp); } +static int app_fsetmod(FILE *fp,char mod) +{ return _setmode (_fileno(fp),mod=='b'?_O_BINARY:_O_TEXT); } + +__declspec(dllexport) void **OPENSSL_Applink() +{ static int once=1; + static void *OPENSSL_ApplinkTable[APPLINK_MAX+1]={(void *)APPLINK_MAX}; + + if (once) + { OPENSSL_ApplinkTable[APPLINK_STDIN] = app_stdin; + OPENSSL_ApplinkTable[APPLINK_STDOUT] = app_stdout; + OPENSSL_ApplinkTable[APPLINK_STDERR] = app_stderr; + OPENSSL_ApplinkTable[APPLINK_FPRINTF] = fprintf; + OPENSSL_ApplinkTable[APPLINK_FGETS] = fgets; + OPENSSL_ApplinkTable[APPLINK_FREAD] = fread; + OPENSSL_ApplinkTable[APPLINK_FWRITE] = fwrite; + OPENSSL_ApplinkTable[APPLINK_FSETMOD] = app_fsetmod; + OPENSSL_ApplinkTable[APPLINK_FEOF] = app_feof; + OPENSSL_ApplinkTable[APPLINK_FCLOSE] = fclose; + once = 0; + } + + return OPENSSL_ApplinkTable; +} +#endif diff --git a/ms/uplink.c b/ms/uplink.c new file mode 100644 index 0000000000..c839f9b087 --- /dev/null +++ b/ms/uplink.c @@ -0,0 +1,168 @@ +#if defined(_WIN64) && !defined(UNICODE) +#define UNICODE +#endif +#if defined(UNICODE) && !defined(_UNICODE) +#define _UNICODE +#endif +#if defined(_UNICODE) && !defined(UNICODE) +#define UNICODE +#endif +#if defined(_MSC_VER) && !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0333 /* 3.51 */ +#endif + +#include +#include +#include +#include +#include "uplink.h" + +#ifdef _MSC_VER +#pragma comment(lib,"delayimp") +/* + * CL command line should also be complemented with following: + * + * /link /delayload:advapi32.dll /delayload:user32.dll + * + * This is required if/as we want to support Win9x. With delayloaded + * DLLs in question all we have to do is to make sure NT-specific + * functions are not actually called under Win9x. + */ +#endif + +#if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333 +int IsService() +{ HWINSTA h; + DWORD len; + WCHAR *name; + + GetDesktopWindow(); /* return value is ignored */ + + h = GetProcessWindowStation(); + if (h==NULL) return -1; + + if (GetUserObjectInformationW (h,UOI_NAME,NULL,0,&len) || + GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return -1; + + if (len>512) return -1; /* paranoia */ + len++,len&=~1; /* paranoia */ +#ifdef _MSC_VER + name=(WCHAR *)_alloca(len+sizeof(WCHAR)); +#else + name=(WCHAR *)alloca(len+sizeof(WCHAR)); +#endif + if (!GetUserObjectInformationW (h,UOI_NAME,name,len,&len)) + return -1; + + len++,len&=~1; /* paranoia */ + name[len/sizeof(WCHAR)]=L'\0'; /* paranoia */ +#if 1 + /* This doesn't cover "interactive" services [working with real + * WinSta0's] nor programs started non-interactively by Task + * Scheduler [those are working with SAWinSta]. */ + if (wcsstr(name,L"Service-0x")) return 1; +#else + /* This covers all non-interactive programs such as services. */ + if (!wcsstr(name,L"WinSta0")) return 1; +#endif + else return 0; +} +#endif + +static TCHAR msg[128]; + +static void unimplemented () +{ +#if defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0333 + /* this -------------v--- guards NT-specific calls */ + if (GetVersion() < 0x80000000 && IsService()) + { HANDLE h = RegisterEventSource(0,_T("OPENSSL")); + TCHAR *pmsg=msg; + ReportEvent(h,EVENTLOG_ERROR_TYPE,0,0,0,1,0,&pmsg,0); + DeregisterEventSource(h); + } + else +#endif + { MSGBOXPARAMS m; + + m.cbSize = sizeof(m); + m.hwndOwner = NULL; + m.lpszCaption = _T("OpenSSL: FATAL"); + m.dwStyle = MB_OK; + m.hInstance = NULL; + m.lpszIcon = IDI_ERROR; + m.dwContextHelpId = 0; + m.lpfnMsgBoxCallback = NULL; + m.dwLanguageId = MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US); + m.lpszText = msg; + + MessageBoxIndirect (&m); + } + ExitProcess (1); +} + +void OPENSSL_Uplink (void **table, int index) +{ static HMODULE app=NULL; + static void **applinktable=NULL; + int len; + + len = _stprintf (msg,_T("OPENSSL_Uplink(%p,%02X): "),table,index); + _tcscpy (msg+len,_T("unimplemented function")); + table [index] = unimplemented; + + if (app==NULL && (app=GetModuleHandle(NULL))==NULL) + { app=(HMODULE)-1; _tcscpy (msg+len,_T("no host application")); + return; + } + else if (app==(HMODULE)-1) { return; } + + if (applinktable==NULL) + { void**(*applink)(); + + applink=(void**(*)())GetProcAddress(app,"OPENSSL_Applink"); + if (applink==NULL) + { app=(HMODULE)-1; _tcscpy (msg+len,_T("no OPENSSL_Applink")); + return; + } + applinktable = (*applink)(); + if (applinktable==NULL) + { app=(HMODULE)-1; _tcscpy (msg+len,_T("no ApplinkTable")); + return; + } + } + + if (index > (int)applinktable[0]) { return; } + + if (applinktable[index]) table[index] = applinktable[index]; +} + +#if defined(_MSC_VER) && defined(_M_IX86) +#define LAZY(i) \ +__declspec(naked) static void lazy##i () { \ + _asm push i \ + _asm push OFFSET OPENSSL_UplinkTable \ + _asm call OPENSSL_Uplink \ + _asm add esp,8 \ + _asm jmp OPENSSL_UplinkTable+4*i } + +#if APPLINK_MAX>20 +#error "Add more stubs..." +#endif +/* make some in advance... */ +LAZY(1) LAZY(2) LAZY(3) LAZY(4) LAZY(5) +LAZY(6) LAZY(7) LAZY(8) LAZY(9) LAZY(10) +LAZY(11) LAZY(12) LAZY(13) LAZY(14) LAZY(15) +LAZY(16) LAZY(17) LAZY(18) LAZY(19) LAZY(20) +void *OPENSSL_UplinkTable[] = { + (void *)APPLINK_MAX, + lazy1, lazy2, lazy3, lazy4, lazy5, + lazy6, lazy7, lazy8, lazy9, lazy10, + lazy11,lazy12,lazy13,lazy14,lazy15, + lazy16,lazy17,lazy18,lazy19,lazy20, +}; +#endif + +#ifdef SELFTEST +main() { UP_fprintf(UP_stdout,"hello, world!\n"); } +#endif diff --git a/ms/uplink.h b/ms/uplink.h new file mode 100644 index 0000000000..3e9911ab93 --- /dev/null +++ b/ms/uplink.h @@ -0,0 +1,14 @@ +#define APPMACROS_ONLY +#include "applink.c" + +extern void *OPENSSL_UplinkTable[]; +#define UP_stdin (*(void *(*)())OPENSSL_UplinkTable[APPLINK_STDIN])() +#define UP_stdout (*(void *(*)())OPENSSL_UplinkTable[APPLINK_STDOUT])() +#define UP_stderr (*(void *(*)())OPENSSL_UplinkTable[APPLINK_STDERR])() +#define UP_fprintf (*(int (*)(void *,const char *,...))OPENSSL_UplinkTable[APPLINK_FPRINTF]) +#define UP_fgets (*(char *(*)(char *,int,void *))OPENSSL_UplinkTable[APPLINK_FGETS]) +#define UP_fread (*(size_t (*)(void *,size_t,size_t,void *))OPENSSL_UplinkTable[APPLINK_FREAD]) +#define UP_fwrite (*(size_t (*)(void *,size_t,size_t,void *))OPENSSL_UplinkTable[APPLINK_FWRITE]) +#define UP_fsetmod (*(int (*)(void *,char))OPENSSL_UplinkTable[APPLINK_FSETMOD]) +#define UP_feof (*(int (*)(void *))OPENSSL_UplinkTable[APPLINK_FEOF]) +#define UP_fclose (*(int (*)(void *))OPENSSL_Uplink[APPLINK_FCLOSE]) diff --git a/ms/uplink.pl b/ms/uplink.pl new file mode 100755 index 0000000000..801f6e01fa --- /dev/null +++ b/ms/uplink.pl @@ -0,0 +1,177 @@ +#!/usr/bin/env perl +# +# For Microsoft CL this is implemented as inline assembler. So that +# even though this script can generate even Win32 code, we'll be +# using it primarily to generate Win64 modules. Both IA-64 and AMD64 +# are supported... + +# pull APPLINK_MAX value from applink.c... +$applink_c=$0; +$applink_c=~s|[^/\\]+$||g; +$applink_c.="applink.c"; +open(INPUT,$applink_c) || die "can't open $applink_c: $!"; +@max=grep {/APPLINK_MAX\s+(\d+)/} ; +close(INPUT); +($#max==0) or die "can't find APPLINK_MAX in $applink_c"; + +$max[0]=~/APPLINK_MAX\s+(\d+)/; +$N=$1; # number of entries in OPENSSL_UplinkTable not including + # OPENSSL_UplinkTable[0], which contains this value... + +# Idea is to fill the OPENSSL_UplinkTable with pointers to stubs +# which invoke 'void OPENSSL_Uplink (ULONG_PTR *table,int index)'; +# and then dereference themselves. Latter shall result in endless +# loop *unless* OPENSSL_Uplink does not replace 'table[index]' with +# something else, e.g. as 'table[index]=unimplemented;'... + +$arg = shift; +#( defined shift || open STDOUT,">$arg" ) || die "can't open $arg: $!"; + +if ($arg =~ /win32n/) { ia32nasm(); } +elsif ($arg =~ /win32/) { ia32masm(); } +elsif ($arg =~ /ia64/) { ia64ias(); } +elsif ($arg =~ /amd64/) { amd64masm(); } +else { die "nonsense $arg"; } + +sub ia32masm() { +print <<___; +.386P +.model FLAT + +_DATA SEGMENT +PUBLIC _OPENSSL_UplinkTable +_OPENSSL_UplinkTable DD $N ; amount of following entries +___ +for ($i=1;$i<=$N;$i++) { print " DD FLAT:\$lazy$i\n"; } +print <<___; +_DATA ENDS + +_TEXT SEGMENT +EXTRN _OPENSSL_Uplink:NEAR +___ +for ($i=1;$i<=$N;$i++) { +print <<___; +ALIGN 4 +\$lazy$i PROC NEAR + push $i + push OFFSET FLAT:_OPENSSL_UplinkTable + call _OPENSSL_Uplink + add esp,8 + jmp DWORD PTR _OPENSSL_UplinkTable+4*$i +\$lazy$i ENDP +___ +} +print <<___; +ALIGN 4 +_TEXT ENDS +END +___ +} + +sub ia32nasm() { +print <<___; +SEGMENT .data +GLOBAL _OPENSSL_UplinkTable +_OPENSSL_UplinkTable DD $N ; amount of following entries +___ +for ($i=1;$i<=$N;$i++) { print " DD \$lazy$i\n"; } +print <<___; + +SEGMENT .text +EXTERN _OPENSSL_Uplink +___ +for ($i=1;$i<=$N;$i++) { +print <<___; +ALIGN 4 +\$lazy$i: + push $i + push _OPENSSL_UplinkTable + call _OPENSSL_Uplink + add esp,8 + jmp [_OPENSSL_UplinkTable+4*$i] +___ +} +print <<___; +ALIGN 4 +END +___ +} + +sub ia64ias () { +local $V=8; # max number of args uplink functions may accept... +print <<___; +.data +.global OPENSSL_UplinkTable# +OPENSSL_UplinkTable: data8 $N // amount of following entries +___ +for ($i=1;$i<=$N;$i++) { print " data8 \@fptr(lazy$i#)\n"; } +print <<___; +.size OPENSSL_UplinkTable,.-OPENSSL_UplinkTable# + +.text +.global OPENSSL_Uplink# +.type OPENSSL_Uplink#,\@function +___ +for ($i=1;$i<=$N;$i++) { +print <<___; +.proc lazy$i +lazy$i: +{ .mii; alloc loc0=ar.pfs,$V,3,2,0 + mov loc1=b0 + addl loc2=\@ltoff(OPENSSL_UplinkTable#),gp };; +{ .mmi; ld8 out0=[loc2] + mov out1=$i };; +{ .mib; adds loc2=8*$i,out0 + br.call.sptk.many b0=OPENSSL_Uplink# };; +{ .mmi; ld8 r31=[loc2];; + ld8 r30=[r31],8 };; +{ .mii; ld8 gp=[r31] + mov b6=r30 + mov b0=loc1 };; +{ .mib; mov ar.pfs=loc0 + br.many b6 };; +.endp lazy$i# +___ +} +} + +sub amd64masm() { +print <<___; +_DATA SEGMENT +PUBLIC OPENSSL_UplinkTable +OPENSSL_UplinkTable DQ $N +___ +for ($i=1;$i<=$N;$i++) { print " DQ FLAT:\$lazy$i\n"; } +print <<___; +_DATA ENDS + +TEXT SEGMENT +EXTERN OPENSSL_Uplink:NEAR +___ +for ($i=1;$i<=$N;$i++) { +print <<___; +ALIGN 4 +\$lazy$i PROC NEAR + push r9 + push r8 + push rdx + push rcx + sub rsp,40 + mov rcx,OFFSET FLAT:OPENSSL_UplinkTable + mov rdx,$i + call OPENSSL_Uplink + add rsp,40 + pop rcx + pop rdx + pop r8 + pop r9 + jmp QWORD PTR OPENSSL_UplinkTable+8*$i +\$lazy$i ENDP +___ +} +print <<___; +TEXT ENDS +END +___ +} +