1 //===-- ExternalFunctions.cpp - Implement External Functions --------------===//
3 // The LLVM Compiler Infrastructure
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains both code to deal with invoking "external" functions, but
11 // also contains code that implements "exported" external functions.
13 // External functions in the interpreter are implemented by
14 // using the system's dynamic loader to look up the address of the function
15 // we want to invoke. If a function is found, then one of the
16 // many lle_* wrapper functions in this file will translate its arguments from
17 // GenericValues to the types the function is actually expecting, before the
18 // function is called.
20 //===----------------------------------------------------------------------===//
22 #include "Interpreter.h"
23 #include "llvm/DerivedTypes.h"
24 #include "llvm/Module.h"
25 #include "llvm/Target/TargetData.h"
26 #include "Support/DynamicLinker.h"
27 #include "Config/dlfcn.h"
28 #include "Config/link.h"
36 typedef GenericValue (*ExFunc)(FunctionType *, const vector<GenericValue> &);
37 static std::map<const Function *, ExFunc> Functions;
38 static std::map<std::string, ExFunc> FuncNames;
40 static Interpreter *TheInterpreter;
42 static char getTypeID(const Type *Ty) {
43 switch (Ty->getPrimitiveID()) {
44 case Type::VoidTyID: return 'V';
45 case Type::BoolTyID: return 'o';
46 case Type::UByteTyID: return 'B';
47 case Type::SByteTyID: return 'b';
48 case Type::UShortTyID: return 'S';
49 case Type::ShortTyID: return 's';
50 case Type::UIntTyID: return 'I';
51 case Type::IntTyID: return 'i';
52 case Type::ULongTyID: return 'L';
53 case Type::LongTyID: return 'l';
54 case Type::FloatTyID: return 'F';
55 case Type::DoubleTyID: return 'D';
56 case Type::PointerTyID: return 'P';
57 case Type::FunctionTyID: return 'M';
58 case Type::StructTyID: return 'T';
59 case Type::ArrayTyID: return 'A';
60 case Type::OpaqueTyID: return 'O';
65 static ExFunc lookupFunction(const Function *F) {
66 // Function not found, look it up... start by figuring out what the
67 // composite function name should be.
68 std::string ExtName = "lle_";
69 const FunctionType *FT = F->getFunctionType();
70 for (unsigned i = 0, e = FT->getNumContainedTypes(); i != e; ++i)
71 ExtName += getTypeID(FT->getContainedType(i));
72 ExtName += "_" + F->getName();
74 ExFunc FnPtr = FuncNames[ExtName];
76 FnPtr = (ExFunc)GetAddressOfSymbol(ExtName);
78 FnPtr = FuncNames["lle_X_"+F->getName()];
79 if (FnPtr == 0) // Try calling a generic function... if it exists...
80 FnPtr = (ExFunc)GetAddressOfSymbol(("lle_X_"+F->getName()).c_str());
82 Functions.insert(std::make_pair(F, FnPtr)); // Cache for later
86 GenericValue Interpreter::callExternalFunction(Function *M,
87 const std::vector<GenericValue> &ArgVals) {
88 TheInterpreter = this;
90 // Do a lookup to see if the function is in our cache... this should just be a
91 // deferred annotation!
92 std::map<const Function *, ExFunc>::iterator FI = Functions.find(M);
93 ExFunc Fn = (FI == Functions.end()) ? lookupFunction(M) : FI->second;
95 std::cout << "Tried to execute an unknown external function: "
96 << M->getType()->getDescription() << " " << M->getName() << "\n";
97 return GenericValue();
100 // TODO: FIXME when types are not const!
101 GenericValue Result = Fn(const_cast<FunctionType*>(M->getFunctionType()),
107 //===----------------------------------------------------------------------===//
108 // Functions "exported" to the running application...
110 extern "C" { // Don't add C++ manglings to llvm mangling :)
112 // void putchar(sbyte)
113 GenericValue lle_Vb_putchar(FunctionType *M, const vector<GenericValue> &Args) {
114 std::cout << Args[0].SByteVal;
115 return GenericValue();
119 GenericValue lle_ii_putchar(FunctionType *M, const vector<GenericValue> &Args) {
120 std::cout << ((char)Args[0].IntVal) << std::flush;
124 // void putchar(ubyte)
125 GenericValue lle_VB_putchar(FunctionType *M, const vector<GenericValue> &Args) {
126 std::cout << Args[0].SByteVal << std::flush;
130 // void atexit(Function*)
131 GenericValue lle_X_atexit(FunctionType *M, const vector<GenericValue> &Args) {
132 assert(Args.size() == 1);
133 TheInterpreter->addAtExitHandler((Function*)GVTOP(Args[0]));
140 GenericValue lle_X_exit(FunctionType *M, const vector<GenericValue> &Args) {
141 TheInterpreter->exitCalled(Args[0]);
142 return GenericValue();
146 GenericValue lle_X_abort(FunctionType *M, const vector<GenericValue> &Args) {
148 return GenericValue();
151 // void *malloc(uint)
152 GenericValue lle_X_malloc(FunctionType *M, const vector<GenericValue> &Args) {
153 assert(Args.size() == 1 && "Malloc expects one argument!");
154 return PTOGV(malloc(Args[0].UIntVal));
157 // void *calloc(uint, uint)
158 GenericValue lle_X_calloc(FunctionType *M, const vector<GenericValue> &Args) {
159 assert(Args.size() == 2 && "calloc expects two arguments!");
160 return PTOGV(calloc(Args[0].UIntVal, Args[1].UIntVal));
164 GenericValue lle_X_free(FunctionType *M, const vector<GenericValue> &Args) {
165 assert(Args.size() == 1);
166 free(GVTOP(Args[0]));
167 return GenericValue();
171 GenericValue lle_X_atoi(FunctionType *M, const vector<GenericValue> &Args) {
172 assert(Args.size() == 1);
174 GV.IntVal = atoi((char*)GVTOP(Args[0]));
178 // double pow(double, double)
179 GenericValue lle_X_pow(FunctionType *M, const vector<GenericValue> &Args) {
180 assert(Args.size() == 2);
182 GV.DoubleVal = pow(Args[0].DoubleVal, Args[1].DoubleVal);
186 // double exp(double)
187 GenericValue lle_X_exp(FunctionType *M, const vector<GenericValue> &Args) {
188 assert(Args.size() == 1);
190 GV.DoubleVal = exp(Args[0].DoubleVal);
194 // double sqrt(double)
195 GenericValue lle_X_sqrt(FunctionType *M, const vector<GenericValue> &Args) {
196 assert(Args.size() == 1);
198 GV.DoubleVal = sqrt(Args[0].DoubleVal);
202 // double log(double)
203 GenericValue lle_X_log(FunctionType *M, const vector<GenericValue> &Args) {
204 assert(Args.size() == 1);
206 GV.DoubleVal = log(Args[0].DoubleVal);
210 // double floor(double)
211 GenericValue lle_X_floor(FunctionType *M, const vector<GenericValue> &Args) {
212 assert(Args.size() == 1);
214 GV.DoubleVal = floor(Args[0].DoubleVal);
219 GenericValue lle_X_drand48(FunctionType *M, const vector<GenericValue> &Args) {
220 assert(Args.size() == 0);
222 GV.DoubleVal = drand48();
227 GenericValue lle_X_lrand48(FunctionType *M, const vector<GenericValue> &Args) {
228 assert(Args.size() == 0);
230 GV.IntVal = lrand48();
234 // void srand48(long)
235 GenericValue lle_X_srand48(FunctionType *M, const vector<GenericValue> &Args) {
236 assert(Args.size() == 1);
237 srand48(Args[0].IntVal);
238 return GenericValue();
242 GenericValue lle_X_srand(FunctionType *M, const vector<GenericValue> &Args) {
243 assert(Args.size() == 1);
244 srand(Args[0].UIntVal);
245 return GenericValue();
248 // int puts(const char*)
249 GenericValue lle_X_puts(FunctionType *M, const vector<GenericValue> &Args) {
250 assert(Args.size() == 1);
252 GV.IntVal = puts((char*)GVTOP(Args[0]));
256 // int sprintf(sbyte *, sbyte *, ...) - a very rough implementation to make
258 GenericValue lle_X_sprintf(FunctionType *M, const vector<GenericValue> &Args) {
259 char *OutputBuffer = (char *)GVTOP(Args[0]);
260 const char *FmtStr = (const char *)GVTOP(Args[1]);
263 // printf should return # chars printed. This is completely incorrect, but
264 // close enough for now.
265 GenericValue GV; GV.IntVal = strlen(FmtStr);
268 case 0: return GV; // Null terminator...
269 default: // Normal nonspecial character
270 sprintf(OutputBuffer++, "%c", *FmtStr++);
272 case '\\': { // Handle escape codes
273 sprintf(OutputBuffer, "%c%c", *FmtStr, *(FmtStr+1));
274 FmtStr += 2; OutputBuffer += 2;
277 case '%': { // Handle format specifiers
278 char FmtBuf[100] = "", Buffer[1000] = "";
281 char Last = *FB++ = *FmtStr++;
282 unsigned HowLong = 0;
283 while (Last != 'c' && Last != 'd' && Last != 'i' && Last != 'u' &&
284 Last != 'o' && Last != 'x' && Last != 'X' && Last != 'e' &&
285 Last != 'E' && Last != 'g' && Last != 'G' && Last != 'f' &&
286 Last != 'p' && Last != 's' && Last != '%') {
287 if (Last == 'l' || Last == 'L') HowLong++; // Keep track of l's
288 Last = *FB++ = *FmtStr++;
294 sprintf(Buffer, FmtBuf); break;
296 sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal); break;
302 TheInterpreter->getModule().getPointerSize()==Module::Pointer64 &&
303 sizeof(long) < sizeof(long long)) {
304 // Make sure we use %lld with a 64 bit argument because we might be
305 // compiling LLI on a 32 bit compiler.
306 unsigned Size = strlen(FmtBuf);
307 FmtBuf[Size] = FmtBuf[Size-1];
309 FmtBuf[Size-1] = 'l';
311 sprintf(Buffer, FmtBuf, Args[ArgNo++].ULongVal);
313 sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal); break;
314 case 'e': case 'E': case 'g': case 'G': case 'f':
315 sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break;
317 sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break;
319 sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break;
320 default: std::cout << "<unknown printf code '" << *FmtStr << "'!>";
323 strcpy(OutputBuffer, Buffer);
324 OutputBuffer += strlen(Buffer);
331 // int printf(sbyte *, ...) - a very rough implementation to make output useful.
332 GenericValue lle_X_printf(FunctionType *M, const vector<GenericValue> &Args) {
334 vector<GenericValue> NewArgs;
335 NewArgs.push_back(PTOGV(Buffer));
336 NewArgs.insert(NewArgs.end(), Args.begin(), Args.end());
337 GenericValue GV = lle_X_sprintf(M, NewArgs);
342 static void ByteswapSCANFResults(const char *Fmt, void *Arg0, void *Arg1,
343 void *Arg2, void *Arg3, void *Arg4, void *Arg5,
344 void *Arg6, void *Arg7, void *Arg8) {
345 void *Args[] = { Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, 0 };
347 // Loop over the format string, munging read values as appropriate (performs
348 // byteswaps as necessary).
352 // Read any flag characters that may be present...
353 bool Suppress = false;
356 bool LongLong = false; // long long or long double
360 case '*': Suppress = true; break;
361 case 'a': /*Allocate = true;*/ break; // We don't need to track this
362 case 'h': Half = true; break;
363 case 'l': Long = true; break;
365 case 'L': LongLong = true; break;
367 if (Fmt[-1] > '9' || Fmt[-1] < '0') // Ignore field width specs
373 // Read the conversion character
374 if (!Suppress && Fmt[-1] != '%') { // Nothing to do?
379 case 'i': case 'o': case 'u': case 'x': case 'X': case 'n': case 'p':
381 if (Long || LongLong) {
382 Size = 8; Ty = Type::ULongTy;
384 Size = 4; Ty = Type::UShortTy;
386 Size = 4; Ty = Type::UIntTy;
390 case 'e': case 'g': case 'E':
392 if (Long || LongLong) {
393 Size = 8; Ty = Type::DoubleTy;
395 Size = 4; Ty = Type::FloatTy;
399 case 's': case 'c': case '[': // No byteswap needed
409 void *Arg = Args[ArgNo++];
410 memcpy(&GV, Arg, Size);
411 TheInterpreter->StoreValueToMemory(GV, (GenericValue*)Arg, Ty);
418 // int sscanf(const char *format, ...);
419 GenericValue lle_X_sscanf(FunctionType *M, const vector<GenericValue> &args) {
420 assert(args.size() < 10 && "Only handle up to 10 args to sscanf right now!");
423 for (unsigned i = 0; i < args.size(); ++i)
424 Args[i] = (char*)GVTOP(args[i]);
427 GV.IntVal = sscanf(Args[0], Args[1], Args[2], Args[3], Args[4],
428 Args[5], Args[6], Args[7], Args[8], Args[9]);
429 ByteswapSCANFResults(Args[1], Args[2], Args[3], Args[4],
430 Args[5], Args[6], Args[7], Args[8], Args[9], 0);
434 // int scanf(const char *format, ...);
435 GenericValue lle_X_scanf(FunctionType *M, const vector<GenericValue> &args) {
436 assert(args.size() < 10 && "Only handle up to 10 args to scanf right now!");
439 for (unsigned i = 0; i < args.size(); ++i)
440 Args[i] = (char*)GVTOP(args[i]);
443 GV.IntVal = scanf(Args[0], Args[1], Args[2], Args[3], Args[4],
444 Args[5], Args[6], Args[7], Args[8], Args[9]);
445 ByteswapSCANFResults(Args[0], Args[1], Args[2], Args[3], Args[4],
446 Args[5], Args[6], Args[7], Args[8], Args[9]);
451 // int clock(void) - Profiling implementation
452 GenericValue lle_i_clock(FunctionType *M, const vector<GenericValue> &Args) {
453 extern int clock(void);
454 GenericValue GV; GV.IntVal = clock();
459 //===----------------------------------------------------------------------===//
460 // String Functions...
461 //===----------------------------------------------------------------------===//
463 // int strcmp(const char *S1, const char *S2);
464 GenericValue lle_X_strcmp(FunctionType *M, const vector<GenericValue> &Args) {
465 assert(Args.size() == 2);
467 Ret.IntVal = strcmp((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]));
471 // char *strcat(char *Dest, const char *src);
472 GenericValue lle_X_strcat(FunctionType *M, const vector<GenericValue> &Args) {
473 assert(Args.size() == 2);
474 return PTOGV(strcat((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1])));
477 // char *strcpy(char *Dest, const char *src);
478 GenericValue lle_X_strcpy(FunctionType *M, const vector<GenericValue> &Args) {
479 assert(Args.size() == 2);
480 return PTOGV(strcpy((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1])));
483 static GenericValue size_t_to_GV (size_t n) {
485 if (sizeof (size_t) == sizeof (uint64_t)) {
488 assert (sizeof (size_t) == sizeof (unsigned int));
494 static size_t GV_to_size_t (GenericValue GV) {
496 if (sizeof (size_t) == sizeof (uint64_t)) {
499 assert (sizeof (size_t) == sizeof (unsigned int));
505 // size_t strlen(const char *src);
506 GenericValue lle_X_strlen(FunctionType *M, const vector<GenericValue> &Args) {
507 assert(Args.size() == 1);
508 size_t strlenResult = strlen ((char *) GVTOP (Args[0]));
509 return size_t_to_GV (strlenResult);
512 // char *strdup(const char *src);
513 GenericValue lle_X_strdup(FunctionType *M, const vector<GenericValue> &Args) {
514 assert(Args.size() == 1);
515 return PTOGV(strdup((char*)GVTOP(Args[0])));
518 // char *__strdup(const char *src);
519 GenericValue lle_X___strdup(FunctionType *M, const vector<GenericValue> &Args) {
520 assert(Args.size() == 1);
521 return PTOGV(strdup((char*)GVTOP(Args[0])));
524 // void *memset(void *S, int C, size_t N)
525 GenericValue lle_X_memset(FunctionType *M, const vector<GenericValue> &Args) {
526 assert(Args.size() == 3);
527 size_t count = GV_to_size_t (Args[2]);
528 return PTOGV(memset(GVTOP(Args[0]), Args[1].IntVal, count));
531 // void *memcpy(void *Dest, void *src, size_t Size);
532 GenericValue lle_X_memcpy(FunctionType *M, const vector<GenericValue> &Args) {
533 assert(Args.size() == 3);
534 size_t count = GV_to_size_t (Args[2]);
535 return PTOGV(memcpy((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]), count));
538 //===----------------------------------------------------------------------===//
540 //===----------------------------------------------------------------------===//
542 // getFILE - Turn a pointer in the host address space into a legit pointer in
543 // the interpreter address space. This is an identity transformation.
544 #define getFILE(ptr) ((FILE*)ptr)
546 // FILE *fopen(const char *filename, const char *mode);
547 GenericValue lle_X_fopen(FunctionType *M, const vector<GenericValue> &Args) {
548 assert(Args.size() == 2);
549 return PTOGV(fopen((const char *)GVTOP(Args[0]),
550 (const char *)GVTOP(Args[1])));
553 // int fclose(FILE *F);
554 GenericValue lle_X_fclose(FunctionType *M, const vector<GenericValue> &Args) {
555 assert(Args.size() == 1);
557 GV.IntVal = fclose(getFILE(GVTOP(Args[0])));
561 // int feof(FILE *stream);
562 GenericValue lle_X_feof(FunctionType *M, const vector<GenericValue> &Args) {
563 assert(Args.size() == 1);
566 GV.IntVal = feof(getFILE(GVTOP(Args[0])));
570 // size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
571 GenericValue lle_X_fread(FunctionType *M, const vector<GenericValue> &Args) {
572 assert(Args.size() == 4);
575 result = fread((void*)GVTOP(Args[0]), GV_to_size_t (Args[1]),
576 GV_to_size_t (Args[2]), getFILE(GVTOP(Args[3])));
577 return size_t_to_GV (result);
580 // size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);
581 GenericValue lle_X_fwrite(FunctionType *M, const vector<GenericValue> &Args) {
582 assert(Args.size() == 4);
585 result = fwrite((void*)GVTOP(Args[0]), GV_to_size_t (Args[1]),
586 GV_to_size_t (Args[2]), getFILE(GVTOP(Args[3])));
587 return size_t_to_GV (result);
590 // char *fgets(char *s, int n, FILE *stream);
591 GenericValue lle_X_fgets(FunctionType *M, const vector<GenericValue> &Args) {
592 assert(Args.size() == 3);
593 return GVTOP(fgets((char*)GVTOP(Args[0]), Args[1].IntVal,
594 getFILE(GVTOP(Args[2]))));
597 // FILE *freopen(const char *path, const char *mode, FILE *stream);
598 GenericValue lle_X_freopen(FunctionType *M, const vector<GenericValue> &Args) {
599 assert(Args.size() == 3);
600 return PTOGV(freopen((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]),
601 getFILE(GVTOP(Args[2]))));
604 // int fflush(FILE *stream);
605 GenericValue lle_X_fflush(FunctionType *M, const vector<GenericValue> &Args) {
606 assert(Args.size() == 1);
608 GV.IntVal = fflush(getFILE(GVTOP(Args[0])));
612 // int getc(FILE *stream);
613 GenericValue lle_X_getc(FunctionType *M, const vector<GenericValue> &Args) {
614 assert(Args.size() == 1);
616 GV.IntVal = getc(getFILE(GVTOP(Args[0])));
620 // int _IO_getc(FILE *stream);
621 GenericValue lle_X__IO_getc(FunctionType *F, const vector<GenericValue> &Args) {
622 return lle_X_getc(F, Args);
625 // int fputc(int C, FILE *stream);
626 GenericValue lle_X_fputc(FunctionType *M, const vector<GenericValue> &Args) {
627 assert(Args.size() == 2);
629 GV.IntVal = fputc(Args[0].IntVal, getFILE(GVTOP(Args[1])));
633 // int ungetc(int C, FILE *stream);
634 GenericValue lle_X_ungetc(FunctionType *M, const vector<GenericValue> &Args) {
635 assert(Args.size() == 2);
637 GV.IntVal = ungetc(Args[0].IntVal, getFILE(GVTOP(Args[1])));
641 // int fprintf(FILE *,sbyte *, ...) - a very rough implementation to make output
643 GenericValue lle_X_fprintf(FunctionType *M, const vector<GenericValue> &Args) {
644 assert(Args.size() >= 2);
646 vector<GenericValue> NewArgs;
647 NewArgs.push_back(PTOGV(Buffer));
648 NewArgs.insert(NewArgs.end(), Args.begin()+1, Args.end());
649 GenericValue GV = lle_X_sprintf(M, NewArgs);
651 fputs(Buffer, getFILE(GVTOP(Args[0])));
658 void Interpreter::initializeExternalFunctions() {
659 FuncNames["lle_Vb_putchar"] = lle_Vb_putchar;
660 FuncNames["lle_ii_putchar"] = lle_ii_putchar;
661 FuncNames["lle_VB_putchar"] = lle_VB_putchar;
662 FuncNames["lle_X_exit"] = lle_X_exit;
663 FuncNames["lle_X_abort"] = lle_X_abort;
664 FuncNames["lle_X_malloc"] = lle_X_malloc;
665 FuncNames["lle_X_calloc"] = lle_X_calloc;
666 FuncNames["lle_X_free"] = lle_X_free;
667 FuncNames["lle_X_atoi"] = lle_X_atoi;
668 FuncNames["lle_X_pow"] = lle_X_pow;
669 FuncNames["lle_X_exp"] = lle_X_exp;
670 FuncNames["lle_X_log"] = lle_X_log;
671 FuncNames["lle_X_floor"] = lle_X_floor;
672 FuncNames["lle_X_srand"] = lle_X_srand;
673 FuncNames["lle_X_drand48"] = lle_X_drand48;
674 FuncNames["lle_X_srand48"] = lle_X_srand48;
675 FuncNames["lle_X_lrand48"] = lle_X_lrand48;
676 FuncNames["lle_X_sqrt"] = lle_X_sqrt;
677 FuncNames["lle_X_puts"] = lle_X_puts;
678 FuncNames["lle_X_printf"] = lle_X_printf;
679 FuncNames["lle_X_sprintf"] = lle_X_sprintf;
680 FuncNames["lle_X_sscanf"] = lle_X_sscanf;
681 FuncNames["lle_X_scanf"] = lle_X_scanf;
682 FuncNames["lle_i_clock"] = lle_i_clock;
684 FuncNames["lle_X_strcmp"] = lle_X_strcmp;
685 FuncNames["lle_X_strcat"] = lle_X_strcat;
686 FuncNames["lle_X_strcpy"] = lle_X_strcpy;
687 FuncNames["lle_X_strlen"] = lle_X_strlen;
688 FuncNames["lle_X___strdup"] = lle_X___strdup;
689 FuncNames["lle_X_memset"] = lle_X_memset;
690 FuncNames["lle_X_memcpy"] = lle_X_memcpy;
692 FuncNames["lle_X_fopen"] = lle_X_fopen;
693 FuncNames["lle_X_fclose"] = lle_X_fclose;
694 FuncNames["lle_X_feof"] = lle_X_feof;
695 FuncNames["lle_X_fread"] = lle_X_fread;
696 FuncNames["lle_X_fwrite"] = lle_X_fwrite;
697 FuncNames["lle_X_fgets"] = lle_X_fgets;
698 FuncNames["lle_X_fflush"] = lle_X_fflush;
699 FuncNames["lle_X_fgetc"] = lle_X_getc;
700 FuncNames["lle_X_getc"] = lle_X_getc;
701 FuncNames["lle_X__IO_getc"] = lle_X__IO_getc;
702 FuncNames["lle_X_fputc"] = lle_X_fputc;
703 FuncNames["lle_X_ungetc"] = lle_X_ungetc;
704 FuncNames["lle_X_fprintf"] = lle_X_fprintf;
705 FuncNames["lle_X_freopen"] = lle_X_freopen;