int module_import0(module_t *Module, const char *Symbol, int *IsRef, void **Data) { //pthread_t Thread = pthread_self(); //printf("<thread @ %x> Entering module_import0:%d(%s, %s)\n", Thread, __LINE__, Module->Name, Symbol); pthread_mutex_lock(Module->Lock); export_t *Export = stringtable_get(Module->Symbols, Symbol); if (Export) { *IsRef = Export->IsRef; *Data = Export->Data; pthread_mutex_unlock(Module->Lock); //printf("<thread @ %x> Leaving module_import0:%d(%s, %s)\n", Thread, __LINE__, Module->Name, Symbol); return 1; }; Symbol = GC_STRDUP(Symbol); for (module_provider_t *Provider = Module->Providers; Provider; Provider = Provider->Next) { if (!Provider->HasImports) continue; if (Provider->ImportFunc == directory_import) continue; if (Provider->ImportFunc(Provider->ImportInfo, Symbol, IsRef, Data)) { export_t *Export = new(export_t); Export->IsRef = *IsRef; Export->Data = *Data; stringtable_put(Module->Symbols, Symbol, Export); pthread_mutex_unlock(Module->Lock); //printf("<thread @ %x> Leaving module_import0:%d(%s, %s)\n", Thread, __LINE__, Module->Name, Symbol); return 1; }; }; pthread_mutex_unlock(Module->Lock); //printf("<thread @ %x> Leaving module_import0:%d(%s, %s)\n", Thread, __LINE__, Module->Name, Symbol); return 0; };
module_t *module_load(const char *Path, const char *File) { log_writef("Loading %s, path = %s.\n", File, Path); if (Path) return module_load_internal(Path, File, 0); //pthread_t Thread = pthread_self(); //printf("<thread @ %x> Entering module_load:%d(%s, %s)\n", Thread, __LINE__, Path, File); const char *Alias = path_join("library:", File); pthread_mutex_lock(LibRivaMutex); module_t *Module = stringtable_get(Modules, Alias); pthread_mutex_unlock(LibRivaMutex); if (Module) { module_reload(Module); //printf("Found module %s = 0x%x\n", Alias, Module); //printf("<thread @ %x> Leaving module_load:%d(%s, %s)\n", Thread, __LINE__, Path, File); return Module; }; for (path_node *Path = ModuleLibrary; Path; Path = Path->Next) { Module = module_load_internal(Path->Dir, File, Alias); if (Module) { //printf("<thread @ %x> Leaving module_load:%d(%s, %s)\n", Thread, __LINE__, Path, File); return Module; }; }; //printf("<thread @ %x> Leaving module_load:%d(%s, %s)\n", Thread, __LINE__, Path, File); return 0; };
static void *check_import(riva_t *Riva, const char *Symbol, jmp_buf *OnError) { const export_t *Export = stringtable_get(Riva->Exports, Symbol); if (Export) { void *Data = Export->Section->Data + Export->Offset; Export->Section->Fixup(Export->Section, OnError); return Data; } else { return 0; }; };
static void symbols_section_relocate(symbols_section_t *Section, relocation_t *Relocation, uint32_t *Target) { const char *Name = Section->Symbols + *Target; *Target = 0; section_t *Symbol = (section_t *)stringtable_get(SymbolTable, Name); if (!Symbol) { Name = strdup(Name); Symbol = (section_t *)new_symbol_section(Name); stringtable_put(SymbolTable, Name, Symbol); }; section_require(Symbol); Relocation->Section = Symbol; };
static module_t *module_load_internal(const char *Path, const char *File, const char *Alias) { //pthread_t Thread = pthread_self(); //printf("<thread @ %x> Entering module_load_internal:%d(%s, %s)\n", Thread, __LINE__, Path, File); const char *Name = path_join(Path, File); pthread_mutex_lock(LibRivaMutex); module_t *Module = stringtable_get(Modules, Name); if (Module) { pthread_mutex_unlock(LibRivaMutex); module_reload(Module); //printf("<thread @ %x> Leaving module_load_internal:%d(%s, %s)\n", Thread, __LINE__, Path, File); return Module; }; module_provider_t *Providers = module_find_loaders(Name, ModuleLoaders, -1); if (!Providers) { pthread_mutex_unlock(LibRivaMutex); //printf("<thread @ %x> Leaving module_load_internal:%d(%s, %s)\n", Thread, __LINE__, Path, File); return 0; }; Module = stringtable_get(Modules, Name); if (Module) { pthread_mutex_unlock(LibRivaMutex); module_reload(Module); //printf("<thread @ %x> Leaving module_load_internal:%d(%s, %s)\n", pthread_self(), __LINE__, Path, File); return Module; }; Module = new(module_t); Module->Type = ModuleT; Module->Name = Name; Module->Path = path_dir(Name); Module->TimeStamp = ModuleTimeStamp; Module->Lock[0] = RecursiveMutex; stringtable_put(Modules, Name, Module); if (Alias) stringtable_put(Modules, Alias, Module); pthread_mutex_lock(Module->Lock); pthread_mutex_unlock(LibRivaMutex); module_call_loaders(Name, Module, Providers); pthread_mutex_unlock(Module->Lock); //printf("<thread @ %x> Leaving module_load_internal:%d(%s, %s)\n", Thread, __LINE__, Path, File); return Module; };
operand_t *compiler_t::lookup(int LineNo, const char *Name) { for (scope_t *Scope = this->Scope; Scope; Scope = Scope->Up) { operand_t *Operand = (operand_t *)stringtable_get(Scope->NameTable, Name); if (Operand) { switch (Scope->Type) { case scope_t::SC_GLOBAL: { if (Operand->Type == operand_t::FUTR) { Sys$Module_t *Module = Sys$Module$load(0, Operand->Module); if (Module == 0) raise_error(LineNo, "Error: module not found %s\n", Operand->Module); if (Operand->Import) { if (Sys$Module$import(Module, Operand->Import, (int *)&Operand->Type, (void **)&Operand->Value) == 0) { raise_error(LineNo, "Error: import not found %s.%s\n", Operand->Module, Operand->Import); }; } else { Operand->Type = operand_t::CNST; Operand->Value = (Lang$Object_t *)Module; }; }; return Operand; }; case scope_t::SC_LOCAL: { if (Scope->Function == Function) return Operand; operand_t *Operand2 = (operand_t *)integertable_get(Function->VarTable, (uint32_t)Operand); if (Operand2 != (operand_t *)0xFFFFFFFF) return Operand2; Operand2 = new operand_t; Operand2->Type = Operand->Type; Operand2->Index = Operand->Index; Operand2->Loop = Function->lookup(Scope->Loop); integertable_put(Function->VarTable, (uint32_t)Operand, Operand2); return Operand2; }; }; }; }; /*switch (this->Scope->Type) { case scope_t::SC_GLOBAL: { operand_t *Operand = new operand_t; Operand->Type = operand_t::GVAR; Lang$Object_t **Address = new Lang$Object_t *; Address[0] = Lang$Object$Nil; Operand->Address = Address; declare(Name, Operand); return Operand; }; case scope_t::SC_LOCAL: { operand_t *Operand = new_local(); declare(Name, Operand); return Operand; }; };*/ raise_error(LineNo, "Error: identifier %s not declared", Name); };
static int riva_import(riva_t *Riva, const char *Symbol, int *IsRef, void **Data) { const export_t *Export = stringtable_get(Riva->Exports, Symbol); if (Export) { jmp_buf OnError[1]; if (setjmp(OnError)) return 0; *IsRef = Export->Flags & EXP_VARIABLE; *Data = Export->Section->Data + Export->Offset; Export->Section->Fixup(Export->Section, OnError); return 1; } else { return 0; }; };
static void bfd_section_setup(bfd_section_t *Section) { bfd *Bfd = Section->Bfd; bfd_info_t *BfdInfo = Section->BfdInfo; asection *Sect = Section->Sect; Section->Size = bfd_get_section_size(Sect); bfd_malloc_and_get_section(Bfd, Sect, &Section->Code); arelent **Relocs = (arelent **)malloc(bfd_get_reloc_upper_bound(Bfd, Sect)); Section->NoOfRelocs = bfd_canonicalize_reloc(Bfd, Sect, Relocs, BfdInfo->Symbols); Section->Relocs = (relocation_t *)malloc(sizeof(relocation_t) * Section->NoOfRelocs); for (int I = Section->NoOfRelocs - 1; I >= 0; --I) { relocation_t *Relocation = Section->Relocs + I; asymbol *Sym = *(Relocs[I]->sym_ptr_ptr); reloc_howto_type *Type = Relocs[I]->howto; Relocation->Position = Relocs[I]->address; Relocation->Size = bfd_get_reloc_size(Type); Relocation->Flags = Type->pc_relative ? RELOC_REL : RELOC_ABS; uint32_t *Target = (uint32_t *)(Section->Code + Relocs[I]->address); if (Type->pc_relative) { #ifdef WINDOWS *(long *)(Section->Code + Relocs[I]->address) -= Relocs[I]->address + 4;// why oh why is this here??? #else *(long *)(Section->Code + Relocs[I]->address) -= Relocs[I]->address;// + 4 on windows platforms ???; #endif }; if (Sym->section == bfd_und_section_ptr) { symbol_t *Symbol; do { Symbol = (symbol_t *)stringtable_get(BfdInfo->LocalTable, Sym->name); if (Symbol) break; Symbol = (symbol_t *)stringtable_get(GlobalTable, Sym->name); if (Symbol) break; Symbol = (symbol_t *)stringtable_get(WeakTable, Sym->name); if (Symbol) break; #ifdef WINDOWS char *WindowsSizeHint = strrchr(Sym->name, '@'); if (WindowsSizeHint) { *WindowsSizeHint = 0; Symbol = (symbol_t *)stringtable_get(BfdInfo->LocalTable, Sym->name); if (Symbol) break; Symbol = (symbol_t *)stringtable_get(GlobalTable, Sym->name); if (Symbol) break; Symbol = (symbol_t *)stringtable_get(WeakTable, Sym->name); if (Symbol) break; } #endif printf("%s: unresolved symbol %s.\n", Bfd->filename, Sym->name); exit(1); } while (0); section_t *Section2 = Symbol->Section; section_relocate(Section2, Relocation, Target); if (Type->partial_inplace) *Target += (uint32_t)Symbol->Offset; } else if (Sym->section->userdata) { section_t *Section2 = (section_t *)Sym->section->userdata; section_relocate(Section2, Relocation, Target); if (Type->partial_inplace) *Target += (uint32_t)Sym->value; }; }; };
static void add_bfd(bfd *Bfd) { if (bfd_check_format(Bfd, bfd_object)) { bfd_info_t *BfdInfo = new(bfd_info_t); BfdInfo->FileName = Bfd->filename; memset(BfdInfo->LocalTable, 0, sizeof(BfdInfo->LocalTable)); BfdInfo->Symbols = (asymbol **)malloc(bfd_get_symtab_upper_bound(Bfd)); int NoOfSymbols = bfd_canonicalize_symtab(Bfd, BfdInfo->Symbols); bfd_map_over_sections(Bfd, (bfd_map)add_bfd_section, BfdInfo); for (int I = NoOfSymbols - 1; I >= 0; --I) { asymbol *Sym = BfdInfo->Symbols[I]; if (Sym->flags & BSF_GLOBAL) { const char *Name = strdup(Sym->name); symbol_t *Symbol = new_symbol(Name, (section_t *)Sym->section->userdata, Sym->value); stringtable_put(BfdInfo->LocalTable, Name, Symbol); stringtable_put(GlobalTable, Name, Symbol); } else if (Sym->section == bfd_com_section_ptr) { symbol_t *Symbol = (symbol_t *)stringtable_get(GlobalTable, Sym->name); bss_section_t *Section; if (!Symbol) { const char *Name = strdup(Sym->name); Section = new_bss_section(0); Symbol = new_symbol(Name, (section_t *)Section, 0); stringtable_put(GlobalTable, Name, Symbol); stringtable_put(BfdInfo->LocalTable, Name, Symbol); } else { Section = (bss_section_t *)Symbol->Section; }; if (Sym->value > Section->Size) Section->Size = Sym->value; } else if (Sym->flags & BSF_LOCAL) { const char *Name = strdup(Sym->name); symbol_t *Symbol = new_symbol(Name, (section_t *)Sym->section->userdata, Sym->value); stringtable_put(BfdInfo->LocalTable, Name, Symbol); } else if (Sym->flags & BSF_WEAK) { const char *Name = strdup(Sym->name); symbol_t *Symbol = new_symbol(Name, (section_t *)Sym->section->userdata, Sym->value); stringtable_put(WeakTable, Name, Symbol); } else if (Sym->section == bfd_und_section_ptr) { } else if (Sym->flags & BSF_DEBUGGING) { // This may be supported later } else { printf("%s: unknown symbol type: %8x.\n", Bfd->filename, Sym->flags); exit(1); }; }; } else if (bfd_check_format(Bfd, bfd_archive)) { bfd *Bfd2 = 0; while ((Bfd2 = bfd_openr_next_archived_file(Bfd, Bfd2))) add_bfd(Bfd2); }; };
static int library_file_module(lua_State *State) { int NoOfArgs = lua_gettop(State); lua_getglobal(State, "Library"); library_file_t *Library = lua_touserdata(State, -1); lua_pop(State, 1); int PathSize = 0; for (int I = 1; I <= NoOfArgs; ++I) PathSize += strlen(lua_tostring(State, I)) + 1; char *Path = (char *)malloc(PathSize), *PathPtr = Path; #ifdef WINDOWS char *Name = (char *)malloc(PathSize + 1), *NamePtr = Name + 1; Name[0] = '_'; #else char *Name = (char *)malloc(PathSize), *NamePtr = Name; #endif for (int I = 1; I <= NoOfArgs; ++I) { char *Temp = lua_tostring(State, I); PathPtr = stpcpy(PathPtr, Temp); *(PathPtr++) = '/'; NamePtr = stpcpy(NamePtr, Temp); *(NamePtr++) = '$'; }; PathPtr[-1] = 0; NamePtr[-1] = 0; library_section_t *LibrarySection = (library_section_t *)stringtable_get(LibraryTable, Path); if (LibrarySection == 0) { LibrarySection = new_library_section(Path); symbol_t *Symbol = new(symbol_t); Symbol->Name = Name; Symbol->Section = (section_t *)LibrarySection; Symbol->Offset = 0; stringtable_put(GlobalTable, Name, Symbol); }; Library->Section = LibrarySection; return 0; };
static void add_file(const char *FileName) { const char *Extension = strrchr(FileName, '.'); if (Extension == 0) { printf("%s: filename must include extension.\n", FileName); return; }; file_adder _add = (file_adder)stringtable_get(SupportedFiles, Extension); if (_add == 0) { printf("%s: unable to determine file type from extension.\n", FileName); return; }; struct stat Stat; char FullFileName[256]; for (search_path_t *Node = &SearchPath; Node; Node = Node->Next) { sprintf(FullFileName, "%s%s", Node->Path, FileName); if (stat(FullFileName, &Stat) == 0) { _add(strdup(FullFileName)); return; }; }; printf("%s: file not found.\n", FileName); exit(1); };
static int library_file_export(lua_State *State) { int NoOfArgs = lua_gettop(State); lua_getglobal(State, "Library"); library_file_t *Library = lua_touserdata(State, -1); lua_pop(State, 1); int Flags = 0; const char *Internal = 0; const char *External = 0; for (int I = 1; I <= NoOfArgs; ++I) { if (lua_isstring(State, I)) { if (Internal == 0) { Internal = strdup(lua_tostring(State, I)); } else { External = strdup(lua_tostring(State, I)); }; } else if (lua_isuserdata(State, I)) { void *Name = lua_touserdata(State, I); for (export_type *E = ExportTypes; E->Name; ++E) { if (E->Name == Name) { Flags = E->Flags; break; }; }; }; }; if (External == 0) asprintf(&External, "%s%s", Library->Prefix, Internal); //printf("Adding export: %s -> %s\n", Internal, External); import_section_t *ImportSection = (import_section_t *)stringtable_get(Library->Section->Imports, Internal); if (ImportSection == 0) { ImportSection = new_import_section(Library->Section, Internal, Flags); }; symbol_t *Symbol = new_symbol(External, (section_t *)ImportSection, 0); stringtable_put(GlobalTable, External, Symbol); return 0; };
int main(int Argc, char **Argv) { if (Argc < 2) { puts("Usage: rlink [-o output] [-l listing] inputs ... "); } else { bfd_init(); stringtable_put(SupportedFiles, ".rlib", (void *)add_library_file); stringtable_put(SupportedFiles, ".rdef", (void *)add_definition_file); stringtable_put(SupportedFiles, ".a", (void *)add_object_file); stringtable_put(SupportedFiles, ".o", (void *)add_object_file); stringtable_put(SupportedFiles, ".obj", (void *)add_object_file); stringtable_put(SupportedFiles, ".mo", (void *)add_object_file); stringtable_put(SupportedFiles, ".io", (void *)add_object_file); char *OutFile = 0; char *ListFile = 0; for (int I = 1; I < Argc; ++I) { if (Argv[I][0] == '-') { switch (Argv[I][1]) { case 'o': OutFile = Argv[I] + 2; break; case 'l': add_file(Argv[I] + 2); break; case 'L': add_path(Argv[I] + 2); case 's': break; case 'm': Platform = Argv[I] + 2; case '?': ListFile = Argv[I] + 2; break; }; } else { add_file(Argv[I]); }; }; for (export_t *Export = Exports.Head; Export; Export = Export->Next) { symbol_t *Symbol = (symbol_t *)stringtable_get(GlobalTable, Export->Internal); if (Symbol) { section_require(Export->Section = Symbol->Section); Export->Offset = Symbol->Offset; } else { printf("exported symbol not found: %s.\n", Export->Internal); exit(1); }; }; if (ListFile) { FILE *File = fopen(ListFile, "w"); for (section_t *Section = Sections.Head; Section; Section = Section->Next) section_debug(Section, File); for (export_t *Export = Exports.Head; Export; Export = Export->Next) { fprintf(File, "export: %s -> %d[%d]\n", Export->External, Export->Section->Index, Export->Offset); }; for (require_t *Require = Requires.Head; Require; Require = Require->Next) { fprintf(File, "require: %s[%d]\n", Require->Library, Require->Flags); }; fclose(File); }; if (OutFile) { uint32_t Temp; gzFile File = gzopen(OutFile, "wb9"); gzwrite(File, "RIVA", 4); Temp = NoOfSections; gzwrite(File, &Temp, 4); Temp = NoOfExports; gzwrite(File, &Temp, 4); Temp = NoOfRequires; gzwrite(File, &Temp, 4); for (section_t *Section = Sections.Head; Section; Section = Section->Next) section_write(Section, File); for (export_t *Export = Exports.Head; Export; Export = Export->Next) { Temp = Export->Flags; gzwrite(File, &Temp, 1); Temp = Export->Section->Index; gzwrite(File, &Temp, 4); Temp = Export->Offset; gzwrite(File, &Temp, 4); Temp = strlen(Export->External); gzwrite(File, &Temp, 4); gzwrite(File, Export->External, Temp); }; for (require_t *Require = Requires.Head; Require; Require = Require->Next) { Temp = Require->Flags; gzwrite(File, &Temp, 1); Temp = strlen(Require->Library); gzwrite(File, &Temp, 4); gzwrite(File, Require->Library, Temp); }; gzclose(File); }; }; };