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; };
void module_provider_export(module_provider_t *Provider, const char *Symbol, int IsRef, void *Data) { export_t *Export = new(export_t); Export->IsRef = IsRef; Export->Data = Data; pthread_mutex_lock(LibRivaMutex); stringtable_put(Provider->Module->Symbols, Symbol, Export); pthread_mutex_unlock(LibRivaMutex); };
void module_export(module_t *Module, const char *Name, int IsRef, void *Data) { export_t *Export = new(export_t); Export->IsRef = IsRef; Export->Data = Data; pthread_mutex_lock(LibRivaMutex); stringtable_put(Module->Symbols, Name, Export); pthread_mutex_unlock(LibRivaMutex); };
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; };
static library_section_t *new_library_section(const char *Path) { static section_methods Methods = { default_section_setup, default_section_relocate, (void (*)(section_t *, FILE *))library_section_debug, (void (*)(section_t *, gzFile ))library_section_write }; library_section_t *Section = new(library_section_t); ((section_t *)Section)->Index = SEC_UNUSED; ((section_t *)Section)->Methods = &Methods; memset(Section->Imports, 0, sizeof(Section->Imports)); Section->Path = Path; stringtable_put(LibraryTable, Path, Section); return Section; };
static import_section_t *new_import_section(library_section_t *Library, const char *Name, int Type) { static section_methods Methods = { (void (*)(section_t *))import_section_setup, default_section_relocate, (void (*)(section_t *, FILE *))import_section_debug, (void (*)(section_t *, gzFile ))import_section_write }; import_section_t *Section = new(import_section_t); ((section_t *)Section)->Index = SEC_UNUSED; ((section_t *)Section)->Methods = &Methods; Section->Name = Name; Section->Library = Library; Section->Type = Type; stringtable_put(Library->Imports, Name, Section); return Section; };
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 method_section_t *new_method_section() { static section_methods Methods = { (void (*)(section_t *))method_section_setup, invalid_section_relocate, (void (*)(section_t *, FILE *))method_section_debug, (void (*)(section_t *, gzFile ))method_section_write }; if (MethodSection == 0) { MethodSection = new(method_section_t); ((section_t *)MethodSection)->Methods = &Methods; ((section_t *)MethodSection)->Index = SEC_UNUSED; MethodSection->Blocks = 0; MethodSection->Size = 0; MethodSection->NoOfRelocs = 0; new_export("<methods>", "__methods", EXP_CONSTANT); symbol_t *Symbol = new_symbol("<methods>", (section_t *)MethodSection, 0); stringtable_put(GlobalTable, "<methods>", Symbol); }; return MethodSection; };
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 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); }; }; };
void module_add_alias(module_t *Module, const char *Name) { pthread_mutex_lock(LibRivaMutex); stringtable_put(Modules, Name, Module); pthread_mutex_unlock(LibRivaMutex); };
void compiler_t::declare(const char *Name, operand_t *Operand) { stringtable_put(Scope->NameTable, Name, Operand); };
static int riva_load(module_t *Module, const char *FileName) { riva_t *Riva = unew(riva_t); // This really should be new... module_setup(Module, Riva, (module_importer)riva_import); gzFile File = gzopen(FileName, "rb"); char *LoadPath; for (int I = strlen(FileName) - 1; I >= 0; --I) { if (FileName[I] == PATHCHR) { strncpy(LoadPath = (char *)GC_malloc_atomic(I + 2), FileName, I + 1); break; }; }; module_set_path(Module, LoadPath); uint32_t Magic; gzread(File, &Magic, 4); if (Magic != 0x41564952) { log_errorf("Error: %s is not a valid riva module\n", FileName); return 0; }; uint32_t NoOfSections; gzread(File, &NoOfSections, 4); uint32_t NoOfExports; gzread(File, &NoOfExports, 4); uint32_t NoOfRequires; gzread(File, &NoOfRequires, 4); jmp_buf OnError[1]; if (setjmp(OnError)) return 0; section_t **Sections = (Riva->Sections = (section_t **)GC_malloc(NoOfSections * sizeof(section_t *))); for (int I = 0; I < NoOfSections; ++I) Sections[I] = new(section_t); for (int I = 0; I < NoOfSections; ++I) { section_t *Section = Sections[I]; uint8_t Type; gzread(File, &Type, 1); switch (Type) { case SECT_CODE: { Section->Fixup = fixup_code_section; gzread(File, &Section->Flags, 1); uint32_t Length; gzread(File, &Length, 4); uint32_t NoOfRelocs; gzread(File, &NoOfRelocs, 4); Section->NoOfRelocs = NoOfRelocs; reloc_t *Relocs = (Section->Relocs = (reloc_t *)GC_malloc_uncollectable(NoOfRelocs * sizeof(reloc_t))); if (Section->Flags & FLAG_GC) { Section->Data = GC_malloc_uncollectable(Length); } else { Section->Data = GC_malloc_atomic_uncollectable(Length); }; gzread(File, Section->Data, Length); for (int J = 0; J < NoOfRelocs; ++J) { reloc_t *Reloc = &Relocs[J]; gzread(File, &Reloc->Size, 1); gzread(File, &Reloc->Flags, 1); gzread(File, &Reloc->Position, 4); uint32_t Index; gzread(File, &Index, 4); Reloc->Section = Sections[Index]; }; break;}; case SECT_LIBRARY: { Section->Fixup = fixup_library_section; gzread(File, &Section->Flags, 1); uint32_t Length; gzread(File, &Length, 4); gzread(File, Section->Name = (char *)GC_malloc_atomic(Length + 1), Length); Section->Name[Length] = 0; if (Section->Flags == LIBRARY_ABS) { Section->Path = 0; } else if (Section->Flags == LIBRARY_REL) { Section->Path = LoadPath; }; for (char *P = Section->Name; *P; ++P) if (*P == '/') *P = PATHCHR; break;}; case SECT_IMPORT: { Section->Fixup = fixup_import_section; gzread(File, &Section->Flags, 1); uint32_t Index; gzread(File, &Index, 4); Section->Library = Sections[Index]; uint32_t Length; gzread(File, &Length, 4); gzread(File, Section->Name = (char *)GC_malloc_atomic(Length + 1), Length); Section->Name[Length] = 0; break;}; case SECT_BSS: { Section->Fixup = fixup_bss_section; gzread(File, &Section->Flags, 1); uint32_t Size; gzread(File, &Size, 4); Section->Data = (uint8_t *)GC_malloc(Size); break;}; case SECT_SYMBOL: { Section->Fixup = fixup_symbol_section; gzread(File, &Section->Flags, 1); uint32_t Length; gzread(File, &Length, 4); gzread(File, Section->Name = (char *)GC_malloc_atomic(Length + 1), Length); Section->Name[Length] = 0; break;}; }; }; for (int I = 0; I < NoOfExports; ++I) { export_t *Export = new(export_t); gzread(File, &Export->Flags, 1); uint32_t Index; gzread(File, &Index, 4); Export->Section = Sections[Index]; gzread(File, &Export->Offset, 4); uint32_t Length; gzread(File, &Length, 4); char *Name = (char *)GC_malloc_atomic(Length + 1); gzread(File, Name, Length); Name[Length] = 0; stringtable_put(Riva->Exports, Name, Export); }; for (int I = 0; I < NoOfRequires; ++I) { uint8_t Flags; gzread(File, &Flags, 1); uint32_t Length; gzread(File, &Length, 4); char *Name = (char *)GC_malloc_atomic(Length + 1); char *Path = 0; gzread(File, Name, Length); Name[Length] = 0; if (Flags == LIBRARY_REL) Path = LoadPath; for (char *P = Name; *P; ++P) if (*P == '/') *P = PATHCHR; module_load(Path, Name); }; gzclose(File); void (*__init)(module_t *) = check_import(Riva, "__init", OnError); if (__init) __init(Module); void *Methods = check_import(Riva, "__methods", OnError); if (Methods) add_methods(Methods); return 1; };