Commit ecf2f704 authored by Erick Gallesio's avatar Erick Gallesio

Added cinvoke lib and some FFI refinements

parent db9573bc
main author: Erick Gallesio <eg@unice.fr>
LURC support: Stephane Epardaud <Stephane.Epardaud@sophia.inria.fr>
main author: Erick Gallesio <eg at unice.fr>
LURC support: Stephane Epardaud <Stephane.Epardaud at sophia.inria.fr>
......@@ -2,11 +2,11 @@
#
# Author: Erick Gallesio [eg@unice.fr]
# Creation date: 11-Apr-2000 10:30 (eg)
# Last file update: 12-Feb-2007 11:23 (eg)
# Last file update: 19-Jun-2007 11:55 (eg)
EXTRA_DIST =
SUBDIRS = @PCRE@ @GC@ @GMP@ src utils lib @GTKLOS@ @EXAMPLES@ \
pkgman extensions tests doc
SUBDIRS = @PCRE@ @GC@ @GMP@ @CINVOKE@ src utils lib @GTKLOS@ \
@EXAMPLES@ pkgman extensions tests doc
SVN_URL = @SVN_URL@/STklos
VERSION_TAG = @PACKAGE@-@VERSION@
VERSION_BETA = $(VERSION_TAG)-beta
......
......@@ -18,7 +18,7 @@
#
# Author: Erick Gallesio [eg@unice.fr]
# Creation date: 11-Apr-2000 10:30 (eg)
# Last file update: 12-Feb-2007 11:23 (eg)
# Last file update: 19-Jun-2007 11:55 (eg)
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
......@@ -87,6 +87,7 @@ CALLCC_STK = @CALLCC_STK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CINVOKE = @CINVOKE@
COMPOBJ = @COMPOBJ@
COMPSRC = @COMPSRC@
CPP = @CPP@
......@@ -144,6 +145,7 @@ PCRE = @PCRE@
PCREINC = @PCREINC@
PCRELIB = @PCRELIB@
PCRETARGET = @PCRETARGET@
PERLINT = @PERLINT@
PREFIX = @PREFIX@
RANLIB = @RANLIB@
SCMDIR = @SCMDIR@
......@@ -202,8 +204,8 @@ target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
EXTRA_DIST =
SUBDIRS = @PCRE@ @GC@ @GMP@ src utils lib @GTKLOS@ @EXAMPLES@ \
pkgman extensions tests doc
SUBDIRS = @PCRE@ @GC@ @GMP@ @CINVOKE@ src utils lib @GTKLOS@ \
@EXAMPLES@ pkgman extensions tests doc
VERSION_TAG = @PACKAGE@-@VERSION@
VERSION_BETA = $(VERSION_TAG)-beta
......
......@@ -36,9 +36,15 @@ LALR: The Dominique Boucher LALR Package
- Home Page: http://www.iro.umontreal.ca/~boucherd/Lalr/documentation/lalr.html
C/INVOKE: a library for connecting to C libraries at runtime
============================================================
- Version: 1.0
- License: 3 clauses BSD
- Home Page: http://www.nongnu.org/cinvoke/index.html
+++++++++++++++++++++++++++++++++++
The GC and GMP libraries provided with STklos are only used if there
The GC, PCRE and GMP libraries provided with STklos are only used if there
are no identical (or higher) versions of these libraries already
installed on the system at configuration time.
......
C/Invoke Software Distribution
Copyright (c) 2006 Will Weisser
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
all:
cd lib && $(MAKE)
cd test && $(MAKE)
cp -f lib/arch/[ARCH_HEADER] lib/cinvoke-archspec.h
install:
install -d [PREFIX]/include
install -d [PREFIX]/lib
install lib/cinvoke.h lib/cinvoke-arch.h lib/cinvoke-archspec.h \
[PREFIX]/include
install lib/libcinvoke.a [PREFIX]/lib
uninstall:
rm -f [PREFIX]/include/cinvoke.h [PREFIX]/include/cinvoke-arch.h \
[PREFIX]/include/cinvoke-archspec.h [PREFIX]/lib/libcinvoke.a
clean:
cd lib && $(MAKE) clean
cd test && $(MAKE) clean
distclean: clean
Here are the 4 (over-simplified) steps to port C/Invoke to a new architecute:
1) copy lib/arch/empty_empty_empty.c and .h to files named
<compiler>_<cpu>_<os>.c and .h. Add an entry to the main cinvoke-arch.h
file to include your new file.
2) Implement the new arch files. Use the comments inside the empty files for
guidance, the other arch files for examples, and the cinvoke-dev mailing list
for help.
3) Get the source building. If your chosen platform is POSIX-based, you can
modify configure.pl to adapt the Makefile system to your architecture. The
build system is exquisitely simple: each directory has a Makefile.templ which
gets evaluated as a perl string and substituted with the variables in the
configure.pl script.
4) Get the test suite in the test/ directory running and spitting out the
correct values.
This directory contains a subset of the standard distribution of
C/invoke (which is available at http://www.nongnu.org/cinvoke/index.html)
The files which are not present here are th one used for the Lua and
Java bindings. Use the standard distribution if needed.
Erick Gallesio
C/Invoke: A library for invoking C functions at runtime.
Copyright (c) 2006 by Will Weisser
See LICENSE.txt for license info.
The C/Invoke homepage is:
http://www.nongnu.org/cinvoke/
Please subscribe to the cinvoke-dev mailing list, more
information at the above URL.
To build and install the library:
$ perl configure.pl --prefix=/usr/local
$ make
$ make install
The language bindings in the bindings/ directory must be built separately.
#!/usr/bin/perl
use IO::File;
use strict;
my $PREFIX = '/usr/local';
my @TARGETS = qw(Makefile lib/Makefile);
parse_args();
my $LINUX = 0;
my $SOLARIS = 0;
my $platform = determine_platform();
print "Using platform '$platform'\n";
my $BUILDARCH = '-DARCH_GCC_' . $platform;
my $CFLAGS = "-g -Wall -DCINVOKE_BUILD $BUILDARCH";
my $ARCH_HEADER = 'gcc_' . lc($platform) . '.h';
my $DYNEXT;
my $JNIDYNEXT;
my $JNIINCLUDE;
my $BUILDSHARED;
my $CXXBUILDSHARED;
my $BUILDSTATIC;
my $RANLIB;
my $DYNCFLAGS;
my $LIBDL;
# Solaris has an issue whereby all object files,
# even those compiled in static libraries, must
# have -fpic set if they will eventually be linked
# by shared libraries
if ($SOLARIS) {
$CFLAGS .= " -fpic";
}
# Linux and OSX have libdl, *BSD doesn't
if ($LINUX || $platform =~ m/_OSX$/) {
$LIBDL = '-ldl';
} else {
$LIBDL = '';
}
# OSX build environment is all wonky
if ($platform =~ m/_OSX$/) {
$DYNEXT = 'dylib';
$JNIDYNEXT = 'jnilib';
$JNIINCLUDE = '-I/System/Library/Frameworks/JavaVM.framework/Headers';
$BUILDSHARED = 'libtool -dynamic -lc -o';
$CXXBUILDSHARED = 'g++ -dynamiclib -o';
$DYNCFLAGS = '-dynamic';
$BUILDSTATIC = 'libtool -static -o';
$RANLIB = 'echo';
} else {
$DYNEXT = 'so';
$JNIDYNEXT = 'so';
my $jni_include_dir = find_jni();
if ($jni_include_dir) {
$JNIINCLUDE = "-I$jni_include_dir";
if ($SOLARIS) { $JNIINCLUDE .= " -I$jni_include_dir/solaris"; }
elsif ($LINUX) { $JNIINCLUDE .= " -I$jni_include_dir/linux"; }
} else {
$JNIINCLUDE = "";
}
$BUILDSHARED = 'gcc -shared -o';
$CXXBUILDSHARED = 'g++ -shared -o';
if ($SOLARIS) { $DYNCFLAGS = ''; }
else { $DYNCFLAGS = '-fpic'; }
$BUILDSTATIC = 'rm -f $(TARGET) && ar rs';
$RANLIB = 'ranlib';
}
my $ARCH_SOURCE = $ARCH_HEADER;
my $ARCH_OBJ = $ARCH_HEADER;
$ARCH_SOURCE =~ s/\.h$/.c/;
$ARCH_OBJ =~ s/\.h$/.o/;
foreach my $target (@TARGETS) {
process($target);
}
print "Complete.\n";
exit;
sub find_jni {
my $ret = '/usr/jdk/default/include';
if (!(-d $ret)) {
$ret = '/usr/java/default/include';
if (!(-d $ret)) {
$ret = '';
}
}
return $ret;
}
sub determine_platform {
my $processor;
my $gccout = `gcc -dumpmachine`;
if ($? != 0) { die "error executing gcc -dumpmachine: $!"; }
if ($gccout =~ m/i[3456]86/) {
$processor = 'X86';
} elsif ($gccout =~ m/x86_64/) {
$processor = 'X64';
} elsif ($gccout =~ m/ppc/) {
$processor = 'PPC';
} elsif ($gccout =~ m/sparc/) {
$processor = 'SPARC';
} else {
die "unrecognized architecture $gccout";
}
my $os;
my $uname = `uname`;
if ($? != 0) { die "error executing uname: $!"; }
if ($uname =~ m/Darwin/) {
$os = "OSX";
} else {
$os = "UNIX"; # hey why not
# specific unices
if ($uname =~ m/Linux/) {
$LINUX = 1;
} elsif ($uname =~ m/SunOS/) {
$SOLARIS = 1;
}
}
return $processor . '_' . $os;
}
sub process {
my ($ofn) = @_;
print "Writing $ofn...\n";
my $fn = $ofn . ".templ";
my $input = new IO::File("<$fn") or die "cannot open $fn: $!";
my $output = new IO::File(">$ofn") or die "cannot open $ofn: $!";
while (<$input>) {
$_ =~ s/\\/\\\\/g;
$_ =~ s/"/\\"/g;
$_ =~ s/\$/\\\$/g;
$_ =~ s/\@/\\\@/g;
$_ =~ s/\[([A-Za-z_][A-Za-z_0-9]*)\]/\$$1/g;
eval("print \$output \"$_\"");
}
$input->close();
$output->close();
}
sub parse_args {
foreach my $arg (@ARGV) {
if ($arg eq "--distclean") {
my $targets = join(" ", @TARGETS);
system("rm -f $targets");
exit;
} elsif ($arg =~ m/^--prefix=/) {
$PREFIX = substr($arg, 9);
} else {
print <<EOF;
usage: configure.pl [--prefix=<path>]
configure.pl --distclean
EOF
exit;
}
}
}
TARGET = libcinvoke.a
all: $(TARGET)
clean:
rm -f *.o arch/*.o libcinvoke.a
SRCS = cinvoke.c structure.c hashtable.c arch/[ARCH_SOURCE]
OBJS = $(SRCS:.c=.o)
$(TARGET): $(OBJS)
[BUILDSTATIC] $(TARGET) $(OBJS)
[RANLIB] $(TARGET)
.c.o:
gcc [CFLAGS] -c $< -o $@
cinvoke.o: cinvoke.c cinvoke.h cinvoke-arch.h arch/[ARCH_HEADER] \
cinvoke-private.h hashtable.h
structure.o: structure.c cinvoke.h cinvoke-arch.h arch/[ARCH_HEADER] \
cinvoke-private.h hashtable.h
hashtable.o: hashtable.c hashtable.h
arch/[ARCH_OBJ]: arch/[ARCH_HEADER] arch/../cinvoke.h \
arch/../cinvoke-arch.h \
arch/../cinvoke-private.h arch/../hashtable.h
/*
C/Invoke Source Code File
Copyright (c) 2006 Will Weisser
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef CINVOKE_BUILD
#include "../cinvoke.h"
#include "../cinvoke-private.h"
#else
#include "cinvoke.h"
#include "cinvoke-private.h"
#endif
char *GetWin32ErrMsg(DWORD err) {
char *str;
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&str, 0, NULL)) {
str = NULL;
}
return str;
}
void context_set_win32_error(CInvContext *context) {
DWORD err = GetLastError();
char *str = GetWin32ErrMsg(err);
context_set_error(context, err, str, 1);
}
void arch_free_errstr(char *str) {
LocalFree(str);
}
cinv_status_t arch_library_create(CInvContext *context, const char *path,
ArchLibrary *library_out) {
HANDLE lib = LoadLibrary(path);
if (!lib) {
context_set_win32_error(context);
return CINV_ERROR;
}
library_out->dl = lib;
return CINV_SUCCESS;
}
cinv_status_t arch_library_get_entrypoint(CInvContext *context,
ArchLibrary *library, const char *name, void **entrypoint_out) {
void *sym = GetProcAddress(library->dl, name);
if (!sym) {
context_set_win32_error(context);
return CINV_ERROR;
}
*entrypoint_out = sym;
return CINV_SUCCESS;
}
cinv_status_t arch_library_delete(CInvContext *context, ArchLibrary *library) {
if (!FreeLibrary(library->dl)) {
context_set_win32_error(context);
return CINV_ERROR;
}
return CINV_SUCCESS;
}
const static int LEN = 4096;
char *arch_callback_stub(void *functionp, void *param,
short stacksize, cinv_callconv_t cc, cinv_type_t types[], int numparams) {
int codesize;
const char *code;
char *ret;
if (cc != CINV_CC_STDCALL && cc != CINV_CC_FASTCALL) {
// void f() { ((void (__cdecl *)(void *))0xAAAAAAAA)((void *)0xBBBBBBBB); }
codesize = 31;
code = "\x55\x8b\xec\x83\xec\x40\x53\x56\x57\x68"
"\xbb\xbb\xbb\xbb\xb8\xaa\xaa\xaa\xaa\xff"
"\xd0\x83\xc4\x04\x5f\x5e\x5b\x8b\xe5\x5d"
"\xc3";
} else {
// same thing except with an additional stack-cleanup argument placeholder
// note that the below code does not modify ecx or edx, so we handle
// fastcall correctly
codesize = 33;
code = "\x55\x8b\xec\x83\xec\x40\x53\x56\x57\x68"
"\xbb\xbb\xbb\xbb\xb8\xaa\xaa\xaa\xaa\xff"
"\xd0\x83\xc4\x04\x5f\x5e\x5b\x8b\xe5\x5d"
"\xc2\xdd\xdd";
}
ret = VirtualAlloc(NULL, LEN, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!ret)
return NULL;
memcpy(ret, code, codesize);
memcpy(ret + 10, &param, 4);
memcpy(ret + 15, &functionp, 4);
if (cc == CINV_CC_STDCALL || cc == CINV_CC_FASTCALL)
memcpy(ret + 31, &stacksize, 2);
return ret;
}
void arch_free_stub(char *stub) {
VirtualFree(stub, 0, MEM_RELEASE);
}
int is_ok_register(cinv_type_t type) {
return (type != CINV_T_FLOAT) &&
(type != CINV_T_DOUBLE) &&
(type != CINV_T_EXTRALONG);
}
int arch_is_register_parm(cinv_callconv_t callingconvention, int index,
int num_params, cinv_type_t types[]) {
int numeligible = 0, i;
if (callingconvention != CINV_CC_FASTCALL) return 0;
for (i = 0; i < index; i++) {
if (is_ok_register(types[i]))
numeligible++;
if (numeligible == 2) break;
}
return (numeligible < 2 && is_ok_register(types[i]));
}
int convert_to_int(void *ptr, cinv_type_t type) {
switch (type) {
case CINV_T_CHAR:
return (int)*(char *)ptr;
case CINV_T_SHORT:
return (int)*(short *)ptr;
case CINV_T_INT:
return *(int *)ptr;
case CINV_T_LONG:
return (int)*(long *)ptr;
case CINV_T_PTR:
return (int)*(void **)ptr;
default:
return -1;
}
}
void set_from_int(void *ptr_out, cinv_type_t type, int val) {
switch (type) {
case CINV_T_CHAR:
*(char *)ptr_out = (char)val;
break;
case CINV_T_SHORT:
*(short *)ptr_out = (short)val;
break;
case CINV_T_INT:
*(int *)ptr_out = val;
break;
case CINV_T_LONG:
*(long *)ptr_out = (long)val;
break;
case CINV_T_PTR:
*(void **)ptr_out = (void *)val;
break;
default:
break;
}
}
void arch_set_register_parms(ArchRegParms *regparms,
cinv_callconv_t callingconvention, int num_params, void *parameters[],
cinv_type_t types[]) {
int numeligible = 0, i;
if (callingconvention != CINV_CC_FASTCALL) return;
for (i = 0; i < num_params; i++) {
if (is_ok_register(types[i])) {
if (numeligible == 0)
regparms->first = convert_to_int(parameters[i], types[i]);
else
regparms->second = convert_to_int(parameters[i], types[i]);
numeligible++;
}
if (numeligible == 2) break;
}
}
void arch_get_register_parms(ArchRegParms *regparms,
cinv_callconv_t callingconvention, int num_params, void *parameters_out[],
cinv_type_t types[]) {
int numeligible = 0, i;
if (callingconvention != CINV_CC_FASTCALL) return;
for (i = 0; i < num_params; i++) {
if (is_ok_register(types[i])) {
if (numeligible == 0)
set_from_int(parameters_out[i], types[i], regparms->first);
else
set_from_int(parameters_out[i], types[i], regparms->second);
numeligible++;
}
if (numeligible == 2) break;
}
}
void arch_getval_char(ArchRetValue *archval, char *outval) {
*outval = archval->ivallow;
}
void arch_getval_short(ArchRetValue *archval, short *outval) {
*outval = archval->ivallow;
}
void arch_getval_int(ArchRetValue *archval, int *outval) {
*outval = archval->ivallow;
}
void arch_getval_long(ArchRetValue *archval, long int *outval) {
*outval = archval->ivallow;
}
void arch_getval_extralong(ArchRetValue *archval, long long int *outval) {
*outval = archval->ivalhigh;
*outval <<= 32;
*outval |= archval->ivallow;
}
void arch_getval_float(ArchRetValue *archval, float *outval) {
*outval = (float)archval->dval;
}
void arch_getval_double(ArchRetValue *archval, double *outval) {
*outval = archval->dval;
}
void arch_getval_ptr(ArchRetValue *archval, void **outval) {
*outval = (void *)archval->ivallow;
}
void arch_setval_char(ArchRetValue *archval, char val) {
archval->ivallow = val;
}
void arch_setval_short(ArchRetValue *archval, short val) {
archval->ivallow = val;
}
void arch_setval_int(ArchRetValue *archval, int val) {
archval->ivallow = val;
}
void arch_setval_long(ArchRetValue *archval, long int val) {
archval->ivallow = val;
}
void arch_setval_extralong(ArchRetValue *archval, long long int val) {
archval->ivalhigh = (int)(val >> 32);
archval->ivallow = (int)val;
}
void arch_setval_float(ArchRetValue *archval, float val) {
archval->dval = val;
}
void arch_setval_double(ArchRetValue *archval, double val) {
archval->dval = val;
}
void arch_setval_ptr(ArchRetValue *archval, void *val) {
archval->ivallow = (int)val;
}
void arch_size_char(int *stacksize_out, int *structsize_out,
int *structalign_out) {
*stacksize_out = 4;
*structsize_out = 1;
}
void arch_size_short(int *stacksize_out, int *structsize_out,
int *structalign_out) {
*stacksize_out = 4;
*structsize_out = 2;
*structalign_out = 2;
}
void arch_size_int(int *stacksize_out, int *structsize_out,
int *structalign_out) {
*stacksize_out = 4;
*structsize_out = 4;
*structalign_out = 4;
}
void arch_size_long(int *stacksize_out, int *structsize_out,
int *structalign_out) {
*stacksize_out = 4;
*structsize_out = 4;
*structalign_out = 4;
}
void arch_size_extralong(int *stacksize_out, int *structsize_out,
int *structalign_out) {
*stacksize_out = 8;
*structsize_out = 8;
*structalign_out = 8;
}
void arch_size_float(int *stacksize_out, int *structsize_out,
int *structalign_out) {
*stacksize_out = 4;
*structsize_out = 4;
*structalign_out = 4;
}
void arch_size_double(int *stacksize_out, int *structsize_out,
int *structalign_out) {
*stacksize_out = 8;
*structsize_out = 8;
*structalign_out = 8;
}
void arch_size_ptr(int *stacksize_out, int *structsize_out,
int *structalign_out) {
*stacksize_out = 4;
*structsize_out = 4;
*structalign_out = 4;
}
/*
C/Invoke Source Code File
Copyright (c) 2006 Will Weisser
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED