Showing posts with label Windows. Show all posts
Showing posts with label Windows. Show all posts

Monday, September 24, 2007

Windows SEH Revisited

It turns out there are Win32 API calls to set up a structured exception handler (SEH) on Windows NT, which is easier and more reliable to use than inline assembly. To install an exception handler, call AddVectoredExceptionHandler. An exception handler gets passed a PEXCEPTION_POINTERS struct, which is a PEXCEPTION_RECORD and a CONTEXT*, both of which are defined in the header files. The context structure is different on every platform because it lists the contents of the CPU registers at the time of the exception, while the ExceptionRecord struct is the same, and contains the ExceptionCode and the address where it occurred (in ExceptionInformation[1]).

The job of the exception handler is to determine where program execution should proceed after it returns. For Factor, the errors we handle are memory access errors, which happen when a stack overflows or underflows and hits a guard page, division by zero, and 'any other error'. We can't just jump to these Factor exception handlers inside the Win32 exception handler, but we can set the instruction pointer, the EIP register, to our handler and return EXCEPTION_CONTINUE_EXECUTION. In this way, we can let the operating system catch errors and report them to the user as "Data stack underflow", "Division by zero", and continue running Factor without expensive checks for each memory access or division.

The stack pointer at the time of the exception is also important. If we were executing compiled Factor code, as determined by checking the fault address against the C predicate in_code_heap_p, then we set a global with this address to continue execution after the exception is handled. However, if we are in C code, then the global is left as NULL.

Here is the code--much cleaner, and more correct, than before.

void c_to_factor_toplevel(CELL quot)
{
AddVectoredExceptionHandler(0, (void*)exception_handler);
c_to_factor(quot);
RemoveVectoredExceptionHandler((void*)exception_handler);
}

long exception_handler(PEXCEPTION_POINTERS pe)
{
PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)pe->ExceptionRecord;
CONTEXT *c = (CONTEXT*)pe->ContextRecord;

if(in_code_heap_p(c->Eip))
signal_callstack_top = (void*)c->Esp;
else
signal_callstack_top = NULL;

if(e->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
signal_fault_addr = e->ExceptionInformation[1];
c->Eip = (CELL)memory_signal_handler_impl;
}
else if(e->ExceptionCode == EXCEPTION_FLT_DIVIDE_BY_ZERO
|| e->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
{
signal_number = ERROR_DIVIDE_BY_ZERO;
c->Eip = (CELL)divide_by_zero_signal_handler_impl;
}
else
{
signal_number = 11;
c->Eip = (CELL)misc_signal_handler_impl;
}

return EXCEPTION_CONTINUE_EXECUTION;
}

void memory_signal_handler_impl(void)
{
memory_protection_error(signal_fault_addr,signal_callstack_top);
}

void divide_by_zero_signal_handler_impl(void)
{
general_error(ERROR_DIVIDE_BY_ZERO,F,F,signal_callstack_top);
}

void misc_signal_handler_impl(void)
{
signal_error(signal_number,signal_callstack_top);
}

Thursday, April 12, 2007

Building Factor in Cygwin now supported

Factor has only compiled on MinGW since we made the Windows Factor port a couple of years ago. The problem with Cygwin has been its dependence on cygwin1.dll, which slows your program. Also, the Cygwin installer doesn't add it to your path, so that is one more step (and not standard). Additionally, structured exception handling (SEH) works the first time but hangs on the second time it triggers with the dll, e.g. on the second stack underflow.

However, Eric Mertens, a new Factor user, found a compiler flag to disable cygwin.dll:
-mno-cygwin

Three cheers for new users!

This flag fixed both the dll dependency and the SEH bug, allowing all unit tests to pass. The only other change I had to make for the port was to #include <wchar.h> for the compiler to find wcslen().

So now you can compile Factor with either MinGW or Cygwin, and both versions are officially supported.

Tuesday, November 14, 2006

Compiling Factor on Windows

To compile Factor you will need:

  • MinGW
  • MSYS
  • darcs
  • freetype6.dll
  • zlib1.dll


  1. Download MinGW and install it.


  2. Download MSYS and install it. Make sure to tell the batch script about your MinGW install.


  3. Download the latest package version of darcs and unzip it to c:\darcsdir-w32. darcs 1.0.7 is broken on Windows, so you must also grab the 1.0.8 binary and copy it into your darcs install directory over the broken version.


  4. Set your path to include darcs. Run:
    start->Control Panel->System->Advanced->Environment Variables

    In System Variables, edit PATH, and append c:\darcsdir-w32 so that your path resembles:
    c:\Program Files\sqlite;c:\darcsdir-w32

    Start cmd.exe from the Run box and try out your darcs installation:
    C:\Documents and Settings\Administrator>darcs --version
    1.0.8 (release)


  5. (Optional) To push patches to a remote server, you will need to generate an RSA key with puttygen unless you already have a public key. Run puttygen (installed with the darcs bundle), click generate, and move the mouse around to make your key. Save both your public and private keys in c:\darcsdir-w32. Adding a passphrase is optional (I didn't do it).


  6. (Optional) On your remote Linux box running sshd, edit the file ~/.ssh/authorized_keys2 and paste your public key so that it looks something like this (but all on one line):

    ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAgMPa1vvlSi4ZrS7hrk/XJNwd9trM+TyvJjhkMzf3fhks
    n8TFin7dhrRfFhVdjka0ep0+RGJrUI/ja6nDyG2SvzG1ka5Ml/Nes2PtpHWcwK7fwU9gBUZNzlvXCkOk
    UKO7X7N65LnyCPjJDZa+8LPqrBeESjbVmstG4cw7uh0= doug@windows


  7. (Optional) So that darcs can find your key, start Regedit and add a key for Pageant:
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
    Name: Pageant
    Data: c:\darcsdir-w32\pageant.exe c:\darcsdir-w32\private.ppk

    When you reboot or run the above command, pageant will find your key and you can begin using darcs to push patches to your Linux box.


  8. To get the Factor source, run this command wherever you want your local copy, perhaps from c:\:
    darcs get http://factorcode.org/repos


  9. Additionally, put these dlls in your Factor directory (repos/Factor/ on a default checkout):
    freetype6.dll
    zlib1.dll


  10. Start MSYS (the blue M link) and change to your Factor directory. Mine is at c:\repos\Factor, so the command is:
    cd /c/repos/Factor


  11. From here you should be able to
    make windows


  12. From cmd.exe, change to the Factor directory and bootstrap with an image (x86) from factorcode.org:
    f -i=boot.image.x86


Now you can run Factor!

f

I recommend bootstrapping and running Factor from cmd.exe because MSYS messes up stderr--you will not notice for a while if Factor has an internal error because there will be no output.

As a final note, the latest version from darcs is usually the best. If the boot image of Factor is stale and bootstrap fails, contact one of the devs in #concatenative on irc.freenode.org.

Happy Windows Factoring!

Update: Troubleshooting

Q: When starting Factor, why do I get the error 'alien-invoke-error-library "freetype", alien-invoke-error-symbol "FT_Init_FreeType"'?

A: You forgot to put freetype6.dll and zlib1.dll in the Factor directory. Download these and bootstrap again.

Q: When I bootstrap, why does Factor spew "*** Data GC (5 minor, 24 cards)" and error out with 'Word not found in current vocabulary search path delegate f no-word-name "\u000c"'?

A: On bootstrap you must pass the '-i' command line argument. The correct command line is:

./f -i=boot.image.x86