#include "Rts.h" #include "elf_got.h" #include #if defined(OBJFORMAT_ELF) /* * Check if we need a global offset table slot for a * given symbol */ bool needGotSlot(Elf_Sym * symbol) { /* using global here should give an upper bound */ /* I don't believe we need to relocate STB_LOCAL * symbols via the GOT; however I'm unsure about * STB_WEAK. * * Any more restrictive filter here would result * in a smaller GOT, which is preferrable. */ return ELF_ST_BIND(symbol->st_info) == STB_GLOBAL || ELF_ST_BIND(symbol->st_info) == STB_WEAK // Section symbols exist primarily for relocation // and as such may need a GOT slot. || ELF_ST_TYPE(symbol->st_info) == STT_SECTION; } bool makeGot(ObjectCode * oc) { size_t got_slots = 0; /* we need to find all symbol tables (elf can have multiple) * and need to iterate over all symbols, to check how many * got slots we need at most */ ASSERT( oc->info != NULL ); ASSERT( oc->info->sectionHeader != NULL ); for(int i=0; i < oc->n_sections; i++) { if(SHT_SYMTAB == oc->info->sectionHeader[i].sh_type) { Elf_Sym *symTab = (Elf_Sym*)((uint8_t*)oc->info->elfHeader + oc->info->sectionHeader[i].sh_offset); size_t n_symbols = oc->info->sectionHeader[i].sh_size / sizeof(Elf_Sym); for(size_t j=0; j < n_symbols; j++) { if(needGotSlot(&symTab[j])) { got_slots += 1; } } } } if(got_slots > 0) { oc->info->got_size = got_slots * sizeof(void *); void * mem = mmapAnonForLinker(oc->info->got_size); if (mem == NULL) { errorBelch("MAP_FAILED. errno=%d", errno); return EXIT_FAILURE; } oc->info->got_start = (void*)mem; /* update got_addr */ size_t slot = 0; for(ElfSymbolTable *symTab = oc->info->symbolTables; symTab != NULL; symTab = symTab->next) { for(size_t i=0; i < symTab->n_symbols; i++) if(needGotSlot(symTab->symbols[i].elf_sym)) symTab->symbols[i].got_addr = (uint8_t *)oc->info->got_start + (slot++ * sizeof(void*)); } } return EXIT_SUCCESS; } bool fillGot(ObjectCode * oc) { /* fill the GOT table */ for(ElfSymbolTable *symTab = oc->info->symbolTables; symTab != NULL; symTab = symTab->next) { for(size_t i=0; i < symTab->n_symbols; i++) { ElfSymbol * symbol = &symTab->symbols[i]; if(needGotSlot(symbol->elf_sym)) { /* no type are undefined symbols */ // Note STT_SECTION symbols should have their addres // set prior to the fillGot call in ocResolve_ELF. if( STT_NOTYPE == ELF_ST_TYPE(symbol->elf_sym->st_info) || STB_WEAK == ELF_ST_BIND(symbol->elf_sym->st_info)) { if(0x0 == symbol->addr) { symbol->addr = lookupDependentSymbol(symbol->name, oc); if(0x0 == symbol->addr) { if(0 == strncmp(symbol->name,"_GLOBAL_OFFSET_TABLE_",21)) { symbol->addr = oc->info->got_start; } else { errorBelch("Failed to lookup symbol: %s\n", symbol->name); return EXIT_FAILURE; } } } else { // we already have the address. } } /* else it was defined somewhere in the same object, and * we should have the address already. */ if(0x0 == symbol->addr) { errorBelch( "Something went wrong! Symbol %s has null address.\n", symbol->name); return EXIT_FAILURE; } if(0x0 == symbol->got_addr) { errorBelch("Not good either!"); return EXIT_FAILURE; } *(void**)symbol->got_addr = symbol->addr; } } } // We are done initializing the GOT; freeze it. if(mprotect(oc->info->got_start, oc->info->got_size, PROT_READ) != 0) { sysErrorBelch("unable to protect memory"); } return EXIT_SUCCESS; } bool verifyGot(ObjectCode * oc) { for(ElfSymbolTable *symTab = oc->info->symbolTables; symTab != NULL; symTab = symTab->next) { for(size_t i=0; i < symTab->n_symbols; i++) { ElfSymbol * symbol = &symTab->symbols[i]; if(symbol->got_addr) { CHECK((void*)(*(void**)symbol->got_addr) == (void*)symbol->addr); } CHECK(0 == ((uintptr_t)symbol->addr & 0xffff000000000000)); } } return EXIT_SUCCESS; } void freeGot(ObjectCode * oc) { // munmapForLinker(oc->info->got_start, oc->info->got_size, "freeGot); oc->info->got_start = 0x0; oc->info->got_size = 0; } #endif