literal_pointers.c [plain text]
#ifdef SHLIB
#include "shlib.h"
#endif
#include <stdlib.h>
#if !(defined(KLD) && defined(__STATIC__))
#include <stdio.h>
#include <mach/mach.h>
#else
#include <mach/mach.h>
#include <mach/kern_return.h>
#endif
#include <stdarg.h>
#include <string.h>
#include "stuff/openstep_mach.h"
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/reloc.h>
#include "stuff/bool.h"
#include "stuff/bytesex.h"
#include "ld.h"
#include "live_refs.h"
#include "objects.h"
#include "sections.h"
#include "pass2.h"
#include "generic_reloc.h"
#include "pass1.h"
#include "symbols.h"
#include "layout.h"
#include "literal_pointers.h"
#include "cstring_literals.h"
#include "4byte_literals.h"
#include "8byte_literals.h"
#include "dylibs.h"
static unsigned long lookup_literal_pointer(
struct merged_symbol *merged_symbol,
struct merged_section *literal_ms,
unsigned long merged_section_offset,
unsigned long offset,
struct literal_pointer_data *data,
struct merged_section *ms,
enum bool *new);
#ifndef RLD
static unsigned long literal_pointer_order_line(
unsigned long *line_start,
unsigned long line_number,
struct literal_pointer_data *data,
struct merged_section *ms,
char *buffer);
#endif
static void count_reloc(
struct merged_section *ms,
enum bool new,
unsigned long r_extern,
enum bool defined);
__private_extern__
void
literal_pointer_merge(
struct literal_pointer_data *data,
struct merged_section *ms,
struct section *s,
struct section_map *section_map,
enum bool redo_live)
{
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){
if(redo_live == FALSE){
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
if(redo_live == FALSE){
data->nfiles++;
data->nliterals += nliterals;
}
#endif
if(dead_strip == FALSE)
ms->relocated = TRUE;
if(redo_live == FALSE){
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;
}
else{
fine_relocs = section_map->fine_relocs;
nliterals = section_map->nfine_relocs;
}
relocs = (struct relocation_info *)(cur_obj->obj_addr + s->reloff);
literals = (char *)(cur_obj->obj_addr + s->offset);
if(cur_obj->swapped && section_map->input_relocs_already_swapped == FALSE){
swap_relocation_info(relocs, s->nreloc, host_byte_sex);
section_map->input_relocs_already_swapped = TRUE;
}
merged_symbol = NULL;
for(i = s->nreloc - 1; i >= 0 ; i--){
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;
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){
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;
}
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;
}
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){
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;
}
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((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
merged_symbol = (struct merged_symbol *)
merged_symbol->nlist.n_value;
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((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;
}
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
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(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 {
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;
merged_section_offset = fine_reloc_output_offset(literal_map,
input_section_offset);
offset = get_long((long *)(literals + r_address));
merged_symbol = NULL;
literal_map->output_section->referenced = TRUE;
}
}
else{
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;
merged_section_offset = fine_reloc_output_offset(literal_map,
input_section_offset);
literal_map->output_section->referenced = TRUE;
}
if(redo_live == FALSE &&
(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;
}
if(redo_live == FALSE){
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);
}
else{
if(fine_relocs[r_address/4].live == TRUE){
ms->relocated = TRUE;
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);
}
else{
fine_relocs[r_address/4].output_offset = 0;
}
}
}
}
static void
count_reloc(
struct merged_section *ms,
enum bool new,
unsigned long r_extern,
enum bool defined)
{
if(output_for_dyld && new == TRUE){
if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
ms->nlocrel++;
}
else if(has_dynamic_linker_command){
if(r_extern)
if(defined == FALSE)
ms->nextrel++;
}
else{
if(r_extern){
if(defined == FALSE)
ms->nextrel++;
else
ms->nlocrel++;
}
else
ms->nlocrel++;
}
}
else if(save_reloc && new == TRUE){
ms->s.nreloc++;
nreloc++;
}
}
__private_extern__
void
literal_pointer_order(
struct literal_pointer_data *data,
struct merged_section *ms)
{
#ifndef RLD
unsigned long i, line_number, line_length, max_line_length, output_offset;
char *buffer;
kern_return_t r;
struct literal_pointer_order_line *order_lines;
line_number = 1;
line_length = 1;
max_line_length = 1;
for(i = 0; i < ms->order_size; i++){
if(ms->order_addr[i] == '\0'){
fatal("format error in -sectorder file: %s line %lu character "
"possition %lu for section (%.16s,%.16s) (illegal null "
"character \'\\0\' found)", ms->order_filename,
line_number, line_length, ms->s.segname, ms->s.sectname);
}
if(ms->order_addr[i] == '\n'){
ms->order_addr[i] = '\0';
if(line_length > max_line_length)
max_line_length = line_length;
line_length = 1;
line_number++;
}
else
line_length++;
}
buffer = allocate(max_line_length + 1);
order_lines = NULL;
if(dead_strip == TRUE){
data->literal_pointer_load_order_data =
allocate(sizeof(struct literal_pointer_load_order_data));
order_lines = allocate(sizeof(struct literal_pointer_order_line) *
(line_number - 1));
data->literal_pointer_load_order_data->order_line_buffer =
buffer;
data->literal_pointer_load_order_data->literal_pointer_order_lines =
order_lines;
data->literal_pointer_load_order_data->nliteral_pointer_order_lines
= (line_number - 1);
}
line_number = 1;
for(i = 0; i < ms->order_size; i++){
if(dead_strip == TRUE){
order_lines[line_number - 1].character_index = i;
order_lines[line_number - 1].line_number = line_number;
}
output_offset = literal_pointer_order_line(&i, line_number, data,
ms, buffer);
if(dead_strip == TRUE)
order_lines[line_number - 1].output_offset = output_offset;
while(i < ms->order_size && ms->order_addr[i] != '\0')
i++;
line_number++;
}
if(dead_strip == FALSE){
free(buffer);
if((r = vm_deallocate(mach_task_self(), (vm_address_t)
ms->order_addr, ms->order_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() memory for -sectorder "
"file: %s for section (%.16s,%.16s)",
ms->order_filename, ms->s.segname,
ms->s.sectname);
ms->order_addr = NULL;
}
#endif
}
#ifndef RLD
static
unsigned long
literal_pointer_order_line(
unsigned long *line_start,
unsigned long line_number,
struct literal_pointer_data *data,
struct merged_section *ms,
char *buffer)
{
unsigned long i, j, char_pos, output_offset, merged_section_offset;
char segname[17], sectname[17];
struct merged_section *literal_ms;
struct literal8 literal8;
struct literal4 literal4;
enum bool new;
output_offset = 0;
i = *line_start;
char_pos = 1;
j = 0;
while(i < ms->order_size &&
ms->order_addr[i] != ':' &&
ms->order_addr[i] != '\0'){
if(j <= 16)
segname[j++] = ms->order_addr[i++];
else
i++;
char_pos++;
}
if(i >= ms->order_size || ms->order_addr[i] == '\0'){
error("format error in -sectorder file: %s line %lu for section"
" (%.16s,%.16s) (missing ':' after segment name)",
ms->order_filename, line_number, ms->s.segname,
ms->s.sectname);
*line_start = i;
return(output_offset);
}
segname[j] = '\0';
i++;
char_pos++;
j = 0;
while(i < ms->order_size &&
ms->order_addr[i] != ':' &&
ms->order_addr[i] != '\0'){
if(j <= 16)
sectname[j++] = ms->order_addr[i++];
else
i++;
char_pos++;
}
if(i >= ms->order_size || ms->order_addr[i] == '\0'){
error("format error in -sectorder file: %s line %lu for section"
" (%.16s,%.16s) (missing ':' after section name)",
ms->order_filename, line_number, ms->s.segname,
ms->s.sectname);
*line_start = i;
return(output_offset);
}
sectname[j] = '\0';
i++;
char_pos++;
literal_ms = lookup_merged_section(segname, sectname);
if(literal_ms == NULL){
error("error in -sectorder file: %s line %lu for section "
"(%.16s,%.16s) (specified section (%s,%s) is not "
"loaded objects)", ms->order_filename, line_number,
ms->s.segname, ms->s.sectname, segname, sectname);
}
else{
switch(literal_ms->s.flags & SECTION_TYPE){
case S_CSTRING_LITERALS:
get_cstring_from_sectorder(ms, &i, buffer, line_number,
char_pos);
merged_section_offset = lookup_cstring(buffer,
literal_ms->literal_data, literal_ms);
output_offset = lookup_literal_pointer(NULL, literal_ms,
merged_section_offset, 0, data, ms, &new);
count_reloc(ms, new, 0, FALSE);
break;
case S_4BYTE_LITERALS:
if(get_hex_from_sectorder(ms, &i, &(literal4.long0),
line_number) == TRUE){
merged_section_offset = lookup_literal4(literal4,
literal_ms->literal_data, literal_ms);
output_offset = lookup_literal_pointer(NULL, literal_ms,
merged_section_offset, 0, data, ms, &new);
count_reloc(ms, new, 0, FALSE);
}
else{
error("error in -sectorder file: %s line %lu for "
"section (%.16s,%.16s) (missing hex number for "
"specified 4 byte literal section (%s,%s))",
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname, segname, sectname);
}
break;
case S_8BYTE_LITERALS:
if(get_hex_from_sectorder(ms, &i, &(literal8.long0),
line_number) == TRUE){
if(get_hex_from_sectorder(ms, &i, &(literal8.long1),
line_number) == TRUE){
merged_section_offset = lookup_literal8(literal8,
literal_ms->literal_data,
literal_ms);
output_offset = lookup_literal_pointer(NULL, literal_ms,
merged_section_offset, 0, data, ms, &new);
count_reloc(ms, new, 0, FALSE);
}
else{
error("error in -sectorder file: %s line %lu for "
"section (%.16s,%.16s) (missing second hex "
"number for specified 8 byte literal section "
"(%s,%s))", ms->order_filename, line_number,
ms->s.segname, ms->s.sectname, segname,
sectname);
}
}
else{
error("error in -sectorder file: %s line %lu for "
"section (%.16s,%.16s) (missing first hex number "
"for specified 8 byte literal section (%s,%s))",
ms->order_filename, line_number,
ms->s.segname, ms->s.sectname, segname, sectname);
}
break;
default:
error("error in -sectorder file: %s line %lu for section "
"(%.16s,%.16s) (specified section (%s,%s) is not a "
"literal section)", ms->order_filename, line_number,
ms->s.segname, ms->s.sectname, segname, sectname);
break;
}
}
*line_start = i;
return(output_offset);
}
#endif
__private_extern__
void
literal_pointer_reset_live(
struct literal_pointer_data *data,
struct merged_section *ms)
{
#ifndef RLD
unsigned long i, norder_lines, line_number, character_index, output_offset;
char *buffer;
struct literal_pointer_order_line *order_lines;
enum bool live;
kern_return_t r;
ms->s.size = 0;
if(output_for_dyld){
ms->nlocrel = 0;
ms->nextrel = 0;
}
else if(save_reloc){
nreloc -= ms->s.nreloc;
ms->s.nreloc = 0;
}
literal_pointer_free(data);
if(ms->order_filename != NULL){
buffer = data->literal_pointer_load_order_data->order_line_buffer;
order_lines = data->literal_pointer_load_order_data->
literal_pointer_order_lines;
norder_lines = data->literal_pointer_load_order_data->
nliteral_pointer_order_lines;
for(i = 0; i < norder_lines; i++){
live = is_literal_output_offset_live(
ms, order_lines[i].output_offset);
line_number = order_lines[i].line_number;
if(live){
character_index = order_lines[i].character_index;
output_offset = literal_pointer_order_line(
&character_index, line_number, data, ms, buffer);
}
else{
if(sectorder_detail == TRUE)
warning("specification of literal pointer in "
"-sectorder file: %s on line %lu for section "
"(%.16s,%.16s) not used (dead stripped)",
ms->order_filename, line_number, ms->s.segname,
ms->s.sectname);
}
}
free(data->literal_pointer_load_order_data->order_line_buffer);
free(data->literal_pointer_load_order_data->
literal_pointer_order_lines);
free(data->literal_pointer_load_order_data);
data->literal_pointer_load_order_data = NULL;
if((r = vm_deallocate(mach_task_self(), (vm_address_t)
ms->order_addr, ms->order_size)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_deallocate() memory for -sectorder "
"file: %s for section (%.16s,%.16s)",
ms->order_filename, ms->s.segname,
ms->s.sectname);
ms->order_addr = NULL;
}
#endif
}
static
unsigned long
lookup_literal_pointer(
struct merged_symbol *merged_symbol,
struct merged_section *literal_ms,
unsigned long merged_section_offset,
unsigned long offset,
struct literal_pointer_data *data,
struct merged_section *ms,
enum bool *new)
{
unsigned long hashval, output_offset;
struct literal_pointer_block **p, *literal_pointer_block;
struct literal_pointer *literal_pointer;
struct literal_pointer_bucket *bp;
*new = FALSE;
if(data->hashtable == NULL){
data->hashtable = allocate(sizeof(struct literal_pointer_bucket *) *
LITERAL_POINTER_HASHSIZE);
memset(data->hashtable, '\0',
sizeof(struct literal_pointer_bucket *) *
LITERAL_POINTER_HASHSIZE);
}
#if defined(DEBUG) && defined(PROBE_COUNT)
data->nprobes++;
#endif
hashval = ((long)merged_symbol + (long)literal_ms +
merged_section_offset + offset) % LITERAL_POINTER_HASHSIZE;
for(bp = data->hashtable[hashval]; bp; bp = bp->next){
#if defined(DEBUG) && defined(PROBE_COUNT)
data->nprobes++;
#endif
if(bp->literal_pointer->merged_symbol == merged_symbol &&
bp->literal_pointer->literal_ms == literal_ms &&
bp->literal_pointer->merged_section_offset ==
merged_section_offset &&
bp->literal_pointer->offset == offset)
return(bp->output_offset);
}
bp = allocate(sizeof(struct literal_pointer_bucket));
output_offset = 0;
for(p = &(data->literal_pointer_blocks);
*p ;
p = &(literal_pointer_block->next)){
literal_pointer_block = *p;
if(literal_pointer_block->used != LITERAL_POINTER_BLOCK_SIZE){
literal_pointer = literal_pointer_block->literal_pointers +
literal_pointer_block->used;
literal_pointer->merged_symbol = merged_symbol;
literal_pointer->literal_ms = literal_ms;
literal_pointer->merged_section_offset = merged_section_offset;
literal_pointer->offset = offset;
bp->literal_pointer = literal_pointer;
bp->output_offset = output_offset +
literal_pointer_block->used * 4;
bp->next = data->hashtable[hashval];
data->hashtable[hashval] = bp;
literal_pointer_block->used++;
ms->s.size += 4;
*new = TRUE;
return(bp->output_offset);
}
output_offset += literal_pointer_block->used * 4;
}
*p = allocate(sizeof(struct literal_pointer_block));
literal_pointer_block = *p;
literal_pointer = literal_pointer_block->literal_pointers;
literal_pointer->merged_symbol = merged_symbol;
literal_pointer->literal_ms = literal_ms;
literal_pointer->merged_section_offset = merged_section_offset;
literal_pointer->offset = offset;
literal_pointer_block->used = 1;
literal_pointer_block->next = NULL;
bp->literal_pointer = literal_pointer;
bp->output_offset = output_offset;
bp->next = data->hashtable[hashval];
data->hashtable[hashval] = bp;
ms->s.size += 4;
*new = TRUE;
return(bp->output_offset);
}
__private_extern__
void
literal_pointer_output(
struct literal_pointer_data *data,
struct merged_section *ms)
{
unsigned long i;
long *output_pointer;
struct literal_pointer_block **p, *literal_pointer_block;
struct literal_pointer *literal_pointers;
#ifndef RLD
struct relocation_info *reloc, *extreloc, *r;
struct scattered_relocation_info *sreloc;
unsigned long r_address;
#endif
output_pointer = (long *)(output_addr + ms->s.offset);
for(p = &(data->literal_pointer_blocks);
*p ;
p = &(literal_pointer_block->next)){
literal_pointer_block = *p;
literal_pointers = literal_pointer_block->literal_pointers;
for(i = 0; i < literal_pointer_block->used; i++){
if(literal_pointers[i].merged_symbol != NULL){
*output_pointer = literal_pointers[i].offset;
}
else{
*output_pointer =
literal_pointers[i].literal_ms->s.addr +
literal_pointers[i].merged_section_offset +
literal_pointers[i].offset;
}
if(host_byte_sex != target_byte_sex)
*output_pointer = SWAP_LONG(*output_pointer);
output_pointer++;
}
}
#ifndef RLD
output_flush(ms->s.offset,
(char *)output_pointer - (char *)(output_addr + ms->s.offset));
if(save_reloc || output_for_dyld){
if(output_for_dyld){
extreloc = (struct relocation_info *)(output_addr +
output_dysymtab_info.dysymtab_command.extreloff +
ms->iextrel * sizeof(struct relocation_info));
reloc = (struct relocation_info *)(output_addr +
output_dysymtab_info.dysymtab_command.locreloff +
ms->ilocrel * sizeof(struct relocation_info));
sreloc = (struct scattered_relocation_info *)reloc;
if(segs_read_only_addr_specified == TRUE)
r_address = ms->s.addr - segs_read_write_addr;
else
r_address = ms->s.addr - merged_segments->sg.vmaddr;
}
else{
extreloc = NULL;
reloc = (struct relocation_info *)(output_addr + ms->s.reloff);
sreloc = (struct scattered_relocation_info *)reloc;
r_address = 0;
}
for(p = &(data->literal_pointer_blocks);
*p ;
p = &(literal_pointer_block->next)){
literal_pointer_block = *p;
literal_pointers = literal_pointer_block->literal_pointers;
for(i = 0; i < literal_pointer_block->used; i++){
if(literal_pointers[i].merged_symbol != NULL){
if(output_for_dyld)
r = extreloc;
else
r = reloc;
r->r_address = r_address;
r->r_symbolnum =
merged_symbol_output_index(
literal_pointers[i].merged_symbol);
r->r_pcrel = 0;
r->r_length = 2;
r->r_extern = 1;
r->r_type = 0;
if(output_for_dyld)
extreloc++;
else
reloc++;
}
else if(literal_pointers[i].offset == 0){
reloc->r_address = r_address;
reloc->r_symbolnum =
literal_pointers[i].literal_ms->output_sectnum;
reloc->r_pcrel = 0;
reloc->r_length = 2;
reloc->r_extern = 0;
reloc->r_type = 0;
reloc++;
sreloc++;
}
else{
sreloc->r_scattered = 1;
sreloc->r_pcrel = 0;
sreloc->r_length = 2;
sreloc->r_type = 0;
sreloc->r_address = r_address;
sreloc->r_value =
literal_pointers[i].literal_ms->s.addr +
literal_pointers[i].merged_section_offset;
reloc++;
sreloc++;
}
r_address += 4;
}
}
if(output_for_dyld){
if(host_byte_sex != target_byte_sex){
swap_relocation_info((struct relocation_info *)
(output_addr +
output_dysymtab_info.dysymtab_command.extreloff +
ms->iextrel * sizeof(struct relocation_info)),
ms->nextrel, target_byte_sex);
swap_relocation_info((struct relocation_info *)
(output_addr +
output_dysymtab_info.dysymtab_command.locreloff +
ms->ilocrel * sizeof(struct relocation_info)),
ms->nlocrel, target_byte_sex);
}
output_flush(output_dysymtab_info.dysymtab_command.extreloff +
ms->iextrel * sizeof(struct relocation_info),
ms->nextrel * sizeof(struct relocation_info));
output_flush(output_dysymtab_info.dysymtab_command.locreloff +
ms->ilocrel * sizeof(struct relocation_info),
ms->nlocrel * sizeof(struct relocation_info));
}
else{
if(host_byte_sex != target_byte_sex)
swap_relocation_info((struct relocation_info *)
(output_addr + ms->s.reloff), ms->s.nreloc,
target_byte_sex);
output_flush(ms->s.reloff,
ms->s.nreloc * sizeof(struct relocation_info));
}
}
#endif
literal_pointer_free(data);
}
__private_extern__
void
literal_pointer_free(
struct literal_pointer_data *data)
{
unsigned long i;
struct literal_pointer_bucket *bp, *next_bp;
struct literal_pointer_block *literal_pointer_block,
*next_literal_pointer_block;
if(data->hashtable != NULL){
for(i = 0; i < LITERAL_POINTER_HASHSIZE; i++){
for(bp = data->hashtable[i]; bp; ){
next_bp = bp->next;
free(bp);
bp = next_bp;
}
}
free(data->hashtable);
data->hashtable = NULL;
}
for(literal_pointer_block = data->literal_pointer_blocks;
literal_pointer_block;
literal_pointer_block = next_literal_pointer_block){
next_literal_pointer_block = literal_pointer_block->next;
free(literal_pointer_block);
}
data->literal_pointer_blocks = NULL;
}
#ifdef DEBUG
__private_extern__
void
print_literal_pointer_data(
struct literal_pointer_data *data,
char *indent)
{
unsigned long i;
struct literal_pointer_block **p, *literal_pointer_block;
struct literal_pointer *literal_pointers;
print("%sliteral pointer data at 0x%x\n", indent, (unsigned int)data);
if(data == NULL)
return;
for(p = &(data->literal_pointer_blocks);
*p ;
p = &(literal_pointer_block->next)){
literal_pointer_block = *p;
literal_pointers = literal_pointer_block->literal_pointers;
print("%sused %lu\n", indent, literal_pointer_block->used);
for(i = 0; i < literal_pointer_block->used; i++){
if(literal_pointers[i].merged_symbol != NULL){
print("%s symbol %s offset %lu\n", indent,
literal_pointers[i].merged_symbol->nlist.n_un.n_name,
literal_pointers[i].offset);
}
else{
print("%s section (%.16s,%.16s) section_offset %lu "
"offset %lu\n", indent,
literal_pointers[i].literal_ms->s.segname,
literal_pointers[i].literal_ms->s.sectname,
literal_pointers[i].merged_section_offset,
literal_pointers[i].offset);
}
}
}
}
__private_extern__
void
literal_pointer_data_stats(
struct literal_pointer_data *data,
struct merged_section *ms)
{
if(data == NULL)
return;
print("literal pointer section (%.16s,%.16s) contains:\n",
ms->s.segname, ms->s.sectname);
print(" %u merged literal pointers\n", ms->s.size / 4);
print(" from %lu files and %lu total literal pointers from those "
"files\n", data->nfiles, data->nliterals);
print(" average number of literals per file %g\n",
(double)((double)data->nliterals / (double)(data->nfiles)));
if(data->nprobes != 0){
print(" average number of hash probes %g\n",
(double)((double)data->nprobes / (double)(data->nliterals)));
}
}
#endif