int main(int argc, char* argv[]) { // Define our variables. FILE* in; FILE* out; int nerrors, i; char* test; uint16_t offset, current, store, mem_index; struct lprov_entry* required = NULL; struct lprov_entry* provided = NULL; struct lprov_entry* adjustment = NULL; struct lprov_entry* temp = NULL; // Define arguments. struct arg_lit* show_help = arg_lit0("h", "help", "Show this help."); struct arg_file* input_files = arg_filen(NULL, NULL, "<file>", 1, 100, "The input object files."); struct arg_file* output_file = arg_file1("o", "output", "<file>", "The output file (or - to send to standard output)."); struct arg_end *end = arg_end(20); void *argtable[] = { show_help, input_files, output_file, end }; // Parse arguments. nerrors = arg_parse(argc,argv,argtable); if (nerrors != 0 || show_help->count != 0) { if (show_help->count != 0) arg_print_errors(stdout, end, "linker"); printf("syntax:\n linker"); arg_print_syntax(stdout, argtable, "\n"); printf("options:\n"); arg_print_glossary(stdout, argtable, " %-25s %s\n"); return 1; } // Open the output file for writing. out = fopen(output_file->filename[0], "wb"); if (out == NULL) { // Handle the error. fprintf(stderr, "linker: unable to write to output file.\n"); return 1; } // We initially need to get a list of ALL provided // labels before we can start replacing them. offset = 0; for (i = 0; i < input_files->count; i++) { // Open the input file. in = fopen(input_files->filename[i], "rb"); if (in == NULL) { // Handle the error. fprintf(stderr, "linker: unable to read input file '%s'.\n", input_files->filename[i]); fclose(out); return 1; } // Is this the object format? test = malloc(strlen(ldata_objfmt) + 1); memset(test, 0, strlen(ldata_objfmt) + 1); fread(test, 1, strlen(ldata_objfmt), in); fseek(in, 1, SEEK_CUR); if (strcmp(test, ldata_objfmt) != 0) { // Handle the error. fprintf(stderr, "linker: input file '%s' is not in object format 1.0.\n", input_files->filename[i]); fclose(in); fclose(out); return 1; } free(test); // Load only the provided label entries into memory. objfile_load(input_files->filename[i], in, &offset, &provided, NULL, NULL); // Close the file. fclose(in); } // Now we can start replacing the labels with the provided values // since we have ALL of the provided labels available. offset = 0; for (i = 0; i < input_files->count; i++) { // Open the input file. in = fopen(input_files->filename[i], "rb"); if (in == NULL) { // Handle the error. fprintf(stderr, "linker: unable to read input file '%s'.\n", input_files->filename[i]); fclose(out); return 1; } // Skip over the object format label; we already tested // for this in phase 1. fseek(in, strlen(ldata_objfmt) + 1, SEEK_CUR); // Load only the required and adjustment entries into memory. current = offset; objfile_load(input_files->filename[i], in, &offset, NULL, &required, &adjustment); // Copy all of the input file's data into the output // file, word by word. mem_index = 0; fprintf(stderr, "BEGIN %s\n", input_files->filename[i]); while (!feof(in)) { // Read a word. fread(&store, sizeof(uint16_t), 1, in); // For some strange reason, the last two bytes get // written twice, as if it's only EOF after you // attempt to read past the end again. I'm not sure // why the semantics are like this, but checking again // for EOF here prevents us writing double. if (feof(in)) break; // Check to see if we need to do something with this // word, such as adjusting it. if (lprov_find_by_address(adjustment, mem_index) != NULL) { // We need to adjust this word by the offset. store += current; fprintf(stderr, "ADJUSTED 0x%04X: 0x%04X -> 0x%04X\n", mem_index, store - current, store); } // Check to see if we need to resolve this word into // an actual address because it was imported. temp = lprov_find_by_address(required, mem_index); if (temp != NULL) { // Find the position we should change this to. temp = lprov_find_by_label(provided, temp->label); // We need to set this word to the proper location. fprintf(stderr, "RESOLVED 0x%04X: 0x%04X -> 0x%04X\n", mem_index, store, temp->address); store = temp->address; } // Now write the (potentially modified) word to the // output. fprintf(stderr, " >> WRITE 0x%04X\n", store); fwrite(&store, sizeof(uint16_t), 1, out); // Increment memory position. mem_index++; } // Close the file. fclose(in); // Reset and free the required and adjustment linked list. // FIXME: Actually free the lists! required = NULL; adjustment = NULL; } // Close file. fprintf(stderr, "linker: completed successfully.\n", input_files->filename[i]); fclose(out); return 0; }
/// /// Loads a new bin by reading a linker object from file. /// /// Adds a new bin by reading in a linker object stored on disk and /// automatically handling loading bytes and linker information into /// the bin. /// /// @param path The path to load. /// @return Whether the bin was loaded successfully. /// bool bins_load(freed_bstring path) { uint16_t offset = 0, store; struct lprov_entry* required = NULL; struct lprov_entry* provided = NULL; struct lprov_entry* adjustment = NULL; struct lprov_entry* section = NULL; struct lprov_entry* output = NULL; struct ldbin* bin; FILE* in; char* test; // Open the input file. in = fopen(path.ref->data, "rb"); if (in == NULL) { // Handle the error. return false; } // Is this the object format? test = malloc(strlen(ldata_objfmt) + 1); memset(test, 0, strlen(ldata_objfmt) + 1); fread(test, 1, strlen(ldata_objfmt), in); fseek(in, 1, SEEK_CUR); if (strcmp(test, ldata_objfmt) != 0) { // Handle the error. return false; } free(test); // Load only the provided label entries into memory. objfile_load(path.ref->data, in, &offset, &provided, &required, &adjustment, §ion, &output); // Add the new bin. bin = bins_add(path, provided, required, adjustment, section, output); // Copy all of the input file's data into the output // file, word by word. while (true) { // Read a word into the bin. The reason that // we break inside the loop is that we are reading // two bytes at a time and thus the EOF flag doesn't // get set until we actually attempt to read past // the end-of-file. If we don't do this, we get a // double read of the same data. fread(&store, sizeof(uint16_t), 1, in); if (feof(in)) break; bin_write(bin, store); } // Close the file. fclose(in); // TODO: Free the list data in the struct lprov_entry // pointers (since it's cloned by the bin system). return true; }