Commit 90538d86 authored by Tamar Christina's avatar Tamar Christina Committed by Ben Gamari
Browse files

Change runtime linker to perform lazy loading of symbols/sections

The Runtime Linker is currently eagerly loading all object files on all
platforms which do not use the system linker for `GHCi`.

The problem with this approach is that it requires all symbols to be
found.  Even those of functions never used/called. This makes the number
of libraries required to link things like `mingwex` quite high.

To work around this the `rts` was relying on a trick. It itself was
compiled with `MingW64-w`'s `GCC`. So it was already linked against
`mingwex`.  As such, it re-exported the symbols from itself.

While this worked it made it impossible to link against `mingwex` in
user libraries. And with this means no `C99` code could ever run in
`GHCi` on Windows without having the required symbols re-exported from
the rts.

Consequently this rules out a large number of packages on Windows.
SDL2, HMatrix etc.

After talking with @rwbarton I have taken the approach of loading entire
object files when a symbol is needed instead of doing the dependency
tracking on a per symbol basis. This is a lot less fragile and a lot
less complicated to implement.

The changes come down to the following steps:

1) modify the linker to and introduce a new state for ObjectCode:
   `Needed`.  A Needed object is one that is required for the linking to
   succeed.  The initial set consists of all Object files passed as
   arguments to the link.

2) Change `ObjectCode`'s to be indexed but not initialized or resolved.
   This means we know where we would load the symbols,
   but haven't actually done so.

3) Mark any `ObjectCode` belonging to `.o` passed as argument
   as required: ObjectState `NEEDED`.

4) During `Resolve` object calls, mark all `ObjectCode`
   containing the required symbols as `NEEDED`

5) During `lookupSymbol` lookups, (which is called from `linkExpr`
   and `linkDecl` in `GHCI.hs`) is the symbol is in a not-yet-loaded
   `ObjectCode` then load the `ObjectCode` on demand and return the
   address of the symbol. Otherwise produce an unresolved symbols error
   as expected.

6) On `unloadObj` we then change the state of the object and remove
   it's symbols from the `reqSymHash` table so it can be reloaded.

This change affects all platforms and OSes which use the runtime linker.
It seems there are no real perf tests for `GHCi`, but performance
shouldn't be impacted much. We gain a lot of time not loading all `obj`
files, and we lose some time in `lookupSymbol` when we're finding
sections that have to be loaded. The actual finding itself is O(1)
(Assuming the hashtnl is perfect)

It also consumes slighly more memory as instead of storing just the
address of a symbol I also store some other information, like if the
symbol is weak or not.

This change will break any packages relying on renamed POSIX functions
that were re-named and re-exported by the rts. Any packages following
the proper naming for functions as found on MSDN will work fine.

Test Plan: ./validate on all platforms which use the Runtime linker.

Reviewers: thomie, rwbarton, simonmar, erikd, bgamari, austin, hvr

Reviewed By: erikd

Subscribers: kgardas, gridaphobe, RyanGlScott, simonmar,
             rwbarton, #ghc_windows_task_force

Differential Revision: https://phabricator.haskell.org/D1805

GHC Trac Issues: #11223
parent 8987ce06
......@@ -934,9 +934,24 @@ runLink dflags args = do
let (p,args0) = pgm_l dflags
args1 = map Option (getOpts dflags opt_l)
args2 = args0 ++ linkargs ++ args1 ++ args
mb_env <- getGccEnv args2
runSomethingResponseFile dflags ld_filter "Linker" p args2 mb_env
args3 = argFixup args2 []
mb_env <- getGccEnv args3
runSomethingResponseFile dflags ld_filter "Linker" p args3 mb_env
where
testLib lib = "-l" `isPrefixOf` lib || ".a" `isSuffixOf` lib
{- GHC is just blindly appending linker arguments from libraries and
the commandline together. This results in very problematic link orders
which will cause incorrect linking. Since we're changing the link
arguments anyway, let's just make sure libraries are last.
This functions moves libraries on the link all the way back
but keeps the order amongst them the same. -}
argFixup [] r = [] ++ r
argFixup (o@(Option opt):xs) r = if testLib opt
then argFixup xs (r ++ [o])
else o:argFixup xs r
argFixup (o@(FileOption _ opt):xs) r = if testLib opt
then argFixup xs (r ++ [o])
else o:argFixup xs r
ld_filter = case (platformOS (targetPlatform dflags)) of
OSSolaris2 -> sunos_ld_filter
_ -> id
......
......@@ -1001,9 +1001,6 @@ AC_COMPILE_IFELSE(
AC_DEFINE([CC_SUPPORTS_TLS],[0],[Define to 1 if __thread is supported])
])
AC_CHECK_FUNCS(__mingw_vfprintf)
dnl large address space support (see includes/rts/storage/MBlock.h)
dnl
dnl Darwin has vm_allocate/vm_protect
......
......@@ -72,6 +72,9 @@ The highlights, since the 7.10 branch, are:
- Support for Windows XP and earlier has been dropped.
- GHC RTS No longer re-exports POSIX functions under their deprecated
names on Windows.
Full details
------------
......@@ -458,6 +461,12 @@ Runtime system
choose to use at most ⟨x⟩ capabilities, limited by the number of processors
as :rts-flag:`-N` is.
- The runtime linker is no longer greedy and will load only the needed objects
from archives. This means particularly on Windows packages requiring e.g. C99
support will now function properly. As part of this the RTS on Windows
no longer re-exports deprecated posix functions under the undeprecated names
(see :ghc-ticket:`11223`).
Build system
~~~~~~~~~~~~
......
......@@ -352,49 +352,115 @@ type CFilePath = CString
type CFilePath = CWString
#endif
foreign import ccall unsafe "HsBase.h access"
foreign import ccall unsafe "HsBase.h __hscore_open"
c_open :: CFilePath -> CInt -> CMode -> IO CInt
foreign import ccall safe "HsBase.h __hscore_open"
c_safe_open :: CFilePath -> CInt -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_fstat"
c_fstat :: CInt -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_lstat"
lstat :: CFilePath -> Ptr CStat -> IO CInt
{- Note: Win32 POSIX functions
Functions that are not part of the POSIX standards were
at some point deprecated by Microsoft. This deprecation
was performed by renaming the functions according to the
C++ ABI Section 17.6.4.3.2b. This was done to free up the
namespace of normal Windows programs since Windows isn't
POSIX compliant anyway.
These were working before since the RTS was re-exporting
these symbols under the undeprecated names. This is no longer
being done. See #11223
See https://msdn.microsoft.com/en-us/library/ms235384.aspx
for more.
-}
#if defined(mingw32_HOST_OS)
foreign import ccall unsafe "io.h _lseeki64"
c_lseek :: CInt -> Int64 -> CInt -> IO Int64
foreign import ccall unsafe "HsBase.h _access"
c_access :: CString -> CInt -> IO CInt
foreign import ccall unsafe "HsBase.h chmod"
foreign import ccall unsafe "HsBase.h _chmod"
c_chmod :: CString -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h close"
foreign import ccall unsafe "HsBase.h _close"
c_close :: CInt -> IO CInt
foreign import ccall unsafe "HsBase.h creat"
foreign import ccall unsafe "HsBase.h _creat"
c_creat :: CString -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h dup"
foreign import ccall unsafe "HsBase.h _dup"
c_dup :: CInt -> IO CInt
foreign import ccall unsafe "HsBase.h dup2"
foreign import ccall unsafe "HsBase.h _dup2"
c_dup2 :: CInt -> CInt -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_fstat"
c_fstat :: CInt -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h isatty"
foreign import ccall unsafe "HsBase.h _isatty"
c_isatty :: CInt -> IO CInt
#if defined(mingw32_HOST_OS)
foreign import ccall unsafe "io.h _lseeki64"
c_lseek :: CInt -> Int64 -> CInt -> IO Int64
-- See Note: CSsize
foreign import capi unsafe "HsBase.h _read"
c_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
-- See Note: CSsize
foreign import capi safe "HsBase.h _read"
c_safe_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
foreign import ccall unsafe "HsBase.h _umask"
c_umask :: CMode -> IO CMode
-- See Note: CSsize
foreign import capi unsafe "HsBase.h _write"
c_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
-- See Note: CSsize
foreign import capi safe "HsBase.h _write"
c_safe_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
foreign import ccall unsafe "HsBase.h _unlink"
c_unlink :: CString -> IO CInt
foreign import ccall unsafe "HsBase.h _pipe"
c_pipe :: Ptr CInt -> IO CInt
foreign import capi unsafe "HsBase.h _utime"
c_utime :: CString -> Ptr CUtimbuf -> IO CInt
foreign import ccall unsafe "HsBase.h _getpid"
c_getpid :: IO CPid
#else
-- We use CAPI as on some OSs (eg. Linux) this is wrapped by a macro
-- which redirects to the 64-bit-off_t versions when large file
-- support is enabled.
foreign import capi unsafe "unistd.h lseek"
c_lseek :: CInt -> COff -> CInt -> IO COff
#endif
foreign import ccall unsafe "HsBase.h __hscore_lstat"
lstat :: CFilePath -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h access"
c_access :: CString -> CInt -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_open"
c_open :: CFilePath -> CInt -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h chmod"
c_chmod :: CString -> CMode -> IO CInt
foreign import ccall safe "HsBase.h __hscore_open"
c_safe_open :: CFilePath -> CInt -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h close"
c_close :: CInt -> IO CInt
foreign import ccall unsafe "HsBase.h creat"
c_creat :: CString -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h dup"
c_dup :: CInt -> IO CInt
foreign import ccall unsafe "HsBase.h dup2"
c_dup2 :: CInt -> CInt -> IO CInt
foreign import ccall unsafe "HsBase.h isatty"
c_isatty :: CInt -> IO CInt
-- See Note: CSsize
foreign import capi unsafe "HsBase.h read"
......@@ -404,9 +470,6 @@ foreign import capi unsafe "HsBase.h read"
foreign import capi safe "HsBase.h read"
c_safe_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
foreign import ccall unsafe "HsBase.h __hscore_stat"
c_stat :: CFilePath -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h umask"
c_umask :: CMode -> IO CMode
......@@ -418,14 +481,24 @@ foreign import capi unsafe "HsBase.h write"
foreign import capi safe "HsBase.h write"
c_safe_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
foreign import ccall unsafe "HsBase.h __hscore_ftruncate"
c_ftruncate :: CInt -> COff -> IO CInt
foreign import ccall unsafe "HsBase.h unlink"
c_unlink :: CString -> IO CInt
foreign import ccall unsafe "HsBase.h pipe"
c_pipe :: Ptr CInt -> IO CInt
foreign import capi unsafe "HsBase.h utime"
c_utime :: CString -> Ptr CUtimbuf -> IO CInt
foreign import ccall unsafe "HsBase.h getpid"
c_getpid :: IO CPid
#endif
foreign import ccall unsafe "HsBase.h __hscore_stat"
c_stat :: CFilePath -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_ftruncate"
c_ftruncate :: CInt -> COff -> IO CInt
#if !defined(mingw32_HOST_OS)
foreign import capi unsafe "HsBase.h fcntl"
......@@ -447,9 +520,6 @@ foreign import ccall unsafe "HsBase.h link"
foreign import capi unsafe "HsBase.h mkfifo"
c_mkfifo :: CString -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h pipe"
c_pipe :: Ptr CInt -> IO CInt
foreign import capi unsafe "signal.h sigemptyset"
c_sigemptyset :: Ptr CSigset -> IO CInt
......@@ -467,9 +537,6 @@ foreign import capi unsafe "HsBase.h tcgetattr"
foreign import capi unsafe "HsBase.h tcsetattr"
c_tcsetattr :: CInt -> CInt -> Ptr CTermios -> IO CInt
foreign import capi unsafe "HsBase.h utime"
c_utime :: CString -> Ptr CUtimbuf -> IO CInt
foreign import ccall unsafe "HsBase.h waitpid"
c_waitpid :: CPid -> Ptr CInt -> CInt -> IO CPid
#endif
......
......@@ -336,7 +336,15 @@ Library
-- OS Specific
if os(windows)
extra-libraries: wsock32, user32, shell32
-- Windows requires some extra libraries for linking because the RTS
-- is no longer re-exporting them.
-- msvcrt: standard C library. The RTS will automatically include this,
-- but is added for completeness.
-- mingwex: provides C99 compatibility. libm is a stub on MingW.
-- mingw32: Unfortunately required because of a resource leak between
-- mingwex and mingw32. the __math_err symbol is defined in
-- mingw32 which is required by mingwex.
extra-libraries: wsock32, user32, shell32, msvcrt, mingw32, mingwex
exposed-modules:
GHC.IO.Encoding.CodePage.API
GHC.IO.Encoding.CodePage.Table
......
......@@ -299,7 +299,7 @@ INLINE int
__hscore_setmode( int fd, HsBool toBin )
{
#if defined(_WIN32)
return setmode(fd,(toBin == HS_BOOL_TRUE) ? _O_BINARY : _O_TEXT);
return _setmode(fd,(toBin == HS_BOOL_TRUE) ? _O_BINARY : _O_TEXT);
#else
return 0;
#endif
......
......@@ -53,6 +53,20 @@ Library
GHC.Tuple
GHC.Types
-- OS Specific
if os(windows)
-- Windows requires some extra libraries for linking because the RTS
-- is no longer re-exporting them (see #11223)
-- msvcrt: standard C library. The RTS will automatically include this,
-- but is added for completeness.
-- mingwex: provides C99 compatibility. libm is a stub on MingW.
-- mingw32: Unfortunately required because of a resource leak between
-- mingwex and mingw32. the __math_err symbol is defined in
-- mingw32 which is required by mingwex.
-- user32: provides access to apis to modify user components (UI etc)
-- on Windows. Required because of mingw32.
extra-libraries: user32, mingw32, mingwex
if flag(include-ghc-prim)
exposed-modules: GHC.Prim
......
This diff is collapsed.
......@@ -9,8 +9,12 @@
#ifndef LINKERINTERNALS_H
#define LINKERINTERNALS_H
#include "Rts.h"
/* See Linker.c Note [runtime-linker-phases] */
typedef enum {
OBJECT_LOADED,
OBJECT_NEEDED,
OBJECT_RESOLVED,
OBJECT_UNLOADED
} OStatus;
......@@ -93,6 +97,21 @@ typedef struct {
#endif
} SymbolExtra;
/* Top-level structure for an symbols in object module. One of these is allocated
* for each symbol in an object in use.
*/
typedef struct _SymbolInfo {
/* The name of the symbol. */
char* name;
/* The address of the symbol. */
unsigned char* addr;
/* Indicates if the symbol is weak */
HsBool isWeak;
} SymbolInfo;
/* Top-level structure for an object module. One of these is allocated
* for each object file in use.
*/
......@@ -111,8 +130,8 @@ typedef struct _ObjectCode {
this object into the global symbol hash table. This is so that
we know which parts of the latter mapping to nuke when this
object is removed from the system. */
char** symbols;
int n_symbols;
SymbolInfo* symbols;
int n_symbols;
/* ptr to mem containing the object file image */
char* image;
......
......@@ -58,18 +58,6 @@
#if defined(mingw32_HOST_OS)
#define RTS_POSIX_ONLY_SYMBOLS /**/
#if HAVE_GETTIMEOFDAY
#define RTS_MINGW_GETTIMEOFDAY_SYM SymI_NeedsProto(gettimeofday)
#else
#define RTS_MINGW_GETTIMEOFDAY_SYM /**/
#endif
#if HAVE___MINGW_VFPRINTF
#define RTS___MINGW_VFPRINTF_SYM SymI_HasProto(__mingw_vfprintf)
#else
#define RTS___MINGW_VFPRINTF_SYM /**/
#endif
#if defined(i386_HOST_ARCH)
#define RTS_WIN32_ONLY(X) X
#else
......@@ -82,324 +70,21 @@
#define RTS_WIN64_ONLY(X) /**/
#endif
/* These are statically linked from the mingw libraries into the ghc
executable, so we have to employ this hack. */
#define RTS_MINGW_ONLY_SYMBOLS \
SymI_HasProto(stg_asyncReadzh) \
SymI_HasProto(stg_asyncWritezh) \
SymI_HasProto(stg_asyncDoProczh) \
SymI_HasProto(getWin32ProgArgv) \
SymI_HasProto(setWin32ProgArgv) \
SymI_HasProto(memset) \
SymI_HasProto(inet_ntoa) \
SymI_HasProto(inet_addr) \
SymI_HasProto(htonl) \
SymI_HasProto(recvfrom) \
SymI_HasProto(listen) \
SymI_HasProto(bind) \
SymI_HasProto(shutdown) \
SymI_HasProto(connect) \
SymI_HasProto(htons) \
SymI_HasProto(ntohs) \
SymI_HasProto(getservbyname) \
SymI_HasProto(getservbyport) \
SymI_HasProto(getprotobynumber) \
SymI_HasProto(getprotobyname) \
SymI_HasProto(gethostbyname) \
SymI_HasProto(gethostbyaddr) \
SymI_HasProto(gethostname) \
SymI_HasProto(strcpy) \
SymI_HasProto(strncpy) \
SymI_HasProto(abort) \
SymI_HasProto(isxdigit) \
SymI_HasProto(isupper) \
SymI_HasProto(ispunct) \
SymI_HasProto(islower) \
SymI_HasProto(isspace) \
SymI_HasProto(isprint) \
SymI_HasProto(isdigit) \
SymI_HasProto(iscntrl) \
SymI_HasProto(isalpha) \
SymI_HasProto(isalnum) \
SymI_HasProto(isascii) \
RTS___MINGW_VFPRINTF_SYM \
SymI_HasProto(strcmp) \
SymI_HasProto(memmove) \
SymI_HasProto(realloc) \
SymI_HasProto(malloc) \
SymI_HasProto(pow) \
SymI_HasProto(tanh) \
SymI_HasProto(cosh) \
SymI_HasProto(sinh) \
SymI_HasProto(atan) \
SymI_HasProto(acos) \
SymI_HasProto(asin) \
SymI_HasProto(tan) \
SymI_HasProto(cos) \
SymI_HasProto(sin) \
SymI_HasProto(exp) \
SymI_HasProto(log) \
SymI_HasProto(sqrt) \
SymI_HasProto(powf) \
SymI_HasProto(tanhf) \
SymI_HasProto(coshf) \
SymI_HasProto(sinhf) \
SymI_HasProto(atanf) \
SymI_HasProto(acosf) \
SymI_HasProto(asinf) \
SymI_HasProto(tanf) \
SymI_HasProto(cosf) \
SymI_HasProto(sinf) \
SymI_HasProto(expf) \
SymI_HasProto(logf) \
SymI_HasProto(sqrtf) \
SymI_HasProto(erf) \
SymI_HasProto(erfc) \
SymI_HasProto(erff) \
SymI_HasProto(erfcf) \
SymI_HasProto(expm1) \
SymI_HasProto(expm1f) \
SymI_HasProto(log1p) \
SymI_HasProto(log1pf) \
SymI_HasProto(memcpy) \
SymI_HasProto(rts_InstallConsoleEvent) \
SymI_HasProto(rts_ConsoleHandlerDone) \
SymI_NeedsProto(mktime) \
SymI_NeedsProto(localtime) \
SymI_NeedsProto(gmtime) \
SymI_NeedsProto(opendir) \
SymI_NeedsProto(readdir) \
SymI_NeedsProto(rewinddir) \
SymI_HasProto(atexit) \
RTS_WIN32_ONLY(SymI_NeedsProto(__chkstk_ms)) \
RTS_WIN64_ONLY(SymI_NeedsProto(___chkstk_ms)) \
SymI_NeedsProto(localeconv) \
SymI_HasProto(close) \
SymI_HasProto(read) \
SymI_HasProto(dup) \
SymI_HasProto(dup2) \
SymI_HasProto(write) \
SymI_NeedsProto(getpid) \
SymI_HasProto(access) \
SymI_HasProto(chmod) \
SymI_HasProto(creat) \
SymI_HasProto(umask) \
SymI_HasProto(unlink) \
SymI_HasProto(_errno) \
SymI_NeedsProto(ftruncate64) \
SymI_HasProto(setmode) \
SymI_HasProto(_wstat64) \
SymI_HasProto(_fstat64) \
SymI_HasProto(_wsopen) \
RTS_WIN32_ONLY(SymI_HasProto(_imp___environ)) \
RTS_WIN64_ONLY(SymI_HasProto(__imp__environ)) \
RTS_WIN32_ONLY(SymI_HasProto(_imp___iob)) \
RTS_WIN64_ONLY(SymI_HasProto(__iob_func)) \
SymI_HasProto(GetFileAttributesA) \
SymI_HasProto(GetFileInformationByHandle) \
SymI_HasProto(GetFileType) \
SymI_HasProto(GetLastError) \
SymI_HasProto(QueryPerformanceFrequency) \
SymI_HasProto(QueryPerformanceCounter) \
SymI_HasProto(GetTickCount) \
SymI_HasProto(WaitForSingleObject) \
SymI_HasProto(PeekConsoleInputA) \
SymI_HasProto(ReadConsoleInputA) \
SymI_HasProto(PeekNamedPipe) \
SymI_HasProto(select) \
SymI_HasProto(isatty) \
SymI_HasProto(_get_osfhandle) \
SymI_HasProto(GetConsoleMode) \
SymI_HasProto(SetConsoleMode) \
SymI_HasProto(FlushConsoleInputBuffer) \
SymI_HasProto(free) \
SymI_NeedsProto(raise) \
SymI_NeedsProto(_getpid) \
SymI_HasProto(getc) \
SymI_HasProto(ungetc) \
SymI_HasProto(puts) \
SymI_HasProto(putc) \
SymI_HasProto(putchar) \
SymI_HasProto(fputc) \
SymI_HasProto(fread) \
SymI_HasProto(fwrite) \
SymI_HasProto(ferror) \
SymI_HasProto(printf) \
SymI_HasProto(fprintf) \
SymI_HasProto(sprintf) \
SymI_HasProto(vsprintf) \
SymI_HasProto(sscanf) \
SymI_HasProto(ldexp) \
SymI_HasProto(strlen) \
SymI_HasProto(strnlen) \
SymI_HasProto(strchr) \
SymI_HasProto(strtol) \
SymI_HasProto(strerror) \
SymI_HasProto(memchr) \
SymI_HasProto(memcmp) \
SymI_HasProto(wcscpy) \
SymI_HasProto(wcslen) \
SymI_HasProto(_lseeki64) \
SymI_HasProto(_wchmod) \
SymI_HasProto(closesocket) \
SymI_HasProto(send) \
SymI_HasProto(recv) \
SymI_HasProto(bsearch) \
SymI_HasProto(CommandLineToArgvW) \
SymI_HasProto(CreateBitmap) \
SymI_HasProto(CreateBitmapIndirect) \
SymI_HasProto(CreateCompatibleBitmap) \
SymI_HasProto(CreateDIBPatternBrushPt) \
SymI_HasProto(CreateDIBitmap) \
SymI_HasProto(SetBitmapDimensionEx) \
SymI_HasProto(GetBitmapDimensionEx) \
SymI_HasProto(GetStockObject) \
SymI_HasProto(GetObjectW) \
SymI_HasProto(DeleteObject) \
SymI_HasProto(SetDIBits) \
SymI_HasProto(GetDIBits) \
SymI_HasProto(CreateSolidBrush) \
SymI_HasProto(CreateHatchBrush) \
SymI_HasProto(CreatePatternBrush) \
SymI_HasProto(CreateFontW) \
SymI_HasProto(AngleArc) \
SymI_HasProto(Arc) \
SymI_HasProto(ArcTo) \
SymI_HasProto(BeginPath) \
SymI_HasProto(BitBlt) \
SymI_HasProto(CancelDC) \
SymI_HasProto(Chord) \
SymI_HasProto(CloseFigure) \
SymI_HasProto(CombineRgn) \
SymI_HasProto(CreateCompatibleDC) \
SymI_HasProto(CreateEllipticRgn) \
SymI_HasProto(CreateEllipticRgnIndirect) \
SymI_HasProto(CreatePen) \
SymI_HasProto(CreatePolygonRgn) \
SymI_HasProto(CreateRectRgn) \
SymI_HasProto(CreateRectRgnIndirect) \
SymI_HasProto(CreateRoundRectRgn) \
SymI_HasProto(DeleteDC) \
SymI_HasProto(Ellipse) \
SymI_HasProto(EndPath) \
SymI_HasProto(EqualRgn) \
SymI_HasProto(ExtSelectClipRgn) \
SymI_HasProto(FillPath) \
SymI_HasProto(FillRgn) \
SymI_HasProto(FlattenPath) \
SymI_HasProto(FrameRgn) \
SymI_HasProto(GetArcDirection) \
SymI_HasProto(GetBkColor) \
SymI_HasProto(GetBkMode) \
SymI_HasProto(GetBrushOrgEx) \
SymI_HasProto(GetCurrentObject) \
SymI_HasProto(GetDCOrgEx) \
SymI_HasProto(GetGraphicsMode) \
SymI_HasProto(GetMiterLimit) \
SymI_HasProto(GetPolyFillMode) \
SymI_HasProto(GetRgnBox) \
SymI_HasProto(GetStretchBltMode) \
SymI_HasProto(GetTextAlign) \
SymI_HasProto(GetTextCharacterExtra) \
SymI_HasProto(GetTextColor) \
SymI_HasProto(GetTextExtentPoint32W) \
SymI_HasProto(InvertRgn) \
SymI_HasProto(LineTo) \
SymI_HasProto(MaskBlt) \
SymI_HasProto(MoveToEx) \
SymI_HasProto(OffsetRgn) \
SymI_HasProto(PaintRgn) \
SymI_HasProto(PathToRegion) \
SymI_HasProto(Pie) \
SymI_HasProto(PlgBlt) \
SymI_HasProto(PolyBezier) \
SymI_HasProto(PolyBezierTo) \
SymI_HasProto(Polygon) \
SymI_HasProto(Polyline) \
SymI_HasProto(PolylineTo) \
SymI_HasProto(PtInRegion) \
SymI_HasProto(Rectangle) \
SymI_HasProto(RectInRegion) \
SymI_HasProto(RestoreDC) \
SymI_HasProto(RoundRect) \
SymI_HasProto(SaveDC) \
SymI_HasProto(SelectClipPath) \
SymI_HasProto(SelectClipRgn) \
SymI_HasProto(SelectObject) \