/* * print_load_fvmlibs_list() prints the fvmlib segments table. For debugging. */ __private_extern__ void print_load_fvmlibs_list(void) { struct merged_fvmlib **p, *mfl; print("Load fvmlibs list\n"); p = &merged_fvmlibs; while(*p){ mfl = *p; if(mfl->fl->cmd == LC_LOADFVMLIB) print(" LC_LOADFVMLIB\n"); else print(" LC_IDFVMLIB\n"); print("\tcmdsize %u\n", mfl->fl->cmdsize); if(mfl->fl->fvmlib.name.offset < mfl->fl->cmdsize) print("\tname %s (offset %u)\n", (char *)(mfl->fl) + mfl->fl->fvmlib.name.offset, mfl->fl->fvmlib.name.offset); else print("\tname ?(bad offset %u)\n",mfl->fl->fvmlib.name.offset); print("\tminor version %u\n", mfl->fl->fvmlib.minor_version); print("\theader addr 0x%08x\n", (unsigned int)(mfl->fl->fvmlib.header_addr)); print(" fvmlib_name %s\n", mfl->fvmlib_name); print(" definition_object "); print_obj_name(mfl->definition_object); print("\n"); print(" multiple %s\n", mfl->multiple == TRUE ? "TRUE" : "FALSE"); p = &(mfl->next); } }
/* * lookup_merged_fvmlib() adds the LC_LOADFVMLIB structure passed to it to the * merged list of fixed VM libraries. It warns if it see the same library * twice. */ static struct merged_fvmlib * lookup_merged_fvmlib( struct fvmlib_command *fl) { char *fvmlib_name; struct merged_fvmlib **p, *mfl; fvmlib_name = (char *)fl + fl->fvmlib.name.offset; p = &merged_fvmlibs; while(*p){ mfl = *p; if(strcmp(mfl->fvmlib_name, fvmlib_name) == 0){ if(mfl->multiple == FALSE){ if(mfl->fl->cmd == LC_IDFVMLIB) error("multiple object files identify fixed VM library " "%s", fvmlib_name); else warning("multiple object files load fixed VM library " "%s", fvmlib_name); print_obj_name(mfl->definition_object); print("%s fixed VM library %s\n", mfl->fl->cmd == LC_LOADFVMLIB ? "loads" :"identifies", fvmlib_name); mfl->multiple = TRUE; } print_obj_name(cur_obj); print("%s fixed VM library %s\n", mfl->fl->cmd == LC_LOADFVMLIB ? "loads" : "identifies", fvmlib_name); return(mfl); } p = &(mfl->next); } *p = allocate(sizeof(struct merged_fvmlib)); memset(*p, '\0', sizeof(struct merged_fvmlib)); mfl = *p; mfl->fl = fl; mfl->fvmlib_name = fvmlib_name; mfl->definition_object = cur_obj; mfl->multiple = FALSE; return(mfl); }
/* * pass2() creates the output file and the memory buffer to create the file * into. It drives the process to get everything copied into the buffer for * the output file. It then writes the output file and deallocates the buffer. */ extern void pass2(void) { unsigned long i, j, section_type; struct object_list *object_list, **p; #ifndef RLD int mode; struct stat stat_buf; kern_return_t r; /* * In UNIX standard conformance mode we are not allowed to replace * a file that is not writeable. */ if(get_unix_standard_mode() == TRUE && access(outputfile, F_OK) == 0 && access(outputfile, W_OK) == -1) system_fatal("can't write output file: %s", outputfile); /* * Create the output file. The unlink() is done to handle the problem * when the outputfile is not writable but the directory allows the * file to be removed (since the file may not be there the return code * of the unlink() is ignored). */ (void)unlink(outputfile); if((fd = open(outputfile, O_WRONLY | O_CREAT | O_TRUNC, 0777)) == -1) system_fatal("can't create output file: %s", outputfile); #ifdef F_NOCACHE /* tell filesystem to NOT cache the file when reading or writing */ (void)fcntl(fd, F_NOCACHE, 1); #endif if(fstat(fd, &stat_buf) == -1) system_fatal("can't stat file: %s", outputfile); /* * Turn the execute bits on or off depending if there are any undefined * symbols in the output file. If the file existed before the above * open() call the creation mode in that call would have been ignored * so it has to be set explicitly in any case. */ if(output_mach_header.flags & MH_NOUNDEFS || (has_dynamic_linker_command && output_for_dyld)) mode = (stat_buf.st_mode & 0777) | (0111 & ~umask(0)); else mode = (stat_buf.st_mode & 0777) & ~0111; if(fchmod(fd, mode) == -1) system_fatal("can't set execution permissions output file: %s", outputfile); /* * Create the buffer to copy the parts of the output file into. */ if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr, output_size, TRUE)) != KERN_SUCCESS) mach_fatal(r, "can't vm_allocate() buffer for output file of size " "%lu", output_size); /* * Set up for flushing pages to the output file as they fill up. */ if(flush) setup_output_flush(); /* * Make sure pure_instruction sections are padded with nop's. */ nop_pure_instruction_scattered_sections(); #endif /* !defined(RLD) */ /* * The strings indexes for the merged string blocks need to be set * before the dylib tables are output because the module names are in * them as well as the merged symbol names. */ set_merged_string_block_indexes(); #ifndef RLD /* * Copy the dylib tables into the output file. This is done before the * sections are outputted so that the indexes to the local and external * relocation entries for each object can be used as running indexes as * each section in the object is outputted. */ if(filetype == MH_DYLIB) output_dylib_tables(); #endif /* !defined(RLD) */ /* * Create the array of pointers to merged sections in the output file * so the relocation routines can use it to set the 'referenced' fields * in the merged section structures. */ create_output_sections_array(); /* * Copy the merged literal sections and the sections created from files * into the output object file. */ output_literal_sections(); #ifndef RLD output_sections_from_files(); #endif /* !defined(RLD) */ /* * For each non-literal content section in each object file loaded * relocate it into the output file (along with the relocation entries). * Then relocate local symbols into the output file for the loaded * objects. */ for(p = &objects; *p; p = &(object_list->next)){ object_list = *p; for(i = 0; i < object_list->used; i++){ cur_obj = &(object_list->object_files[i]); /* print the object file name if tracing */ if(trace){ print_obj_name(cur_obj); print("\n"); } if(cur_obj->dylib) continue; if(cur_obj->bundle_loader) continue; if(cur_obj->dylinker) continue; if(cur_obj != base_obj){ for(j = 0; j < cur_obj->nsection_maps; j++){ if(cur_obj->section_maps[j].s->flags & S_ATTR_DEBUG) continue; #ifdef RLD if(cur_obj->set_num == cur_set) #endif /* RLD */ { section_type = (cur_obj->section_maps[j].s->flags & SECTION_TYPE); if(section_type == S_REGULAR || section_type == S_SYMBOL_STUBS || section_type == S_NON_LAZY_SYMBOL_POINTERS || section_type == S_LAZY_SYMBOL_POINTERS || section_type == S_COALESCED || section_type == S_MOD_INIT_FUNC_POINTERS || section_type == S_MOD_TERM_FUNC_POINTERS){ output_section(&(cur_obj->section_maps[j])); } } } } output_local_symbols(); #if defined(VM_SYNC_DEACTIVATE) && !defined(_POSIX_C_SOURCE) && !defined(__CYGWIN__) vm_msync(mach_task_self(), (vm_address_t)cur_obj->obj_addr, (vm_size_t)cur_obj->obj_size, VM_SYNC_DEACTIVATE); #endif /* VM_SYNC_DEACTIVATE */ } } /* * If there were errors in output_section() then return as so not * to cause later internal errors. */ if(errors != 0) return; #ifdef RLD /* * For each content section clean up the data structures not needed * after rld is run. This must be done after ALL the sections are * output'ed because the fine relocation entries could be used by any * of the sections. */ for(p = &objects; *p; p = &(object_list->next)){ object_list = *p; for(i = 0; i < object_list->used; i++){ cur_obj = &(object_list->object_files[i]); for(j = 0; j < cur_obj->nsection_maps; j++){ if(cur_obj->section_maps[j].nfine_relocs != 0){ free(cur_obj->section_maps[j].fine_relocs); cur_obj->section_maps[j].fine_relocs = NULL; cur_obj->section_maps[j].nfine_relocs = 0; } } if(cur_obj->nundefineds != 0){ free(cur_obj->undefined_maps); cur_obj->undefined_maps = NULL; cur_obj->nundefineds = 0; } } } #endif /* RLD */ /* * Set the SG_NORELOC flag in the segments that had no relocation to * or for them. */ set_SG_NORELOC_flags(); #ifndef SA_RLD /* * Copy the indirect symbol table into the output file. */ output_indirect_symbols(); #endif /* SA_RLD */ /* * Copy the merged symbol table into the output file. */ output_merged_symbols(); /* * Copy the headers into the output file. */ output_headers(); #ifndef RLD if(flush){ /* * Flush the sections that have been scatter loaded. */ flush_scatter_copied_sections(); /* * flush the remaining part of the object file that is not a full * page. */ final_output_flush(); } else{ /* * Write the entire object file. */ if(write(fd, output_addr, output_size) != (int)output_size) system_fatal("can't write output file"); if((r = vm_deallocate(mach_task_self(), (vm_address_t)output_addr, output_size)) != KERN_SUCCESS) mach_fatal(r, "can't vm_deallocate() buffer for output file"); } #ifdef F_NOCACHE /* re-enable caching of file reads/writes */ (void)fcntl(fd, F_NOCACHE, 0); #endif if(close(fd) == -1) system_fatal("can't close output file"); #endif /* RLD */ }
/* * literal_pointer_merge() merges literal pointers from the specified section * in the current object file (cur_obj). It allocates a fine relocation map and * sets the fine_relocs field in the section_map to it (as well as the count). */ __private_extern__ void literal_pointer_merge( struct literal_pointer_data *data, struct merged_section *ms, struct section *s, struct section_map *section_map) { long i; unsigned long nliterals, j; char *literals; struct fine_reloc *fine_relocs; struct relocation_info *relocs; struct relocation_info *reloc; struct scattered_relocation_info *sreloc; unsigned long r_address, r_symbolnum, r_pcrel, r_length, r_extern, r_scattered, r_value; struct undefined_map *undefined_map; struct nlist *nlists; char *strings; enum bool defined, new; struct merged_symbol *merged_symbol, **hash_pointer; struct section_map *literal_map; struct merged_section *literal_ms; struct section *literal_s; unsigned long section_value, input_section_offset, merged_section_offset, offset; if(s->size == 0){ section_map->fine_relocs = NULL; section_map->nfine_relocs = 0; return; } if(s->size % 4 != 0){ error_with_cur_obj("literal pointer section (%.16s,%.16s) size is " "not a multiple of 4 bytes",s->segname, s->sectname); return; } nliterals = s->size / 4; if(s->nreloc != nliterals){ error_with_cur_obj("literal pointer section (%.16s,%.16s) does not " "have is exactly one relocation entry for each " "pointer\n", s->segname, s->sectname); return; } #ifdef DEBUG data->nfiles++; data->nliterals += nliterals; #endif /* DEBUG */ /* * The size is not zero an it has as many relocation entries as literals so * this section is being relocated. */ ms->relocated = TRUE; /* * Set the output_offset to -1 here so that when going through the * relocation entries to merge the literals the error of having more than * one relocation entry for each literal can be caught. */ fine_relocs = allocate(nliterals * sizeof(struct fine_reloc)); memset(fine_relocs, '\0', nliterals * sizeof(struct fine_reloc)); for(j = 0; j < nliterals; j++){ fine_relocs[j].output_offset = -1; } section_map->fine_relocs = fine_relocs; section_map->nfine_relocs = nliterals; /* * Because at this point it is known that their are exactly as many literals * in the section as relocation entries either could be used to merge the * the literals themselves. The loop is driven off the relocation entries * for two reasons: first if it looped throught the literals themselfs a * costly search would result in trying to find the relocation entry for it * and by doing it the way it is done here the r_address (really an offset) * can be used directly to get the literal, secondly by looping through the * relocation entries checking for the error case of more than one * relocation entry refering to the same literal can be caught easily. So * if everything goes without error then their must have been exactly one * relocation entry for each literal pointer in this section. The reason * that this loop runs backwards through the relocation entries is to get * this implementation of merging literal pointers to match the previous * one so a binary compare can be done (the previous implemention went * through the literals and the current assembler puts out the relocation * entries in reverse order so these two implementions just happen to get * the exact same result). */ relocs = (struct relocation_info *)(cur_obj->obj_addr + s->reloff); literals = (char *)(cur_obj->obj_addr + s->offset); if(cur_obj->swapped) swap_relocation_info(relocs, s->nreloc, host_byte_sex); merged_symbol = NULL; for(i = s->nreloc - 1; i >= 0 ; i--){ /* * Break out the fields of the relocation entry. */ if((relocs[i].r_address & R_SCATTERED) != 0){ sreloc = (struct scattered_relocation_info *)(relocs + i); reloc = NULL; r_scattered = 1; r_address = sreloc->r_address; r_pcrel = sreloc->r_pcrel; r_length = sreloc->r_length; r_value = sreloc->r_value; r_extern = 0; /* calculate the r_symbolnum (n_sect) from the r_value */ r_symbolnum = 0; for(j = 0; j < cur_obj->nsection_maps; j++){ if(r_value >= cur_obj->section_maps[j].s->addr && r_value < cur_obj->section_maps[j].s->addr + cur_obj->section_maps[j].s->size){ r_symbolnum = j + 1; break; } } if(r_symbolnum == 0){ /* * The edge case where the last address past then end of * of the last section is referenced. */ for(j = 0; j < cur_obj->nsection_maps; j++){ if(r_value == cur_obj->section_maps[j].s->addr + cur_obj->section_maps[j].s->size){ r_symbolnum = j + 1; break; } } if(r_symbolnum == 0){ error_with_cur_obj("r_value (0x%x) field of relocation " "entry %lu in section (%.16s,%.16s) out of range", (unsigned int)r_value, i, s->segname, s->sectname); continue; } } } else{ reloc = relocs + i; sreloc = NULL; r_scattered = 0; r_address = reloc->r_address; r_pcrel = reloc->r_pcrel; r_length = reloc->r_length; r_extern = reloc->r_extern; r_symbolnum = reloc->r_symbolnum; r_value = 0; } /* * The r_address field is really an offset into the contents of the * section and must reference something inside the section. */ if(r_address >= s->size){ error_with_cur_obj("r_address (0x%x) field of relocation entry " "%ld in section (%.16s,%.16s) out of range", (unsigned int)r_address, i, s->segname, s->sectname); continue; } /* * For a literal pointer section all relocation entries must be for one * of the pointers and therefore the offset must be a multiple of 4, * have an r_length field of 2 (long) and a r_pcrel field of 0 (FALSE). */ if(r_address % 4 != 0){ error_with_cur_obj("r_address (0x%x) field of relocation entry " "%ld in literal pointer section (%.16s,%.16s) is not a " "multiple of 4", (unsigned int)r_address, i, s->segname, s->sectname); continue; } if(r_length != 2){ error_with_cur_obj("r_length (0x%x) field of relocation entry " "%ld in literal pointer section (%.16s,%.16s) is not 2 (long)", (unsigned int)r_length, i, s->segname, s->sectname); continue; } if(r_pcrel != 0){ error_with_cur_obj("r_pcrel (0x%x) field of relocation entry " "%ld in literal pointer section (%.16s,%.16s) is not 0 " "(FALSE)", (unsigned int)r_pcrel, i, s->segname, s->sectname); continue; } defined = TRUE; /* * If r_extern is set this relocation entry is an external entry * else it is a local entry (or scattered entry). */ if(r_extern){ /* * This is an external relocation entry. So the value to be * added to the item to be relocated is the value of the symbol. * r_symbolnum is an index into the input file's symbol table * of the symbol being refered to. The symbol must be an * undefined symbol to be used in an external relocation entry. */ if(r_symbolnum >= cur_obj->symtab->nsyms){ error_with_cur_obj("r_symbolnum (%lu) field of external " "relocation entry %ld in section (%.16s,%.16s) out of " "range", r_symbolnum, i, s->segname, s->sectname); continue; } undefined_map = bsearch(&r_symbolnum, cur_obj->undefined_maps, cur_obj->nundefineds, sizeof(struct undefined_map), (int (*)(const void *, const void *))undef_bsearch); if(undefined_map != NULL){ merged_symbol = undefined_map->merged_symbol; } else{ nlists = (struct nlist *)(cur_obj->obj_addr + cur_obj->symtab->symoff); strings = cur_obj->obj_addr + cur_obj->symtab->stroff; if((nlists[r_symbolnum].n_type & N_EXT) != N_EXT){ error_with_cur_obj("r_symbolnum (%lu) field of external " "relocation entry %lu in section (%.16s,%.16s) refers " "to a non-external symbol", r_symbolnum, i, s->segname, s->sectname); continue; } /* * We must correctly catch the errors of a literal pointer * refering defined global coalesced symbols with external * relocation entries. */ if((nlists[r_symbolnum].n_type & N_TYPE) == N_SECT && (cur_obj->section_maps[nlists[r_symbolnum]. n_sect-1].s->flags & SECTION_TYPE) == S_COALESCED){ hash_pointer = lookup_symbol(strings + nlists[r_symbolnum].n_un.n_strx); if(hash_pointer == NULL){ fatal("internal error, in literal_pointer_merge() " "failed to lookup coalesced symbol %s", strings + nlists[r_symbolnum].n_un.n_strx); } merged_symbol = *hash_pointer; error_with_cur_obj("exteral symbol (%s) for external " "relocation entry %ld in section (%.16s,%.16s) refers " "a symbol not defined in a literal section", merged_symbol->nlist.n_un.n_name, i, s->segname, s->sectname); continue; } else{ if(nlists[r_symbolnum].n_type != (N_EXT | N_UNDF)){ error_with_cur_obj("r_symbolnum (%lu) field of " "external relocation entry %lu in section " "(%.16s,%.16s) refers to a non-undefined symbol", r_symbolnum, i, s->segname, s->sectname); continue; } print_obj_name(cur_obj); fatal("internal error, in literal_pointer_merge() symbol " "index %lu in above file not in undefined map", r_symbolnum); } } /* * If this is an indirect symbol resolve indirection (all chains * of indirect symbols have been resolved so that they point at * a symbol that is not an indirect symbol). */ if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR) merged_symbol = (struct merged_symbol *) merged_symbol->nlist.n_value; /* * If the symbol is a common symbol it is an error * because it not a pointer to a literal. */ if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF) && merged_symbol->nlist.n_value != 0){ error_with_cur_obj("r_symbolnum (%lu) field of external " "relocation entry %ld in section (%.16s,%.16s) refers to " "a common symbol (%s) and is not in a literal section", r_symbolnum, i, s->segname, s->sectname, merged_symbol->nlist.n_un.n_name); continue; } /* * If the symbol is an absolute symbol it is treated as an error * because it is not known to be a pointer to a literal. */ if((merged_symbol->nlist.n_type & N_TYPE) == N_ABS){ error_with_cur_obj("r_symbolnum (%lu) field of external " "relocation entry %ld in section (%.16s,%.16s) refers to " "an absolue symbol (%s) and is not known to be in a " "literal section", r_symbolnum, i, s->segname, s->sectname, merged_symbol->nlist.n_un.n_name); continue; } /* * For multi module dynamic shared library format files the * merged sections that could have had external relocation * entries must be resolved to private extern symbols. This is * because for multi module MH_DYLIB files all modules share the * merged sections and the entire section gets relocated when * the library is mapped in. So the above restriction assures * the merged section will get relocated properly and can be * shared amoung library modules. */ if(filetype == MH_DYLIB && multi_module_dylib == TRUE){ /* * If the symbol is undefined or not a private extern it is an * error for in this section for a MH_DYLIB file. */ if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF)){ if(merged_symbol->error_flagged_for_dylib == 0){ error_with_cur_obj("illegal undefined reference for " "multi module MH_DYLIB output file to symbol: %s " "from a literal pointer section (section (%.16s," "%.16s) relocation entry: %lu)", merged_symbol->nlist.n_un.n_name, s->segname, s->sectname, i); merged_symbol->error_flagged_for_dylib = 1; } } else if((merged_symbol->nlist.n_type & N_PEXT) != N_PEXT){ if(merged_symbol->error_flagged_for_dylib == 0){ error_with_cur_obj("illegal external reference for " "multi module MH_DYLIB output file to symbol: %s " "(not a private extern symbol) from a literal " "pointer section (section (%.16s,%.16s) relocation " "entry: %lu)", merged_symbol->nlist.n_un.n_name, s->segname, s->sectname, i); merged_symbol->error_flagged_for_dylib = 1; } } } /* * If the symbol is an undefined symbol then the literal is an * offset to be added to the value of the symbol. */ if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF)){ literal_ms = NULL; merged_section_offset = 0; offset = get_long((long *)(literals + r_address)); defined = FALSE; } else { /* * All other types of symbol of symbol have been handled so this * symbol must be defined in a section. The section that the * symbol is defined in must be a literal section or else it * is an error. Since this is an external relocation entry and * the symbol is defined this means it is defined in some other * object than this one. */ if((merged_symbol->nlist.n_type & N_TYPE) != N_SECT || (merged_symbol->nlist.n_type & N_EXT) != N_EXT){ fatal("internal error, in merge_literal_pointers() merged " "symbol %s does not have a type of N_EXT|N_SECT", merged_symbol->nlist.n_un.n_name); } literal_map = &(merged_symbol->definition_object-> section_maps[merged_symbol->nlist.n_sect - 1]); literal_ms = literal_map->output_section; if((literal_ms->s.flags & SECTION_TYPE) != S_CSTRING_LITERALS && (literal_ms->s.flags & SECTION_TYPE) != S_4BYTE_LITERALS && (literal_ms->s.flags & SECTION_TYPE) != S_8BYTE_LITERALS){ error_with_cur_obj("exteral symbol (%s) for external " "relocation entry %ld in section (%.16s,%.16s) refers " "a symbol not defined in a literal section", merged_symbol->nlist.n_un.n_name, i, s->segname, s->sectname); continue; } section_value = merged_symbol->nlist.n_value; literal_s = literal_map->s; if(section_value < literal_s->addr || section_value > literal_s->addr + literal_s->size){ error_with_cur_obj("exteral symbol's (%s) address not in " "the section (%.16s,%.16s) it is defined in", merged_symbol->nlist.n_un.n_name, literal_s->segname, literal_s->sectname); continue; } input_section_offset = section_value - literal_s->addr; /* * At this point it is known that the merged section the * literal is defined in is a literal section. The checking * for an internal error if the section does not have fine_reloc * entry is left to fine_reloc_output_offset(); */ merged_section_offset = fine_reloc_output_offset(literal_map, input_section_offset); /* * since this was an external relocation entry the value of the * literal pointer is symbol+offset and the relocation is done * based on only the symbol's value without the offset added. * That's why offset is NOT added to input_section_offset above. * Also if the offset is not zero that is need to be known so * that a scattered relocation entry can be created on output. */ offset = get_long((long *)(literals + r_address)); /* * merged_symbol is set to NULL for the call to * lookup_literal_pointer because this symbol is not undefined. */ merged_symbol = NULL; /* mark the section this symbol is in as referenced */ literal_map->output_section->referenced = TRUE; } } else{ /* * This is a local relocation entry (the value to which the item * to be relocated is refering to is defined in section number * r_symbolnum in this object file). Check that r_symbolnum is not * R_ABS so it can be used to directly index the section map. * For scattered relocation entries r_value was previously checked * to be in the section refered to by r_symbolnum. */ if(r_symbolnum == R_ABS){ error_with_cur_obj("r_symbolnum (0x%x) field of relocation " "entry %ld in literal pointer section (%.16s,%.16s) is " "R_ABS (not correct for a literal pointer section)", (unsigned int)r_symbolnum, i, s->segname, s->sectname); continue; } merged_symbol = NULL; literal_map = &(cur_obj->section_maps[r_symbolnum - 1]); literal_s = literal_map->s; literal_ms = literal_map->output_section; if(r_scattered == 0){ offset = 0; section_value = get_long((long *)(literals + r_address)); if(section_value < literal_s->addr || section_value > literal_s->addr + literal_s->size){ error_with_cur_obj("literal pointer (0x%x) in section " "(%.16s,%.16s) at address 0x%x does not point into " "its (%.16s,%.16s) section as refered to by its " "r_symbolnum (0x%x) field in relocation entry %ld as " "it should", (unsigned int)section_value, s->segname, s->sectname, (unsigned int)(s->addr + r_address), literal_s->segname, literal_s->sectname, (unsigned int)r_symbolnum, i); continue; } if((literal_ms->s.flags & SECTION_TYPE) != S_CSTRING_LITERALS && (literal_ms->s.flags & SECTION_TYPE) != S_4BYTE_LITERALS && (literal_ms->s.flags & SECTION_TYPE) != S_8BYTE_LITERALS){ error_with_cur_obj("r_symbolnum field (0x%x) in relocation " "entry %ld in literal pointer section (%.16s,%.16s) " "refers to section (%.16s,%.16s) which is not a " "literal section", (unsigned int)r_symbolnum, i, s->segname, s->sectname, literal_ms->s.segname, literal_ms->s.sectname); continue; } } else{ offset = get_long((long *)(literals + r_address)) - r_value; section_value = r_value; if((literal_ms->s.flags & SECTION_TYPE) != S_CSTRING_LITERALS && (literal_ms->s.flags & SECTION_TYPE) != S_4BYTE_LITERALS && (literal_ms->s.flags & SECTION_TYPE) != S_8BYTE_LITERALS){ error_with_cur_obj("r_value field (0x%x) in relocation " "entry %ld in literal pointer section (%.16s,%.16s) " "refers to section (%.16s,%.16s) which is not a " "literal section", (unsigned int)r_value, i, s->segname, s->sectname, literal_ms->s.segname, literal_ms->s.sectname); continue; } } input_section_offset = section_value - literal_s->addr; /* * At this point it is known that the merged section the * literal is defined in is a literal section. The checking * for an internal error if the section does not have fine_reloc * entry is left to fine_reloc_output_offset(); */ merged_section_offset = fine_reloc_output_offset(literal_map, input_section_offset); /* mark the section this literal is in as referenced */ literal_map->output_section->referenced = TRUE; } /* * Since all the output_offset field of all the fine reloc entries were * set to -1 before merging the literals and there must be only one * relocation entry for each literal pointer if the relocation entry * for this literal does not have an output_offset of -1 it is an error * because we have seen it before. */ if((int)(fine_relocs[r_address/4].output_offset) != -1){ error_with_cur_obj("more than one relocation entry for literal " "pointer at address 0x%x (r_address 0x%x) in section " "(%.16s,%.16s)", (unsigned int)(s->addr + r_address), (unsigned int)r_address, s->segname, s->sectname); continue; } /* * Now at long last the literal pointer can be merged and the fine * relocation entries for it can be built. */ fine_relocs[r_address/4].input_offset = r_address; fine_relocs[r_address/4].output_offset = lookup_literal_pointer(merged_symbol, literal_ms, merged_section_offset, offset, data, ms, &new); count_reloc(ms, new, r_extern, defined); } }