#ifdef SHLIB
#include "shlib.h"
#endif
#include <stdlib.h>
#if !(defined(KLD) && defined(__STATIC__))
#include <stdio.h>
#include <mach/mach.h>
#else
#include <mach/kern_return.h>
#endif
#include <stdarg.h>
#include <string.h>
#include <mach-o/loader.h>
#include "stuff/bool.h"
#include "stuff/bytesex.h"
#include "ld.h"
#include "live_refs.h"
#include "objects.h"
#include "sections.h"
#include "4byte_literals.h"
#include "8byte_literals.h"
#include "pass2.h"
__private_extern__
void
literal4_merge(
struct literal4_data *data,
struct merged_section *ms,
struct section *s,
struct section_map *section_map,
enum bool redo_live)
{
unsigned long nliteral4s, i;
struct literal4 *literal4s;
struct fine_reloc *fine_relocs;
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("4 byte literal section (%.16s,%.16s) size is "
"not a multiple of 4 bytes", ms->s.segname,
ms->s.sectname);
return;
}
nliteral4s = s->size / 4;
#ifdef DEBUG
if(redo_live == FALSE){
data->nfiles++;
data->nliterals += nliteral4s;
}
#endif
if(redo_live == FALSE){
fine_relocs = allocate(nliteral4s * sizeof(struct fine_reloc));
memset(fine_relocs, '\0', nliteral4s * sizeof(struct fine_reloc));
literal4s = (struct literal4 *)(cur_obj->obj_addr + s->offset);
for(i = 0; i < nliteral4s; i++){
fine_relocs[i].input_offset = i * 4;
fine_relocs[i].output_offset =
lookup_literal4(literal4s[i], data, ms);
}
section_map->fine_relocs = fine_relocs;
section_map->nfine_relocs = nliteral4s;
}
else{
fine_relocs = section_map->fine_relocs;
nliteral4s = section_map->nfine_relocs;
literal4s = (struct literal4 *)(cur_obj->obj_addr + s->offset);
for(i = 0; i < nliteral4s; i++){
if(fine_relocs[i].live == TRUE){
fine_relocs[i].output_offset =
lookup_literal4(literal4s[i], data, ms);
}
else{
fine_relocs[i].output_offset = 0;
}
}
}
}
__private_extern__
void
literal4_order(
struct literal4_data *data,
struct merged_section *ms)
{
#ifndef RLD
unsigned long i, line_number, output_offset, nliteral4_order_lines;
struct literal4 literal4;
struct literal4_order_line *literal4_order_lines;
literal4_order_lines = NULL;
if(dead_strip == TRUE){
line_number = 1;
i = 0;
while(i < ms->order_size){
while(i < ms->order_size && ms->order_addr[i] != '\n')
i++;
if(i < ms->order_size && ms->order_addr[i] == '\n')
i++;
line_number++;
}
data->literal4_load_order_data =
allocate(sizeof(struct literal4_load_order_data));
literal4_order_lines = allocate(sizeof(struct literal4_order_line) *
(line_number - 1));
data->literal4_load_order_data->literal4_order_lines =
literal4_order_lines;
}
line_number = 1;
i = 0;
nliteral4_order_lines = 0;
while(i < ms->order_size){
if(get_hex_from_sectorder(ms, &i, &(literal4.long0), line_number) ==
TRUE){
output_offset = lookup_literal4(literal4, data, ms);
if(dead_strip == TRUE){
literal4_order_lines[nliteral4_order_lines].literal4 =
literal4;
literal4_order_lines[nliteral4_order_lines].line_number =
line_number;
literal4_order_lines[nliteral4_order_lines].output_offset =
output_offset;
nliteral4_order_lines++;
}
}
while(i < ms->order_size && ms->order_addr[i] != '\n')
i++;
if(i < ms->order_size && ms->order_addr[i] == '\n')
i++;
line_number++;
}
if(dead_strip == TRUE)
data->literal4_load_order_data->nliteral4_order_lines =
nliteral4_order_lines;
#endif
}
__private_extern__
void
literal4_reset_live(
struct literal4_data *data,
struct merged_section *ms)
{
#ifndef RLD
unsigned long i, nliteral4_order_lines, line_number;
struct literal4_order_line *literal4_order_lines;
enum bool live;
ms->s.size = 0;
literal4_free(data);
if(ms->order_filename != NULL){
literal4_order_lines =
data->literal4_load_order_data->literal4_order_lines;
nliteral4_order_lines =
data->literal4_load_order_data->nliteral4_order_lines;
for(i = 0; i < nliteral4_order_lines; i++){
live = is_literal_output_offset_live(
ms, literal4_order_lines[i].output_offset);
line_number = literal4_order_lines[i].line_number;
if(live){
(void)lookup_literal4(literal4_order_lines[i].literal4,
data, ms);
}
else{
if(sectorder_detail == TRUE)
warning("specification of 4-byte literal 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->literal4_load_order_data->literal4_order_lines);
free(data->literal4_load_order_data);
data->literal4_load_order_data = NULL;
}
#endif
}
__private_extern__
unsigned long
lookup_literal4(
struct literal4 literal4,
struct literal4_data *data,
struct merged_section *ms)
{
struct literal4_block **p, *literal4_block;
unsigned long align_multiplier, output_offset, i;
align_multiplier = 1;
if((1 << ms->s.align) > 4)
align_multiplier = (1 << ms->s.align) / 4;
output_offset = 0;
for(p = &(data->literal4_blocks); *p ; p = &(literal4_block->next)){
literal4_block = *p;
for(i = 0; i < literal4_block->used; i++){
if(literal4.long0 == literal4_block->literal4s[i].long0)
return(output_offset + i * 4 * align_multiplier);
}
if(literal4_block->used != LITERAL4_BLOCK_SIZE){
literal4_block->literal4s[i].long0 = literal4.long0;
literal4_block->used++;
ms->s.size += 4 * align_multiplier;
return(output_offset + i * 4 * align_multiplier);
}
output_offset += literal4_block->used * 4 * align_multiplier;
}
*p = allocate(sizeof(struct literal4_block));
literal4_block = *p;
literal4_block->used = 1;
literal4_block->literal4s[0].long0 = literal4.long0;
literal4_block->next = NULL;
ms->s.size += 4 * align_multiplier;
return(output_offset);
}
__private_extern__
void
literal4_output(
struct literal4_data *data,
struct merged_section *ms)
{
unsigned long align_multiplier, i, offset;
struct literal4_block **p, *literal4_block;
align_multiplier = 1;
if((1 << ms->s.align) > 4)
align_multiplier = (1 << ms->s.align) / 4;
offset = ms->s.offset;
for(p = &(data->literal4_blocks); *p ;){
literal4_block = *p;
for(i = 0; i < literal4_block->used; i++){
memcpy(output_addr + offset,
literal4_block->literal4s + i,
sizeof(struct literal4));
offset += 4 * align_multiplier;
}
p = &(literal4_block->next);
}
#ifndef RLD
output_flush(ms->s.offset, offset - ms->s.offset);
#endif
}
__private_extern__
void
literal4_free(
struct literal4_data *data)
{
struct literal4_block *literal4_block, *next_literal4_block;
for(literal4_block = data->literal4_blocks; literal4_block ;){
next_literal4_block = literal4_block->next;
free(literal4_block);
literal4_block = next_literal4_block;
}
data->literal4_blocks = NULL;
}
#ifdef DEBUG
__private_extern__
void
print_literal4_data(
struct literal4_data *data,
char *indent)
{
unsigned long i;
struct literal4_block **p, *literal4_block;
print("%s4 byte literal data at 0x%x\n", indent, (unsigned int)data);
if(data == NULL)
return;
print("%s literal4_blocks 0x%x\n", indent,
(unsigned int)(data->literal4_blocks));
for(p = &(data->literal4_blocks); *p ; p = &(literal4_block->next)){
literal4_block = *p;
print("%s\tused %lu\n", indent, literal4_block->used);
print("%s\tnext 0x%x\n", indent,
(unsigned int)(literal4_block->next));
print("%s\tliteral4s\n", indent);
for(i = 0; i < literal4_block->used; i++){
print("%s\t 0x%08x\n", indent,
(unsigned int)(literal4_block->literal4s[i].long0));
}
}
}
__private_extern__
void
literal4_data_stats(
struct literal4_data *data,
struct merged_section *ms)
{
if(data == NULL)
return;
print("literal4 section (%.16s,%.16s) contains:\n",
ms->s.segname, ms->s.sectname);
print(" %u merged literals \n", ms->s.size / 4);
print(" from %lu files and %lu total literals from those "
"files\n", data->nfiles, data->nliterals);
print(" average number of literals per file %g\n",
(double)((double)data->nliterals / (double)(data->nfiles)));
}
#endif