#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/file.h>
#include <libc.h>
#include <mach/mach.h>
#include "arch64_32.h"
#include "stuff/openstep_mach.h"
#include <mach-o/loader.h>
#include <mach-o/reloc.h>
#include <mach-o/stab.h>
#ifdef I860
#include <mach-o/i860/reloc.h>
#endif
#ifdef M88K
#include <mach-o/m88k/reloc.h>
#endif
#ifdef PPC
#include <mach-o/ppc/reloc.h>
#endif
#ifdef HPPA
#include <mach-o/hppa/reloc.h>
#include "stuff/hppa.h"
#endif
#ifdef SPARC
#include <mach-o/sparc/reloc.h>
#endif
#ifdef ARM
#include <mach-o/arm/reloc.h>
#include "arm_reloc.h"
#endif
#if defined(I386) && defined(ARCH64)
#include <mach-o/x86_64/reloc.h>
#endif
#include "stuff/rnd.h"
#include "stuff/bytesex.h"
#include "stuff/errors.h"
#include "as.h"
#include "struc-symbol.h"
#include "symbols.h"
#include "frags.h"
#include "fixes.h"
#include "md.h"
#include "sections.h"
#include "messages.h"
#include "xmalloc.h"
#include "input-scrub.h"
#if defined(I386) && defined(ARCH64)
#include "i386.h"
#endif
#ifdef I860
#define RELOC_SECTDIFF I860_RELOC_SECTDIFF
#define RELOC_LOCAL_SECTDIFF I860_RELOC_SECTDIFF
#define RELOC_PAIR I860_RELOC_PAIR
#endif
#ifdef M88K
#define RELOC_SECTDIFF M88K_RELOC_SECTDIFF
#define RELOC_LOCAL_SECTDIFF M88K_RELOC_SECTDIFF
#define RELOC_PAIR M88K_RELOC_PAIR
#endif
#ifdef PPC
#define RELOC_SECTDIFF PPC_RELOC_SECTDIFF
#define RELOC_LOCAL_SECTDIFF PPC_RELOC_LOCAL_SECTDIFF
#define RELOC_PAIR PPC_RELOC_PAIR
#define PPC_RELOC_BR14_predicted (0x10 | PPC_RELOC_BR14)
#endif
#ifdef HPPA
#define RELOC_SECTDIFF HPPA_RELOC_SECTDIFF
#define RELOC_LOCAL_SECTDIFF HPPA_RELOC_SECTDIFF
#define RELOC_PAIR HPPA_RELOC_PAIR
#endif
#ifdef SPARC
#define RELOC_SECTDIFF SPARC_RELOC_SECTDIFF
#define RELOC_LOCAL_SECTDIFF SPARC_RELOC_SECTDIFF
#define RELOC_PAIR SPARC_RELOC_PAIR
#endif
#if defined(M68K) || defined(I386)
#define RELOC_SECTDIFF GENERIC_RELOC_SECTDIFF
#define RELOC_LOCAL_SECTDIFF GENERIC_RELOC_LOCAL_SECTDIFF
#define RELOC_PAIR GENERIC_RELOC_PAIR
#endif
#ifdef ARM
#define RELOC_SECTDIFF ARM_RELOC_SECTDIFF
#define RELOC_LOCAL_SECTDIFF ARM_RELOC_SECTDIFF
#define RELOC_PAIR ARM_RELOC_PAIR
#endif
static uint32_t ilocalsym = 0;
static uint32_t nlocalsym = 0;
static uint32_t iextdefsym = 0;
static uint32_t nextdefsym = 0;
static symbolS **extdefsyms = NULL;
static uint32_t iundefsym = 0;
static uint32_t nundefsym = 0;
static symbolS **undefsyms = NULL;
static uint32_t layout_indirect_symbols(
void);
static void layout_symbols(
int32_t *symbol_number,
int32_t *string_byte_count);
static int qsort_compare(
const symbolS **sym1,
const symbolS **sym2);
static uint32_t nrelocs_for_fix(
struct fix *fixP);
static uint32_t fix_to_relocation_entries(
struct fix *fixP,
uint64_t sect_addr,
struct relocation_info *riP,
uint32_t debug_section);
#ifdef I860
static void
I860_tweeks(void);
#endif
void
write_object(
char *out_file_name)
{
mach_header_t header;
segment_command_t reloc_segment;
struct symtab_command symbol_table;
struct dysymtab_command dynamic_symbol_table;
uint32_t section_type;
uint32_t *indirect_symbols;
isymbolS *isymbolP;
uint32_t i, j, nsects, nsyms, strsize, nindirectsyms;
uint32_t offset, zero;
struct frchain *frchainP, *p;
struct symbol *symbolP;
struct frag *fragP;
struct fix *fixP;
uint32_t output_size;
char *output_addr;
kern_return_t r;
enum byte_sex host_byte_sex;
uint32_t reloff, nrelocs;
int32_t count;
char *fill_literal;
int32_t fill_size;
int32_t num_bytes;
char *symbol_name;
int fd;
uint32_t local;
struct stat stat_buf;
#ifdef I860
I860_tweeks();
#endif
i = 0;
nsects = 0;
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
frchainP->frch_section.addr = frchainP->frch_root->fr_address;
frchainP->frch_section.size = frchainP->frch_last->fr_address -
frchainP->frch_root->fr_address;
nsects++;
}
nindirectsyms = layout_indirect_symbols();
nsyms = 0;
strsize = 0;
layout_symbols((int32_t *)&nsyms, (int32_t *)&strsize);
header.magic = MH_MAGIC_VALUE;
header.cputype = md_cputype;
if(archflag_cpusubtype != -1)
header.cpusubtype = archflag_cpusubtype;
else
header.cpusubtype = md_cpusubtype;
header.filetype = MH_OBJECT;
header.ncmds = 0;
header.sizeofcmds = 0;
if(nsects != 0){
header.ncmds += 1;
header.sizeofcmds += sizeof(segment_command_t) +
nsects * sizeof(section_t);
}
if(nsyms != 0){
header.ncmds += 1;
header.sizeofcmds += sizeof(struct symtab_command);
if(flagseen['k']){
header.ncmds += 1;
header.sizeofcmds += sizeof(struct dysymtab_command);
}
}
else
strsize = 0;
header.flags = 0;
if(subsections_via_symbols == TRUE)
header.flags |= MH_SUBSECTIONS_VIA_SYMBOLS;
#ifdef ARCH64
header.reserved = 0;
#endif
memset(&reloc_segment, '\0', sizeof(segment_command_t));
reloc_segment.cmd = LC_SEGMENT_VALUE;
reloc_segment.cmdsize = sizeof(segment_command_t) +
nsects * sizeof(section_t);
reloc_segment.vmaddr = 0;
reloc_segment.vmsize = 0;
reloc_segment.filesize = 0;
offset = header.sizeofcmds + sizeof(mach_header_t);
reloc_segment.fileoff = offset;
reloc_segment.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
reloc_segment.initprot= VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
reloc_segment.nsects = nsects;
reloc_segment.flags = 0;
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
section_type = frchainP->frch_section.flags & SECTION_TYPE;
if(section_type == S_ZEROFILL ||
section_type == S_THREAD_LOCAL_ZEROFILL)
continue;
for(p = frchainP->frch_next; p != NULL; p = p->frch_next){
section_type = p->frch_section.flags & SECTION_TYPE;
if(section_type != S_ZEROFILL &&
section_type != S_THREAD_LOCAL_ZEROFILL)
break;
}
if(p != NULL)
i = p->frch_section.addr - frchainP->frch_section.addr;
else
i = frchainP->frch_section.size;
reloc_segment.filesize += i;
frchainP->frch_section.offset = offset;
offset += i;
reloc_segment.vmsize = frchainP->frch_section.addr +
frchainP->frch_section.size;
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
section_type = frchainP->frch_section.flags & SECTION_TYPE;
if(section_type != S_ZEROFILL &&
section_type != S_THREAD_LOCAL_ZEROFILL)
continue;
reloc_segment.vmsize = frchainP->frch_section.addr +
frchainP->frch_section.size;
}
offset = rnd(offset, sizeof(int32_t));
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
frchainP->frch_section.nreloc = 0;
for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){
frchainP->frch_section.nreloc += nrelocs_for_fix(fixP);
}
}
offset = rnd(offset, sizeof(int32_t));
reloff = offset;
nrelocs = 0;
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
if(frchainP->frch_section.nreloc == 0)
frchainP->frch_section.reloff = 0;
else
frchainP->frch_section.reloff = offset;
offset += frchainP->frch_section.nreloc *
sizeof(struct relocation_info);
nrelocs += frchainP->frch_section.nreloc;
}
if(flagseen['k']){
dynamic_symbol_table.cmd = LC_DYSYMTAB;
dynamic_symbol_table.cmdsize = sizeof(struct dysymtab_command);
dynamic_symbol_table.ilocalsym = ilocalsym;
dynamic_symbol_table.nlocalsym = nlocalsym;
dynamic_symbol_table.iextdefsym = iextdefsym;
dynamic_symbol_table.nextdefsym = nextdefsym;
dynamic_symbol_table.iundefsym = iundefsym;
dynamic_symbol_table.nundefsym = nundefsym;
if(nindirectsyms == 0){
dynamic_symbol_table.nindirectsyms = 0;
dynamic_symbol_table.indirectsymoff = 0;
}
else{
dynamic_symbol_table.nindirectsyms = nindirectsyms;
dynamic_symbol_table.indirectsymoff = offset;
offset += nindirectsyms * sizeof(uint32_t);
}
dynamic_symbol_table.tocoff = 0;
dynamic_symbol_table.ntoc = 0;
dynamic_symbol_table.modtaboff = 0;
dynamic_symbol_table.nmodtab = 0;
dynamic_symbol_table.extrefsymoff = 0;
dynamic_symbol_table.nextrefsyms = 0;
dynamic_symbol_table.extreloff = 0;
dynamic_symbol_table.nextrel = 0;
dynamic_symbol_table.locreloff = 0;
dynamic_symbol_table.nlocrel = 0;
}
symbol_table.cmd = LC_SYMTAB;
symbol_table.cmdsize = sizeof(struct symtab_command);
if(nsyms == 0)
symbol_table.symoff = 0;
else
symbol_table.symoff = offset;
symbol_table.nsyms = nsyms;
offset += symbol_table.nsyms * sizeof(nlist_t);
if(strsize == 0)
symbol_table.stroff = 0;
else
symbol_table.stroff = offset;
symbol_table.strsize = rnd(strsize, sizeof(uint32_t));
offset += rnd(strsize, sizeof(uint32_t));
output_size = offset;
if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr,
output_size, TRUE)) != KERN_SUCCESS)
as_fatal("can't vm_allocate() buffer for output file of size %u",
output_size);
host_byte_sex = get_host_byte_sex();
offset = 0;
memcpy(output_addr + offset, &header, sizeof(mach_header_t));
if(host_byte_sex != md_target_byte_sex)
swap_mach_header_t((mach_header_t *)(output_addr + offset),
md_target_byte_sex);
offset += sizeof(mach_header_t);
if(nsects != 0){
memcpy(output_addr + offset, &reloc_segment,
sizeof(segment_command_t));
if(host_byte_sex != md_target_byte_sex)
swap_segment_command_t((segment_command_t *)
(output_addr + offset),
md_target_byte_sex);
offset += sizeof(segment_command_t);
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
memcpy(output_addr + offset, &(frchainP->frch_section),
sizeof(section_t));
if(host_byte_sex != md_target_byte_sex)
swap_section_t((section_t *)(output_addr + offset), 1,
md_target_byte_sex);
offset += sizeof(section_t);
}
if(nsyms != 0){
memcpy(output_addr + offset, &symbol_table,
sizeof(struct symtab_command));
if(host_byte_sex != md_target_byte_sex)
swap_symtab_command((struct symtab_command *)
(output_addr + offset),
md_target_byte_sex);
offset += sizeof(struct symtab_command);
}
if(flagseen['k']){
if(nsyms != 0){
memcpy(output_addr + offset, &dynamic_symbol_table,
sizeof(struct dysymtab_command));
if(host_byte_sex != md_target_byte_sex)
swap_dysymtab_command((struct dysymtab_command *)
(output_addr + offset),
md_target_byte_sex);
offset += sizeof(struct dysymtab_command);
}
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
offset = frchainP->frch_section.offset;
for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
know(fragP->fr_type == rs_fill);
memcpy(output_addr + offset, fragP->fr_literal, fragP->fr_fix);
offset += fragP->fr_fix;
fill_literal = fragP->fr_literal + fragP->fr_fix;
fill_size = fragP->fr_var;
num_bytes = fragP->fr_offset * fragP->fr_var;
for(count = 0; count < num_bytes; count += fill_size){
memcpy(output_addr + offset, fill_literal, fill_size);
offset += fill_size;
}
}
}
offset = symbol_table.symoff;
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
if((symbolP->sy_type & N_EXT) == 0){
symbol_name = symbolP->sy_name;
symbolP->sy_nlist.n_un.n_strx = symbolP->sy_name_offset;
if(symbolP->expression != 0) {
expressionS *exp;
exp = (expressionS *)symbolP->expression;
if((exp->X_add_symbol->sy_type & N_TYPE) == N_UNDF)
as_fatal("undefined symbol `%s' in operation setting "
"`%s'", exp->X_add_symbol->sy_name,
symbol_name);
if((exp->X_subtract_symbol->sy_type & N_TYPE) == N_UNDF)
as_fatal("undefined symbol `%s' in operation setting "
"`%s'", exp->X_subtract_symbol->sy_name,
symbol_name);
if(exp->X_add_symbol->sy_other !=
exp->X_subtract_symbol->sy_other)
as_fatal("invalid sections for operation on `%s' and "
"`%s' setting `%s'",exp->X_add_symbol->sy_name,
exp->X_subtract_symbol->sy_name, symbol_name);
symbolP->sy_nlist.n_value +=
exp->X_add_symbol->sy_value -
exp->X_subtract_symbol->sy_value;
}
memcpy(output_addr + offset, (char *)(&symbolP->sy_nlist),
sizeof(nlist_t));
symbolP->sy_name = symbol_name;
offset += sizeof(nlist_t);
}
}
for(i = 0; i < nextdefsym; i++){
symbol_name = extdefsyms[i]->sy_name;
extdefsyms[i]->sy_nlist.n_un.n_strx = extdefsyms[i]->sy_name_offset;
memcpy(output_addr + offset, (char *)(&extdefsyms[i]->sy_nlist),
sizeof(nlist_t));
extdefsyms[i]->sy_name = symbol_name;
offset += sizeof(nlist_t);
}
for(j = 0; j < nundefsym; j++){
symbol_name = undefsyms[j]->sy_name;
undefsyms[j]->sy_nlist.n_un.n_strx = undefsyms[j]->sy_name_offset;
memcpy(output_addr + offset, (char *)(&undefsyms[j]->sy_nlist),
sizeof(nlist_t));
undefsyms[j]->sy_name = symbol_name;
offset += sizeof(nlist_t);
}
if(host_byte_sex != md_target_byte_sex)
swap_nlist_t((nlist_t *)(output_addr + symbol_table.symoff),
symbol_table.nsyms, md_target_byte_sex);
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
offset = frchainP->frch_section.reloff;
for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){
offset += fix_to_relocation_entries(
fixP,
frchainP->frch_section.addr,
(struct relocation_info *)(output_addr +
offset),
frchainP->frch_section.flags &
S_ATTR_DEBUG);
}
}
if(host_byte_sex != md_target_byte_sex)
swap_relocation_info((struct relocation_info *)
(output_addr + reloff), nrelocs, md_target_byte_sex);
if(flagseen['k']){
offset = dynamic_symbol_table.indirectsymoff;
for(frchainP = frchain_root;
frchainP != NULL;
frchainP = frchainP->frch_next){
section_type = frchainP->frch_section.flags & SECTION_TYPE;
if(section_type == S_NON_LAZY_SYMBOL_POINTERS ||
section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_SYMBOL_STUBS){
for(isymbolP = frchainP->frch_isym_root;
isymbolP != NULL;
isymbolP = isymbolP->isy_next){
if(section_type == S_NON_LAZY_SYMBOL_POINTERS &&
(isymbolP->isy_symbol->sy_nlist.n_type & N_EXT) !=
N_EXT){
local = INDIRECT_SYMBOL_LOCAL;
if((isymbolP->isy_symbol->sy_nlist.n_type &
N_TYPE) == N_ABS)
local |= INDIRECT_SYMBOL_ABS;
memcpy(output_addr + offset, (char *)(&local),
sizeof(uint32_t));
}
else{
memcpy(output_addr + offset,
(char *)(&isymbolP->isy_symbol->sy_number),
sizeof(uint32_t));
}
offset += sizeof(uint32_t);
}
}
}
if(host_byte_sex != md_target_byte_sex){
indirect_symbols = (uint32_t *)(output_addr +
dynamic_symbol_table.indirectsymoff);
swap_indirect_symbols(indirect_symbols, nindirectsyms,
md_target_byte_sex);
}
}
offset = symbol_table.stroff;
if(symbol_table.strsize != 0){
zero = 0;
memcpy(output_addr + offset, (char *)&zero, sizeof(char));
offset += sizeof(char);
}
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
if(symbolP->sy_name != NULL){
if((symbolP->sy_type & N_EXT) != 0){
memcpy(output_addr + offset, symbolP->sy_name,
strlen(symbolP->sy_name) + 1);
offset += strlen(symbolP->sy_name) + 1;
}
}
}
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
if(symbolP->sy_name != NULL){
if((symbolP->sy_type & N_EXT) == 0){
memcpy(output_addr + offset, symbolP->sy_name,
strlen(symbolP->sy_name) + 1);
offset += strlen(symbolP->sy_name) + 1;
}
}
}
if(bad_error != 0)
return;
if(stat(out_file_name, &stat_buf) != -1){
if(stat_buf.st_mode & S_IFREG)
(void)unlink(out_file_name);
}
if((fd = open(out_file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1)
as_fatal("can't create output file: %s", out_file_name);
if(write(fd, output_addr, output_size) != (int)output_size)
as_fatal("can't write output file");
if(close(fd) == -1)
as_fatal("can't close output file");
}
static
uint32_t
layout_indirect_symbols(void)
{
struct frchain *frchainP;
uint32_t section_type, total, count, stride;
isymbolS *isymbolP;
symbolS *symbolP;
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
section_type = frchainP->frch_section.flags & SECTION_TYPE;
if(section_type == S_NON_LAZY_SYMBOL_POINTERS){
for(isymbolP = frchainP->frch_isym_root;
isymbolP != NULL;
isymbolP = isymbolP->isy_next){
symbolP = symbol_find(isymbolP->isy_name);
if(symbolP == NULL){
symbolP = symbol_new(isymbolP->isy_name, N_UNDF, 0, 0,
0, &zero_address_frag);
symbol_table_insert(symbolP);
}
}
}
}
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
section_type = frchainP->frch_section.flags & SECTION_TYPE;
if(section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_SYMBOL_STUBS){
for(isymbolP = frchainP->frch_isym_root;
isymbolP != NULL;
isymbolP = isymbolP->isy_next){
symbolP = symbol_find(isymbolP->isy_name);
if(symbolP == NULL){
symbolP = symbol_find_or_make(isymbolP->isy_name);
symbolP->sy_desc |= REFERENCE_FLAG_UNDEFINED_LAZY;
}
}
}
}
total = 0;
for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
section_type = frchainP->frch_section.flags & SECTION_TYPE;
if(section_type == S_LAZY_SYMBOL_POINTERS ||
section_type == S_NON_LAZY_SYMBOL_POINTERS ||
section_type == S_SYMBOL_STUBS){
count = 0;
for(isymbolP = frchainP->frch_isym_root;
isymbolP != NULL;
isymbolP = isymbolP->isy_next){
symbolP = symbol_find(isymbolP->isy_name);
if(symbolP == NULL){
symbolP = symbol_new(isymbolP->isy_name, N_UNDF, 0, 0,
0, &zero_address_frag);
symbol_table_insert(symbolP);
}
isymbolP->isy_symbol = symbolP;
count++;
}
if(section_type == S_SYMBOL_STUBS)
stride = frchainP->frch_section.reserved2;
else
stride = sizeof(signed_target_addr_t);
if(frchainP->frch_section.size / stride != count)
as_bad("missing indirect symbols for section (%s,%s)",
frchainP->frch_section.segname,
frchainP->frch_section.sectname);
frchainP->frch_section.reserved1 = total;
total += count;
}
}
return(total);
}
static
void
set_BINCL_checksums()
{
struct HeaderRange {
symbolS* bincl;
struct HeaderRange* parentRange;
unsigned int sum;
int okToChecksum;
};
symbolS *symbolP;
struct HeaderRange* curRange = NULL;
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
if((symbolP->sy_nlist.n_type & N_STAB) != 0){
switch(symbolP->sy_nlist.n_type){
case N_BINCL:
{
struct HeaderRange* range =
xmalloc(sizeof(struct HeaderRange));
range->bincl = symbolP;
range->parentRange = curRange;
range->sum = 0;
range->okToChecksum = (symbolP->sy_nlist.n_value == 0);
curRange = range;
}
break;
case N_EINCL:
if(curRange != NULL){
struct HeaderRange* tmp = curRange;
if (curRange->okToChecksum)
curRange->bincl->sy_nlist.n_value = curRange->sum;
curRange = tmp->parentRange;
free(tmp);
}
break;
case N_FUN:
case N_BNSYM:
case N_ENSYM:
case N_LBRAC:
case N_RBRAC:
case N_SLINE:
case N_STSYM:
case N_LCSYM:
if(curRange != NULL){
curRange->okToChecksum = FALSE;
}
break;
case N_EXCL:
break;
default:
if(curRange != NULL){
if(curRange->okToChecksum){
unsigned int sum = 0;
const char* s = symbolP->sy_name;
char c;
while((c = *s++) != '\0'){
sum += c;
if(c == '('){
while(isdigit(*s))
++s;
}
}
curRange->sum += sum;
}
}
}
}
}
}
static
void
layout_symbols(
int32_t *symbol_number,
int32_t *string_byte_count)
{
uint32_t i, j;
symbolS *symbolP;
symbolS **symbolPP;
char *name;
int seenBINCL = FALSE;
*symbol_number = 0;
*string_byte_count = sizeof(char);
symbolPP = &symbol_rootP;
while((symbolP = *symbolPP)){
name = symbolP->sy_name;
if(name != NULL &&
(symbolP->sy_nlist.n_type & N_STAB) == 0 &&
name[0] == 'L'){
if((symbolP->sy_nlist.n_type & N_TYPE) == N_UNDF){
if(name[1] != '\0' && name[2] == '\001'){
as_bad("Undefined local symbol %c (%cf or %cb)",
name[1], name[1], name[1]);
}
else{
as_bad("Undefined local symbol %s", name);
}
*symbolPP = symbolP->sy_next;
}
else if(flagseen['L'] || (symbolP->sy_type & N_EXT) != 0
#if defined(I386) && defined(ARCH64)
|| is_section_cstring_literals(symbolP->sy_other)
#endif
){
if((symbolP->sy_type & N_EXT) == 0){
nlocalsym++;
symbolP->sy_number = *symbol_number;
*symbol_number = *symbol_number + 1;
}
else{
nextdefsym++;
symbolP->sy_name_offset = *string_byte_count;
*string_byte_count += strlen(symbolP->sy_name) + 1;
}
symbolPP = &(symbolP->sy_next);
}
else{
*symbolPP = symbolP->sy_next;
}
}
else{
if(symbolP->sy_type == N_UNDF)
symbolP->sy_type |= N_EXT;
if((symbolP->sy_type & N_EXT) == 0){
symbolP->sy_number = *symbol_number;
*symbol_number = *symbol_number + 1;
nlocalsym++;
}
else{
if((symbolP->sy_type & N_TYPE) != N_UNDF)
nextdefsym++;
else
nundefsym++;
if(name != NULL){
symbolP->sy_name_offset = *string_byte_count;
*string_byte_count += strlen(symbolP->sy_name) + 1;
}
else{
symbolP->sy_name_offset = 0;
}
}
symbolPP = &(symbolP->sy_next);
}
}
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
if((symbolP->sy_nlist.n_type & N_STAB) == 0 &&
(symbolP->sy_desc & N_WEAK_DEF) == N_WEAK_DEF){
if((symbolP->sy_type & N_EXT) == 0){
as_bad("Non-global symbol: %s can't be a weak_definition",
symbolP->sy_name);
}
else if((symbolP->sy_type & N_TYPE) == N_UNDF){
as_bad("Undefined symbol: %s can't be a weak_definition",
symbolP->sy_name);
}
}
}
ilocalsym = 0;
iextdefsym = nlocalsym;
iundefsym = nlocalsym + nextdefsym;
extdefsyms = xmalloc(nextdefsym * sizeof(symbolS *));
undefsyms = xmalloc(nundefsym * sizeof(symbolS *));
i = 0;
j = 0;
for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
if((symbolP->sy_type & N_EXT) == 0){
if(symbolP->sy_name != NULL){
symbolP->sy_name_offset = *string_byte_count;
*string_byte_count += strlen(symbolP->sy_name) + 1;
if(symbolP->sy_nlist.n_type == N_BINCL)
seenBINCL = TRUE;
}
else{
symbolP->sy_name_offset = 0;
}
}
else{
if((symbolP->sy_type & N_TYPE) != N_UNDF)
extdefsyms[i++] = symbolP;
else
undefsyms[j++] = symbolP;
}
}
qsort(extdefsyms, nextdefsym, sizeof(symbolS *),
(int (*)(const void *, const void *))qsort_compare);
qsort(undefsyms, nundefsym, sizeof(symbolS *),
(int (*)(const void *, const void *))qsort_compare);
for(i = 0; i < nextdefsym; i++){
extdefsyms[i]->sy_number = *symbol_number;
*symbol_number = *symbol_number + 1;
}
for(j = 0; j < nundefsym; j++){
undefsyms[j]->sy_number = *symbol_number;
*symbol_number = *symbol_number + 1;
}
if(seenBINCL)
set_BINCL_checksums();
}
static
int
qsort_compare(
const symbolS **sym1,
const symbolS **sym2)
{
return(strcmp((*sym1)->sy_name, (*sym2)->sy_name));
}
static
uint32_t
nrelocs_for_fix(
struct fix *fixP)
{
if(fixP->fx_addsy == NULL)
return(0);
if(fixP->fx_subsy != NULL)
return(2);
#ifdef I860
if(fixP->fx_r_type == I860_RELOC_HIGH ||
fixP->fx_r_type == I860_RELOC_HIGHADJ)
return(2);
#endif
#ifdef M88K
if(fixP->fx_r_type == M88K_RELOC_HI16 ||
fixP->fx_r_type == M88K_RELOC_LO16)
return(2);
#endif
#ifdef PPC
if(fixP->fx_r_type == PPC_RELOC_HI16 ||
fixP->fx_r_type == PPC_RELOC_LO16 ||
fixP->fx_r_type == PPC_RELOC_HA16 ||
fixP->fx_r_type == PPC_RELOC_LO14 ||
fixP->fx_r_type == PPC_RELOC_JBSR)
return(2);
#endif
#ifdef HPPA
if(fixP->fx_r_type == HPPA_RELOC_HI21 ||
fixP->fx_r_type == HPPA_RELOC_LO14 ||
fixP->fx_r_type == HPPA_RELOC_BR17 ||
fixP->fx_r_type == HPPA_RELOC_JBSR)
return(2);
#endif
#ifdef SPARC
if(fixP->fx_r_type == SPARC_RELOC_HI22 ||
fixP->fx_r_type == SPARC_RELOC_LO10)
return(2);
#endif
#ifdef ARM
if(fixP->fx_r_type == ARM_RELOC_LO16 ||
fixP->fx_r_type == ARM_RELOC_HI16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_LO16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_HI16)
return(2);
#endif
return(1);
}
static
uint32_t
fix_to_relocation_entries(
struct fix *fixP,
uint64_t sect_addr,
struct relocation_info *riP,
uint32_t debug_section)
{
struct symbol *symbolP;
uint32_t count;
struct scattered_relocation_info sri;
uint32_t sectdiff;
#ifdef HPPA
uint32_t left21, right14;
#endif
if(fixP->fx_addsy == NULL)
return(0);
#ifdef TC_VALIDATE_FIX
TC_VALIDATE_FIX(fixP, sect_addr, 0);
#endif
memset(riP, '\0', sizeof(struct relocation_info));
symbolP = fixP->fx_addsy;
#ifdef ARM
if(fixP->fx_r_type == ARM_RELOC_LO16 ||
fixP->fx_r_type == ARM_RELOC_HI16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_LO16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_HI16){
riP->r_length = fixP->fx_r_type & 0x3;
}
else
#endif
switch(fixP->fx_size){
case 1:
riP->r_length = 0;
break;
case 2:
riP->r_length = 1;
break;
case 4:
#ifdef PPC
if(fixP->fx_r_type == PPC_RELOC_BR14_predicted)
riP->r_length = 3;
else
#endif
riP->r_length = 2;
break;
#if defined(ARCH64)
case 8:
riP->r_length = 3;
break;
#endif
default:
layout_file = fixP->file;
layout_line = fixP->line;
as_fatal("Bad fx_size (0x%x) in fix_to_relocation_info()\n",
fixP->fx_size);
}
riP->r_pcrel = fixP->fx_pcrel;
riP->r_address = fixP->fx_frag->fr_address + fixP->fx_where -
sect_addr;
#ifdef ARM
if(fixP->fx_r_type == ARM_RELOC_LO16 ||
fixP->fx_r_type == ARM_RELOC_HI16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_LO16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_HI16){
riP->r_type = ARM_RELOC_HALF;
}
else
#endif
riP->r_type = fixP->fx_r_type;
#if defined(I386) && defined(ARCH64)
if(fixP->fx_subsy == NULL &&
(!debug_section || (symbolP->sy_type & N_TYPE) == N_UNDF) &&
(!is_local_symbol(symbolP) ||
((symbolP->sy_type & N_TYPE) == N_SECT &&
is_section_cstring_literals(symbolP->sy_other)) ) ) {
#else
if((symbolP->sy_type & N_TYPE) == N_UNDF ||
((symbolP->sy_type & N_EXT) == N_EXT &&
(symbolP->sy_type & N_TYPE) == N_SECT &&
(is_section_coalesced(symbolP->sy_other) ||
(symbolP->sy_desc & N_WEAK_DEF) == N_WEAK_DEF) &&
fixP->fx_subsy == NULL)
#if defined(I386) && !defined(ARCH64)
||
((symbolP->sy_type & N_TYPE) == N_SECT &&
fixP->fx_r_type == GENERIC_RELOC_TLV)
#endif
){
#endif
riP->r_extern = 1;
riP->r_symbolnum = symbolP->sy_number;
}
else{
riP->r_extern = 0;
riP->r_symbolnum = symbolP->sy_other;
if(fixP->fx_subsy != NULL){
#if defined(I386) && defined(ARCH64)
if (is_local_symbol(fixP->fx_subsy))
{
riP->r_extern = 0;
riP->r_symbolnum = fixP->fx_subsy->sy_other;
}
else
{
riP->r_extern = 1;
riP->r_symbolnum = fixP->fx_subsy->sy_number;
}
riP->r_type = X86_64_RELOC_SUBTRACTOR;
riP++;
*riP = *(riP - 1);
if (is_local_symbol(fixP->fx_addsy))
{
riP->r_extern = 0;
riP->r_symbolnum = fixP->fx_addsy->sy_other;
}
else
{
riP->r_extern = 1;
riP->r_symbolnum = fixP->fx_addsy->sy_number;
}
riP->r_type = X86_64_RELOC_UNSIGNED;
return(2 * sizeof(struct relocation_info));
#endif
#ifdef PPC
if(fixP->fx_r_type == PPC_RELOC_HI16)
sectdiff = PPC_RELOC_HI16_SECTDIFF;
else if(fixP->fx_r_type == PPC_RELOC_LO16)
sectdiff = PPC_RELOC_LO16_SECTDIFF;
else if(fixP->fx_r_type == PPC_RELOC_HA16)
sectdiff = PPC_RELOC_HA16_SECTDIFF;
else if(fixP->fx_r_type == PPC_RELOC_LO14)
sectdiff = PPC_RELOC_LO14_SECTDIFF;
else
#endif
#ifdef HPPA
if(fixP->fx_r_type == HPPA_RELOC_HI21)
sectdiff = HPPA_RELOC_HI21_SECTDIFF;
else if(fixP->fx_r_type == HPPA_RELOC_LO14)
sectdiff = HPPA_RELOC_LO14_SECTDIFF;
else
#endif
#ifdef SPARC
if(fixP->fx_r_type == SPARC_RELOC_HI22)
sectdiff = SPARC_RELOC_HI22_SECTDIFF;
else if(fixP->fx_r_type == SPARC_RELOC_LO10)
sectdiff = SPARC_RELOC_LO10_SECTDIFF;
else
#endif
#ifdef ARM
if(fixP->fx_r_type == ARM_RELOC_LO16 ||
fixP->fx_r_type == ARM_RELOC_HI16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_LO16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_HI16)
sectdiff = ARM_RELOC_HALF_SECTDIFF;
else
#endif
{
if(fixP->fx_r_type != 0 && fixP->fx_r_type != NO_RELOC){
layout_file = fixP->file;
layout_line = fixP->line;
as_fatal("Internal error: incorrect fx_r_type (%u) for "
"fx_subsy != 0 in fix_to_relocation_info()",
fixP->fx_r_type);
}
if((!(fixP->fx_addsy->sy_type & N_EXT)) && flagseen['k'])
sectdiff = RELOC_LOCAL_SECTDIFF;
else
sectdiff = RELOC_SECTDIFF;
}
memset(&sri, '\0',sizeof(struct scattered_relocation_info));
sri.r_scattered = 1;
#ifdef ARM
if(fixP->fx_r_type == ARM_RELOC_LO16 ||
fixP->fx_r_type == ARM_RELOC_HI16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_LO16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_HI16)
sri.r_length = fixP->fx_r_type & 0x3;
else
#endif
sri.r_length = riP->r_length;
sri.r_pcrel = riP->r_pcrel;
sri.r_address = riP->r_address;
if(sri.r_address != riP->r_address)
as_fatal("Section too large, can't encode r_address (0x%x) "
"into 24-bits of scattered relocation entry",
riP->r_address);
sri.r_type = sectdiff;
sri.r_value = symbolP->sy_value;
*riP = *((struct relocation_info *)&sri);
riP++;
sri.r_type = RELOC_PAIR;
sri.r_value = fixP->fx_subsy->sy_value;
if(sectdiff == RELOC_SECTDIFF ||
sectdiff == RELOC_LOCAL_SECTDIFF)
sri.r_address = 0;
#ifdef PPC
else if(sectdiff == PPC_RELOC_HI16_SECTDIFF ||
sectdiff == PPC_RELOC_HA16_SECTDIFF){
sri.r_address = (symbolP->sy_value -
fixP->fx_subsy->sy_value
+ fixP->fx_offset) & 0xffff;
}
else if(sectdiff == PPC_RELOC_LO16_SECTDIFF ||
sectdiff == PPC_RELOC_LO14_SECTDIFF){
sri.r_address = ((symbolP->sy_value -
fixP->fx_subsy->sy_value +
fixP->fx_offset) >> 16) & 0xffff;
}
#endif
#ifdef HPPA
else if(sectdiff == HPPA_RELOC_HI21_SECTDIFF){
calc_hppa_HILO(symbolP->sy_value - fixP->fx_subsy->sy_value,
fixP->fx_offset, &left21, &right14);
sri.r_address = right14 & 0x3fff;
}
else if(sectdiff == HPPA_RELOC_LO14_SECTDIFF){
calc_hppa_HILO(symbolP->sy_value - fixP->fx_subsy->sy_value,
fixP->fx_offset, &left21, &right14);
sri.r_address = left21 >> 11;
}
#endif
#ifdef SPARC
else if(sectdiff == SPARC_RELOC_HI22_SECTDIFF){
sri.r_address = (symbolP->sy_value -
fixP->fx_subsy->sy_value
+ fixP->fx_offset) & 0x3ff;
}
else if(sectdiff == SPARC_RELOC_LO10_SECTDIFF){
sri.r_address = ((symbolP->sy_value -
fixP->fx_subsy->sy_value +
fixP->fx_offset) >> 10) & 0x3fffff;
}
#endif
#ifdef ARM
else if(sectdiff == ARM_RELOC_HALF_SECTDIFF){
if((sri.r_length & 0x1) == 0x1)
sri.r_address = (symbolP->sy_value -
fixP->fx_subsy->sy_value
+ fixP->fx_offset) & 0xffff;
else
sri.r_address = ((symbolP->sy_value -
fixP->fx_subsy->sy_value +
fixP->fx_offset) >> 16) & 0xffff;
}
#endif
*riP = *((struct relocation_info *)&sri);
return(2 * sizeof(struct relocation_info));
}
#if !defined(I860) && !(defined(I386) && defined(ARCH64))
if(fixP->fx_offset != 0 &&
(riP->r_address & 0xff000000) == 0 &&
((symbolP->sy_type & N_TYPE) & ~N_EXT) != N_ABS
#ifdef M68K
&& !(fixP->fx_pcrel &&
((fixP->fx_size == 2 && fixP->fx_offset == 2) ||
(fixP->fx_size == 4 && fixP->fx_offset == 4)) )
#endif
){
memset(&sri, '\0',sizeof(struct scattered_relocation_info));
sri.r_scattered = 1;
sri.r_length = riP->r_length;
sri.r_pcrel = riP->r_pcrel;
sri.r_address = riP->r_address;
if(sri.r_address != riP->r_address)
as_fatal("Section too large, can't encode r_address (0x%x) "
"into 24-bits of scattered relocation entry",
riP->r_address);
sri.r_type = riP->r_type;
sri.r_value = symbolP->sy_value;
*riP = *((struct relocation_info *)&sri);
}
#endif
}
count = 1;
riP++;
#if !defined(M68K) && !defined(I386)
#ifdef I860
if(fixP->fx_r_type == I860_RELOC_HIGH ||
fixP->fx_r_type == I860_RELOC_HIGHADJ)
#endif
#ifdef M88K
if(fixP->fx_r_type == M88K_RELOC_HI16 ||
fixP->fx_r_type == M88K_RELOC_LO16)
#endif
#ifdef PPC
if(fixP->fx_r_type == PPC_RELOC_HI16 ||
fixP->fx_r_type == PPC_RELOC_LO16 ||
fixP->fx_r_type == PPC_RELOC_HA16 ||
fixP->fx_r_type == PPC_RELOC_LO14 ||
fixP->fx_r_type == PPC_RELOC_JBSR)
#endif
#ifdef HPPA
if(fixP->fx_r_type == HPPA_RELOC_HI21 ||
fixP->fx_r_type == HPPA_RELOC_LO14 ||
fixP->fx_r_type == HPPA_RELOC_BR17 ||
fixP->fx_r_type == HPPA_RELOC_JBSR)
#endif
#ifdef SPARC
if(fixP->fx_r_type == SPARC_RELOC_HI22 ||
fixP->fx_r_type == SPARC_RELOC_LO10)
#endif
#ifdef ARM
if(fixP->fx_r_type == ARM_RELOC_LO16 ||
fixP->fx_r_type == ARM_RELOC_HI16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_LO16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_HI16)
#endif
{
memset(riP, '\0', sizeof(struct relocation_info));
#ifdef ARM
if(fixP->fx_r_type == ARM_RELOC_LO16 ||
fixP->fx_r_type == ARM_RELOC_HI16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_LO16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_HI16){
riP->r_length = fixP->fx_r_type & 0x3;
}
else
#endif
switch(fixP->fx_size){
case 1:
riP->r_length = 0;
break;
case 2:
riP->r_length = 1;
break;
case 4:
riP->r_length = 2;
break;
#if defined(ARCH64)
case 8:
riP->r_length = 3;
break;
#endif
default:
as_fatal("Bad fx_size (0x%x) in fix_to_relocation_info()\n",
fixP->fx_size);
}
riP->r_pcrel = fixP->fx_pcrel;
riP->r_extern = 0;
riP->r_symbolnum = 0x00ffffff;
#ifdef I860
riP->r_type = I860_RELOC_PAIR;
riP->r_address = 0xffff & fixP->fx_value;
#endif
#ifdef M88K
riP->r_type = M88K_RELOC_PAIR;
if(fixP->fx_r_type == M88K_RELOC_HI16)
riP->r_address = 0xffff & fixP->fx_value;
else if(fixP->fx_r_type == M88K_RELOC_LO16)
riP->r_address = 0xffff & (fixP->fx_value >> 16);
#endif
#ifdef PPC
riP->r_type = PPC_RELOC_PAIR;
if(fixP->fx_r_type == PPC_RELOC_HI16 ||
fixP->fx_r_type == PPC_RELOC_HA16)
riP->r_address = 0xffff & fixP->fx_value;
else if(fixP->fx_r_type == PPC_RELOC_LO16 ||
fixP->fx_r_type == PPC_RELOC_LO14)
riP->r_address = 0xffff & (fixP->fx_value >> 16);
else if (fixP->fx_r_type == PPC_RELOC_JBSR){
if((fixP->fx_value & R_SCATTERED) == 0){
riP->r_address = fixP->fx_value;
}
else{
memset(&sri, '\0',sizeof(struct scattered_relocation_info));
sri.r_scattered = 1;
sri.r_pcrel = riP->r_pcrel;
sri.r_length = riP->r_length;
sri.r_type = riP->r_type;
sri.r_address = 0;
sri.r_value = fixP->fx_value;
*riP = *((struct relocation_info *)&sri);
}
}
#endif
#ifdef HPPA
riP->r_type = HPPA_RELOC_PAIR;
calc_hppa_HILO(fixP->fx_value - fixP->fx_offset,
fixP->fx_offset, &left21, &right14);
if (fixP->fx_r_type == HPPA_RELOC_LO14 ||
fixP->fx_r_type == HPPA_RELOC_BR17)
riP->r_address = left21 >> 11;
else if (fixP->fx_r_type == HPPA_RELOC_HI21)
riP->r_address = right14 & 0x3fff;
else if (fixP->fx_r_type == HPPA_RELOC_JBSR){
if((symbolP->sy_type & N_TYPE) == N_UNDF)
riP->r_address = fixP->fx_value & 0xffffff;
else
riP->r_address = (fixP->fx_value - sect_addr) & 0xffffff;
}
#endif
#ifdef SPARC
riP->r_type = SPARC_RELOC_PAIR;
if (fixP->fx_r_type == SPARC_RELOC_HI22)
riP->r_address = fixP->fx_value & 0x3ff;
else if (fixP->fx_r_type == SPARC_RELOC_LO10)
riP->r_address = (fixP->fx_value >> 10) & 0x3fffff;
#endif
#ifdef ARM
riP->r_type = ARM_RELOC_PAIR;
if(fixP->fx_r_type == ARM_RELOC_HI16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_HI16)
riP->r_address = 0xffff & fixP->fx_value;
else if(fixP->fx_r_type == ARM_RELOC_LO16 ||
fixP->fx_r_type == ARM_THUMB_RELOC_LO16)
riP->r_address = 0xffff & (fixP->fx_value >> 16);
#endif
count = 2;
}
#endif
return(count * sizeof(struct relocation_info));
}
#ifdef I860
static
void
set_default_section_align(
char *segname,
char *sectname,
uint32_t align)
{
frchainS *frcP;
for(frcP = frchain_root; frcP != NULL; frcP = frcP->frch_next){
if(strncmp(frcP->frch_section.segname, segname,
sizeof(frcP->frch_section.segname)) == 0 &&
strncmp(frcP->frch_section.sectname, sectname,
sizeof(frcP->frch_section.sectname)) == 0){
if(align > frcP->frch_section.align)
frcP->frch_section.align = align;
return;
}
}
}
static
void
clear_section_flags(void)
{
frchainS *frcP;
for(frcP = frchain_root; frcP != NULL; frcP = frcP->frch_next)
if(frcP->frch_section.flags != S_ZEROFILL &&
frcP->frch_section.flags != S_THREAD_LOCAL_ZEROFILL)
frcP->frch_section.flags = 0;
}
static
void
I860_tweeks(void)
{
set_default_section_align("__TEXT", "__text", 5);
set_default_section_align("__DATA", "__data", 4);
set_default_section_align("__DATA", "__bss", 4);
clear_section_flags();
}
#endif
void
number_to_chars_bigendian (char *buf, signed_expr_t val, int n)
{
if (n <= 0)
abort ();
while (n--)
{
buf[n] = val & 0xff;
val >>= 8;
}
}
void
number_to_chars_littleendian (char *buf, signed_expr_t val, int n)
{
if (n <= 0)
abort ();
while (n--)
{
*buf++ = val & 0xff;
val >>= 8;
}
}