#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 "8byte_literals.h"
#include "pass2.h"
__private_extern__
void
literal8_merge(
struct literal8_data *data,
struct merged_section *ms,
struct section *s,
struct section_map *section_map,
enum bool redo_live)
{
unsigned long nliteral8s, i;
struct literal8 *literal8s;
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 % 8 != 0){
error_with_cur_obj("8 byte literal section (%.16s,%.16s) size is "
"not a multiple of 8 bytes", ms->s.segname,
ms->s.sectname);
return;
}
nliteral8s = s->size / 8;
#ifdef DEBUG
if(redo_live == FALSE){
data->nfiles++;
data->nliterals += nliteral8s;
}
#endif
if(redo_live == FALSE){
fine_relocs = allocate(nliteral8s * sizeof(struct fine_reloc));
memset(fine_relocs, '\0', nliteral8s * sizeof(struct fine_reloc));
literal8s = (struct literal8 *)(cur_obj->obj_addr + s->offset);
for(i = 0; i < nliteral8s; i++){
fine_relocs[i].input_offset = i * 8;
fine_relocs[i].output_offset =
lookup_literal8(literal8s[i], data, ms);
}
section_map->fine_relocs = fine_relocs;
section_map->nfine_relocs = nliteral8s;
}
else{
fine_relocs = section_map->fine_relocs;
nliteral8s = section_map->nfine_relocs;
literal8s = (struct literal8 *)(cur_obj->obj_addr + s->offset);
for(i = 0; i < nliteral8s; i++){
if(fine_relocs[i].live == TRUE){
fine_relocs[i].output_offset =
lookup_literal8(literal8s[i], data, ms);
}
else{
fine_relocs[i].output_offset = 0;
}
}
}
}
__private_extern__
void
literal8_order(
struct literal8_data *data,
struct merged_section *ms)
{
#ifndef RLD
unsigned long i, line_number, output_offset, nliteral8_order_lines;
struct literal8 literal8;
struct literal8_order_line *literal8_order_lines;
literal8_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->literal8_load_order_data =
allocate(sizeof(struct literal8_load_order_data));
literal8_order_lines = allocate(sizeof(struct literal8_order_line) *
(line_number - 1));
data->literal8_load_order_data->literal8_order_lines =
literal8_order_lines;
}
line_number = 1;
i = 0;
nliteral8_order_lines = 0;
while(i < ms->order_size){
if(get_hex_from_sectorder(ms, &i, &(literal8.long0),
line_number) == TRUE){
if(get_hex_from_sectorder(ms, &i, &(literal8.long1),
line_number) == TRUE){
output_offset = lookup_literal8(literal8, data, ms);
if(dead_strip == TRUE){
literal8_order_lines[nliteral8_order_lines].
literal8 = literal8;
literal8_order_lines[nliteral8_order_lines].
line_number = line_number;
literal8_order_lines[nliteral8_order_lines].
output_offset = output_offset;
nliteral8_order_lines++;
}
}
else
error("format error in -sectorder file: %s line %lu for "
"section (%.16s,%.16s) (missing second hex number)",
ms->order_filename, line_number, ms->s.segname,
ms->s.sectname);
}
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->literal8_load_order_data->nliteral8_order_lines =
nliteral8_order_lines;
#endif
}
__private_extern__
void
literal8_reset_live(
struct literal8_data *data,
struct merged_section *ms)
{
#ifndef RLD
unsigned long i, nliteral8_order_lines, line_number;
struct literal8_order_line *literal8_order_lines;
enum bool live;
ms->s.size = 0;
literal8_free(data);
if(ms->order_filename != NULL){
literal8_order_lines =
data->literal8_load_order_data->literal8_order_lines;
nliteral8_order_lines =
data->literal8_load_order_data->nliteral8_order_lines;
for(i = 0; i < nliteral8_order_lines; i++){
live = is_literal_output_offset_live(
ms, literal8_order_lines[i].output_offset);
line_number = literal8_order_lines[i].line_number;
if(live){
(void)lookup_literal8(literal8_order_lines[i].literal8,
data, ms);
}
else{
if(sectorder_detail == TRUE)
warning("specification of 8-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->literal8_load_order_data->literal8_order_lines);
free(data->literal8_load_order_data);
data->literal8_load_order_data = NULL;
}
#endif
}
__private_extern__
enum bool
get_hex_from_sectorder(
struct merged_section *ms,
unsigned long *index,
unsigned long *value,
unsigned long line_number)
{
unsigned long i, j;
char hex[9];
i = *index;
while(i < ms->order_size &&
(ms->order_addr[i] == ' ' ||
ms->order_addr[i] == '\t'))
i++;
if(i > ms->order_size){
*index = i;
return(FALSE);
}
if(i > ms->order_size || ms->order_addr[i] != '0'){
error("format error in -sectorder file: %s line %lu for section "
"(%.16s,%.16s) (missing hex number, no leading 0x found)",
ms->order_filename,line_number,ms->s.segname,ms->s.sectname);
*index = i;
return(FALSE);
}
i++;
if(i > ms->order_size || ms->order_addr[i] != 'x'){
error("format error in -sectorder file: %s line %lu for section "
"(%.16s,%.16s) (missing hex number, no leading 0x found)",
ms->order_filename,line_number,ms->s.segname,ms->s.sectname);
*index = i;
return(FALSE);
}
i++;
j = 0;
while(i < ms->order_size &&
((ms->order_addr[i] >= '0' && ms->order_addr[i] <= '9') ||
(ms->order_addr[i] >= 'a' && ms->order_addr[i] <= 'f') ||
(ms->order_addr[i] >= 'A' && ms->order_addr[i] <= 'F')) ){
if(j <= 8)
hex[j++] = ms->order_addr[i++];
else
i++;
}
if(j > 8){
error("format error in -sectorder file: %s line %lu for section "
"(%.16s,%.16s) (too many hex digits for 32 bit value)",
ms->order_filename,line_number,ms->s.segname,ms->s.sectname);
*index = i;
return(FALSE);
}
hex[j] = '\0';
*value = strtoul(hex, NULL, 16);
*index = i;
return(TRUE);
}
__private_extern__
unsigned long
lookup_literal8(
struct literal8 literal8,
struct literal8_data *data,
struct merged_section *ms)
{
struct literal8_block **p, *literal8_block;
unsigned long align_multiplier, output_offset, i;
align_multiplier = 1;
if((1 << ms->s.align) > 8)
align_multiplier = (1 << ms->s.align) / 8;
output_offset = 0;
for(p = &(data->literal8_blocks); *p ; p = &(literal8_block->next)){
literal8_block = *p;
for(i = 0; i < literal8_block->used; i++){
if(literal8.long0 == literal8_block->literal8s[i].long0 &&
literal8.long1 == literal8_block->literal8s[i].long1)
return(output_offset + i * 8 * align_multiplier);
}
if(literal8_block->used != LITERAL8_BLOCK_SIZE){
literal8_block->literal8s[i].long0 = literal8.long0;
literal8_block->literal8s[i].long1 = literal8.long1;
literal8_block->used++;
ms->s.size += 8 * align_multiplier;
return(output_offset + i * 8 * align_multiplier);
}
output_offset += literal8_block->used * 8 * align_multiplier;
}
*p = allocate(sizeof(struct literal8_block));
literal8_block = *p;
literal8_block->used = 1;
literal8_block->literal8s[0].long0 = literal8.long0;
literal8_block->literal8s[0].long1 = literal8.long1;
literal8_block->next = NULL;
ms->s.size += 8 * align_multiplier;
return(output_offset);
}
__private_extern__
void
literal8_output(
struct literal8_data *data,
struct merged_section *ms)
{
unsigned long align_multiplier, i, offset;
struct literal8_block **p, *literal8_block;
align_multiplier = 1;
if((1 << ms->s.align) > 8)
align_multiplier = (1 << ms->s.align) / 8;
offset = ms->s.offset;
for(p = &(data->literal8_blocks); *p ;){
literal8_block = *p;
for(i = 0; i < literal8_block->used; i++){
memcpy(output_addr + offset,
literal8_block->literal8s + i,
sizeof(struct literal8));
offset += 8 * align_multiplier;
}
p = &(literal8_block->next);
}
#ifndef RLD
output_flush(ms->s.offset, offset - ms->s.offset);
#endif
literal8_free(data);
}
__private_extern__
void
literal8_free(
struct literal8_data *data)
{
struct literal8_block *literal8_block, *next_literal8_block;
for(literal8_block = data->literal8_blocks; literal8_block ;){
next_literal8_block = literal8_block->next;
free(literal8_block);
literal8_block = next_literal8_block;
}
data->literal8_blocks = NULL;
}
#ifdef DEBUG
__private_extern__
void
print_literal8_data(
struct literal8_data *data,
char *indent)
{
unsigned long i;
struct literal8_block **p, *literal8_block;
print("%s8 byte literal data at 0x%x\n", indent, (unsigned int)data);
if(data == NULL)
return;
print("%s literal8_blocks 0x%x\n", indent,
(unsigned int)(data->literal8_blocks));
for(p = &(data->literal8_blocks); *p ; p = &(literal8_block->next)){
literal8_block = *p;
print("%s\tused %lu\n", indent, literal8_block->used);
print("%s\tnext 0x%x\n", indent,
(unsigned int)(literal8_block->next));
print("%s\tliteral8s\n", indent);
for(i = 0; i < literal8_block->used; i++){
print("%s\t 0x%08x 0x%08x\n", indent,
(unsigned int)(literal8_block->literal8s[i].long0),
(unsigned int)(literal8_block->literal8s[i].long1));
}
}
}
__private_extern__
void
literal8_data_stats(
struct literal8_data *data,
struct merged_section *ms)
{
if(data == NULL)
return;
print("literal8 section (%.16s,%.16s) contains:\n",
ms->s.segname, ms->s.sectname);
print(" %u merged literals \n", ms->s.size / 8);
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