diff options
author | John van Groningen | 2003-10-03 14:11:56 +0000 |
---|---|---|
committer | John van Groningen | 2003-10-03 14:11:56 +0000 |
commit | 9aa3e9b5761fba46529541a1ad2b02c3e857d3b5 (patch) | |
tree | bb4f9e06d7e19ddaf83873249d440f72eb74d471 /cgsas.c | |
parent | implement optimizing linking for ELF (linux) (diff) |
add optimized linking
Diffstat (limited to 'cgsas.c')
-rw-r--r-- | cgsas.c | 3103 |
1 files changed, 3103 insertions, 0 deletions
@@ -0,0 +1,3103 @@ +/* + File: cgsas.c + Author: John van Groningen + Machine: Sun 4 + At: University of Nijmegen +*/ + +#include <stdio.h> +#include <string.h> + +#define ELF_TARGET_SPARC +#include <elf.h> + +#define ELF + +#include "cgport.h" +#include "cgrconst.h" +#include "cgtypes.h" +#include "cg.h" +#include "cgiconst.h" +#include "cgcode.h" +#include "cgswas.h" + +#define for_l(v,l,n) for(v=(l);v!=NULL;v=v->n) + +#define U4(s,v1,v2,v3,v4) s->v1;s->v2;s->v3;s->v4 +#define U5(s,v1,v2,v3,v4,v5) s->v1;s->v2;s->v3;s->v4;s->v5 + +#define IO_BUFFER_SIZE 16384 +#define BUFFER_SIZE 4096 + +struct object_buffer { + struct object_buffer * next; + int size; + unsigned char data [BUFFER_SIZE]; +}; + +#define BRANCH_RELOCATION 0 +#define CALL_RELOCATION 1 +#define LONG_WORD_RELOCATION 2 +#define HI22_RELOCATION 3 +#define LO12_RELOCATION 4 +#ifdef FUNCTION_LEVEL_LINKING +# define DUMMY_BRANCH_RELOCATION 5 +#endif + +#ifdef FUNCTION_LEVEL_LINKING +# define TEXT_LABEL_ID (-2) +# define DATA_LABEL_ID (-3) +#else +# define TEXT_LABEL_ID 1 +# define DATA_LABEL_ID 2 +#endif + +#define CODE_CONTROL_SECTION 0 +#define DATA_CONTROL_SECTION 1 +#define IMPORTED_LABEL 2 +#define EXPORTED_CODE_LABEL 3 +#define EXPORTED_DATA_LABEL 4 + +struct object_label { + struct object_label * next; + union { + unsigned long offset; /* CODE_CONTROL_SECTION,DATA_CONTROL_SECTION */ + struct label * label; /* IMPORTED_LABEL,EXPORTED_CODE_LABEL */ + } object_label_u1; + union { + unsigned long length; /* CODE_CONTROL_SECTION,DATA_CONTROL_SECTION */ + unsigned long string_offset; /* IMPORTED_LABEL,EXPORTED_CODE_LABEL */ + } object_label_u2; + int object_label_number; +#ifdef FUNCTION_LEVEL_LINKING + int object_label_n_relocations; /* CODE_CONTROL_SECTION,DATA_CONTROL_SECTION */ + short object_label_section_n; /* CODE_CONTROL_SECTION,DATA_CONTROL_SECTION */ +#endif + unsigned char object_label_kind; + unsigned char object_section_align8; +}; + +#define object_label_offset object_label_u1.offset +#define object_label_label object_label_u1.label + +#define object_label_length object_label_u2.length +#define object_label_string_offset object_label_u2.string_offset + +struct relocation { + struct relocation * next; + unsigned long relocation_offset; + struct label * relocation_label; + long relocation_addend; +#ifdef FUNCTION_LEVEL_LINKING + struct object_label * relocation_object_label; /* for BRANCH_RELOCATION, CALL_RELOCATION and DUMMY_BRANCH_RELOCATION */ +#endif + short relocation_kind; +}; + +static FILE *output_file; + +static int n_code_relocations,n_data_relocations; +static struct object_label *code_object_label,*data_object_label; + +static struct relocation *first_code_relocation,**last_code_relocation_l; +static struct relocation *first_data_relocation,**last_data_relocation_l; + +static struct object_buffer *first_code_buffer,*current_code_buffer; +static int code_buffer_free,code_buffer_offset; +static unsigned int *code_buffer_p; + +static struct object_buffer *first_data_buffer,*current_data_buffer; +static int data_buffer_free,data_buffer_offset; +static unsigned int *data_buffer_p; + +static void initialize_buffers (void) +{ + struct object_buffer *new_code_buffer,*new_data_buffer; + + new_code_buffer=memory_allocate_type (struct object_buffer); + + new_code_buffer->size=0; + new_code_buffer->next=NULL; + + first_code_buffer=new_code_buffer; + current_code_buffer=new_code_buffer; + code_buffer_offset=0; + + code_buffer_free=BUFFER_SIZE; + code_buffer_p=(unsigned int*)new_code_buffer->data; + + new_data_buffer=memory_allocate_type (struct object_buffer); + + new_data_buffer->size=0; + new_data_buffer->next=NULL; + + first_data_buffer=new_data_buffer; + current_data_buffer=new_data_buffer; + data_buffer_offset=0; + + data_buffer_free=BUFFER_SIZE; + data_buffer_p=(unsigned int*)new_data_buffer->data; +} + +static void store_instruction2 (int c) +{ + struct object_buffer *new_buffer; + + current_code_buffer->size=BUFFER_SIZE; + + new_buffer=memory_allocate_type (struct object_buffer); + + new_buffer->size=0; + new_buffer->next=NULL; + + current_code_buffer->next=new_buffer; + current_code_buffer=new_buffer; + code_buffer_offset+=BUFFER_SIZE; + + code_buffer_free=BUFFER_SIZE-4; + code_buffer_p=(unsigned int*)new_buffer->data; + + *code_buffer_p++=c; +} + +static void store_instruction (int c) +{ + if (code_buffer_free>=4){ + code_buffer_free-=4; + *code_buffer_p++=c; + } else + store_instruction2 (c); +} + +static void store_long_word_in_data_section2 (ULONG c) +{ + struct object_buffer *new_buffer; + + current_data_buffer->size=BUFFER_SIZE; + + new_buffer=memory_allocate_type (struct object_buffer); + + new_buffer->size=0; + new_buffer->next=NULL; + + current_data_buffer->next=new_buffer; + current_data_buffer=new_buffer; + data_buffer_offset+=BUFFER_SIZE; + + data_buffer_free=BUFFER_SIZE-4; + data_buffer_p=(unsigned int*)new_buffer->data; + + *data_buffer_p++=c; +} + +void store_long_word_in_data_section (ULONG c) +{ + if (data_buffer_free>=4){ + data_buffer_free-=4; + *data_buffer_p++=c; + } else + store_long_word_in_data_section2 (c); +} + +void store_2_words_in_data_section (UWORD w1,UWORD w2) +{ + store_long_word_in_data_section ((w1<<16) | ((UWORD)w2)); +} + +static void flush_code_buffer (void) +{ + current_code_buffer->size=BUFFER_SIZE-code_buffer_free; + code_buffer_offset+=BUFFER_SIZE-code_buffer_free; +} + +static void flush_data_buffer (void) +{ + current_data_buffer->size=BUFFER_SIZE-data_buffer_free; + data_buffer_offset+=BUFFER_SIZE-data_buffer_free; +} + +static void write_buffers_and_release_memory (struct object_buffer **first_buffer_l) +{ + struct object_buffer *buffer,*next_buffer; + + for (buffer=*first_buffer_l; buffer!=NULL; buffer=next_buffer){ + int size; + + size=buffer->size; + + if (fwrite (buffer->data,1,size,output_file)!=size) + error ("Write error"); + + next_buffer=buffer->next; + + memory_free (buffer); + } + + *first_buffer_l=NULL; +} + +void store_abc_string_in_data_section (char *string,int length) +{ + unsigned char *string_p; + + string_p=(unsigned char*)string; + store_long_word_in_data_section (length); + + while (length>=4){ + store_long_word_in_data_section (*(ULONG*)string_p); + string_p+=4; + length-=4; + } + + if (length>0){ + ULONG d; + int shift; + + d=0; + shift=24; + while (length>0){ + d |= string_p[0]<<shift; + shift-=8; + --length; + ++string_p; + } + store_long_word_in_data_section (d); + } +} + +void store_c_string_in_data_section (char *string,int length) +{ + unsigned char *string_p; + ULONG d; + int shift; + + string_p=(unsigned char*)string; + + while (length>=4){ + store_long_word_in_data_section (*(ULONG*)string_p); + string_p+=4; + length-=4; + } + + d=0; + shift=24; + while (length>0){ + d |= string_p[0]<<shift; + shift-=8; + --length; + ++string_p; + } + store_long_word_in_data_section (d); +} + +#define CURRENT_CODE_OFFSET (code_buffer_offset+((unsigned char*)code_buffer_p-current_code_buffer->data)) +#define CURRENT_DATA_OFFSET (data_buffer_offset+((unsigned char*)data_buffer_p-current_data_buffer->data)) + +static struct object_label *first_object_label,**last_object_label_l; +#ifdef FUNCTION_LEVEL_LINKING +static int n_code_sections,n_data_sections; +#endif + +#ifdef FUNCTION_LEVEL_LINKING +void as_new_data_module (void) +{ + struct object_label *new_object_label; + unsigned long current_data_offset; + int data_section_label_number; + + new_object_label=fast_memory_allocate_type (struct object_label); + data_object_label=new_object_label; + + data_section_label_number=0; + current_data_offset=CURRENT_DATA_OFFSET; + + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_offset=current_data_offset; + new_object_label->object_label_number=data_section_label_number; + new_object_label->object_label_section_n=n_data_sections; + ++n_data_sections; + new_object_label->object_label_length=0; + new_object_label->object_label_kind=DATA_CONTROL_SECTION; + new_object_label->object_section_align8=0; +} + +static void as_new_code_module (void) +{ + struct object_label *new_object_label; + unsigned long current_code_offset; + int code_section_label_number; + + new_object_label=fast_memory_allocate_type (struct object_label); + code_object_label=new_object_label; + + code_section_label_number=0; + current_code_offset=CURRENT_CODE_OFFSET; + + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_offset=current_code_offset; + new_object_label->object_label_number=code_section_label_number; + new_object_label->object_label_section_n=n_code_sections; + ++n_code_sections; + new_object_label->object_label_length=0; + new_object_label->object_label_kind=CODE_CONTROL_SECTION; +} +#endif + +static void store_label_plus_offset_in_data_section (LABEL *label,int offset) +{ + struct relocation *new_relocation; + + store_long_word_in_data_section (0); + + new_relocation=fast_memory_allocate_type (struct relocation); + ++n_data_relocations; + + *last_data_relocation_l=new_relocation; + last_data_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + new_relocation->relocation_label=label; + new_relocation->relocation_offset=CURRENT_DATA_OFFSET-4; + new_relocation->relocation_kind=LONG_WORD_RELOCATION; + new_relocation->relocation_addend=offset; +} + +static int n_object_labels; + +static unsigned long string_table_offset; + +void define_data_label (LABEL *label) +{ + label->label_id=DATA_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + label->label_object_label=data_object_label; +#endif + label->label_offset=CURRENT_DATA_OFFSET; + + if (label->label_flags & EXPORT_LABEL){ + struct object_label *new_object_label; + int string_length; + + new_object_label=fast_memory_allocate_type (struct object_label); + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_label=label; +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + new_object_label->object_label_number = n_object_labels; +#endif + + ++n_object_labels; + + string_length=strlen (label->label_name); + new_object_label->object_label_string_offset=string_table_offset; + string_table_offset+=string_length+1; + +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + label->label_object_label=new_object_label; + new_object_label->object_label_section_n = data_object_label->object_label_section_n; +#endif + + new_object_label->object_label_kind=EXPORTED_DATA_LABEL; + } +} + +static void as_labels (struct block_label *labels) +{ + for (; labels!=NULL; labels=labels->block_label_next) +#if 0 + if (labels->block_label_label->label_number==0) +#endif + { + LABEL *label; + + label=labels->block_label_label; + + label->label_id=TEXT_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + label->label_object_label=code_object_label; +#endif + label->label_offset=CURRENT_CODE_OFFSET; + + if (label->label_flags & EXPORT_LABEL){ + struct object_label *new_object_label; + int string_length; + + new_object_label=fast_memory_allocate_type (struct object_label); + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_label=label; + new_object_label->object_label_number=n_object_labels; + ++n_object_labels; + + string_length=strlen (label->label_name); + new_object_label->object_label_string_offset=string_table_offset; + string_table_offset+=string_length+1; + new_object_label->object_label_kind=EXPORTED_CODE_LABEL; + } + } +} + +void store_label_in_data_section (LABEL *label) +{ + store_label_plus_offset_in_data_section (label,0); +} + +void store_descriptor_in_data_section (LABEL *label) +{ + store_label_plus_offset_in_data_section (label,2); +} + +void store_descriptor_string_in_data_section (char *string,int length,LABEL *string_label) +{ + define_data_label (string_label); + store_abc_string_in_data_section (string,length); +} + +static void as_branch_label (struct label *label,int relocation_kind) +{ + struct relocation *new_relocation; + + new_relocation=fast_memory_allocate_type (struct relocation); + ++n_code_relocations; + + *last_code_relocation_l=new_relocation; + last_code_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + new_relocation->relocation_label=label; + new_relocation->relocation_offset=CURRENT_CODE_OFFSET-4; +#ifdef FUNCTION_LEVEL_LINKING + new_relocation->relocation_object_label=code_object_label; +#endif + new_relocation->relocation_kind=relocation_kind; + new_relocation->relocation_addend=0; +} + +static void as_hi_or_lo_label (struct label *label,int offset,int relocation_kind) +{ + struct relocation *new_relocation; + + new_relocation=fast_memory_allocate_type (struct relocation); + ++n_code_relocations; + + *last_code_relocation_l=new_relocation; + last_code_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + new_relocation->relocation_label=label; + new_relocation->relocation_offset=CURRENT_CODE_OFFSET-4; + new_relocation->relocation_kind=relocation_kind; + new_relocation->relocation_addend=offset; +} + +static void store_label_in_code_section (struct label *label) +{ + struct toc_label *t_label; + struct relocation *new_relocation; + + store_instruction (0); + + new_relocation=fast_memory_allocate_type (struct relocation); + ++n_code_relocations; + + *last_code_relocation_l=new_relocation; + last_code_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + new_relocation->relocation_offset=CURRENT_CODE_OFFSET-4; + + new_relocation->relocation_label=label; + new_relocation->relocation_kind=LONG_WORD_RELOCATION; + new_relocation->relocation_addend=0; +} + +#define REGISTER_G0 (-16) +#define REGISTER_I6 (-10) +#define REGISTER_O0 8 +#define REGISTER_O1 9 +#define REGISTER_O7 15 + +/* +static char register_type [32]="ggggggiiggiiiiiilllllllloooooooo"; +static char register_number[32]="01234767565432100123456701234567"; +*/ + +static unsigned char real_reg_num [32] = +{ + 0,1,2,3,4,7,30,31, + 5,6,29,28,27,26,25,24, + 16,17,18,19,20,21,22,23, + 8,9,10,11,12,13,14,15 +}; + +#define reg_num(r) (real_reg_num[(r)+16]) + +#define as_i_id0(i,rd) store_instruction(0x1000000|(reg_num(rd)<<25)|((i)&0x3fffff)) +#define as_i_bic(i,cond) store_instruction((cond<<25)|(2<<22)|((i)&0x3fffffff)) +#define as_i_bica(i,cond) store_instruction((1<<29)|(cond<<25)|(2<<22)|(i)&0x3fffffff) +#define as_i_call(i) store_instruction((1<<30)|i) +#define as_i_fbic(i,cond) store_instruction((cond<<25)|(6<<22)|i) +#define as_i_fbica(i,cond) store_instruction((1<<29)|(cond<<25)|(6<<22)|i) +#define as_i_abd2(ra,rb,rd,op) store_instruction(0x80000000|((op)<<19)|(reg_num(rd)<<25)|(reg_num(ra)<<14)|reg_num(rb)) +#define as_i_fb2(fa,fb,op,opf) store_instruction(0x80000000|((op)<<19)|((fa)<<14)|((opf)<<5)|(fb)) +#define as_i_ff2(ra,rd,op,opf) store_instruction(0x80000000|((op)<<19)|((rd)<<25)|((opf)<<5)|(ra)) +#define as_i_fff2(ra,rb,rd,op,opf) store_instruction(0x80000000|((op)<<19)|((rd)<<25)|((ra)<<14)|((opf)<<5)|(rb)) +#define as_i_aid2(ra,i,rd,op) store_instruction(0x80000000|((op)<<19)|(reg_num(rd)<<25)|(reg_num(ra)<<14)|0x2000|((i)&0x1fff)) +#define as_i_abd3(ra,rb,rd,op) store_instruction(0xc0000000|((op)<<19)|(reg_num(rd)<<25)|(reg_num(ra)<<14)|reg_num(rb)) +#define as_i_aod3(ra,o,rd,op) store_instruction(0xc0000000|((op)<<19)|(reg_num(rd)<<25)|(reg_num(ra)<<14)|0x2000|((o)&0x1fff)) +#define as_i_foa3(fa,o,ra,op) store_instruction(0xc0000000|((op)<<19)|((fa)<<25)|((reg_num(ra))<<14)|0x2000|((o)&0x1fff)) +#define as_i_fab3(fa,ra,rb,op) store_instruction(0xc0000000|((op)<<19)|((fa)<<25)|((reg_num(ra))<<14)|(rb)) + +#define LD_OP 0 +#define LDUB_OP 1 +#define LDUH_OP 2 +#define LDSB_OP 9 +#define LDSH_OP 10 +#define ST_OP 4 +#define STB_OP 5 +#define STH_OP 6 + +#define LDF_OP 0x20 +#define LDDF_OP 0x23 +#define STF_OP 0x24 + +#define AND_OP 1 +#define OR_OP 2 +#define XOR_OP 3 +#define SLL_OP 0x25 +#define SRL_OP 0x26 +#define SRA_OP 0x27 + +#define FADDD_OP 0x42 +#define FDIVD_OP 0x4e +#define FMULD_OP 0x4a +#define FSUBD_OP 0x46 + +#define A_COND 0x8 +#define E_COND 0x1 +#define GE_COND 0xb +#define G_COND 0xa +#define L_COND 0x3 +#define LE_COND 0x2 +#define NE_COND 0x9 +#define CS_COND 0x5 +#define VC_COND 0xf +#define VS_COND 0x7 + +#define FE_COND 0x9 +#define FGE_COND 0xb +#define FG_COND 0x6 +#define FLE_COND 0xd +#define FL_COND 0x4 +#define FNE_COND 0x1 + +#define as_add(ra,rb,rd) as_i_abd2(ra,rb,rd,0) +#define as_addcc(ra,rb,rd) as_i_abd2(ra,rb,rd,0x10) +#define as_addcci(ra,i,rd) as_i_aid2(ra,i,rd,0x10) +#define as_addi(ra,i,rd) as_i_aid2(ra,i,rd,0) +#define as_andcci(ra,i,rd) as_i_aid2(ra,i,rd,0x11) +#define as_faddd(fa,fb,fd) as_i_fff2(fa,fb,fd,0x34,FADDD_OP) +#define as_fcmpd(fa,fb) as_i_fb2(fa,fb,0x35,0x52) +#define as_fdtoi(fa,fd) as_i_ff2(fa,fd,0x34,0xd2) +#define as_fitod(fa,fd) as_i_ff2(fa,fd,0x34,0xc8) +#define as_fdivd(fa,fb,fd) as_i_fff2(fa,fb,fd,0x34,FDIVD_OP) +#define as_fmuld(fa,fb,fd) as_i_fff2(fa,fb,fd,0x34,FMULD_OP) +#define as_fsqrtd(fa,fd) as_i_ff2(fa,fd,0x34,0x2a) +#define as_fsubd(fa,fb,fd) as_i_fff2(fa,fb,fd,0x34,FSUBD_OP) +#define as_jmpli(i,ra,rd) as_i_aid2(ra,i,rd,0x38) +#define as_ld(o,ra,rd) as_i_aod3(ra,o,rd,LD_OP) +#define as_lddf(o,ra,fd) as_i_foa3(fd,o,ra,LDDF_OP) +#define as_ldf(o,ra,fd) as_i_foa3(fd,o,ra,LDF_OP) +#define as_ldf_x(ra,rb,fd) as_i_fab3(fd,ra,rb,LDF_OP) +#define as_ldsh(o,ra,rd) as_i_aod3(ra,o,rd,LDSH_OP) +#define as_ldsh_x(ra,rb,rd) as_i_abd3(ra,rb,rd,LDSH_OP) +#define as_ld_x(ra,rb,rd) as_i_abd3(ra,rb,rd,LD_OP) +#define as_fmovs(fa,fd) as_i_ff2(fa,fd,0x34,1); +#define as_fnegs(fa,fd) as_i_ff2(fa,fd,0x34,5); +#define as_or(ra,rb,rd) as_i_abd2(ra,rb,rd,OR_OP) +#define as_orcc(ra,rb,rd) as_i_abd2(ra,rb,rd,0x12) +#define as_ori(ra,i,rd) as_i_aid2(ra,i,rd,OR_OP) +#define as_sethi(i,rd) as_i_id0(i,rd) +#define as_slli(ra,i,rd) as_i_aid2(ra,i,rd,SLL_OP) +#define as_stf(fa,o,rd) as_i_foa3(fa,o,rd,STF_OP) +#define as_sub(ra,rb,rd) as_i_abd2(ra,rb,rd,4) +#define as_subcc(ra,rb,rd) as_i_abd2(ra,rb,rd,0x14) +#define as_subcci(ra,i,rd) as_i_aid2(ra,i,rd,0x14) + +#define as_btst(i,ra) as_i_aid2(ra,i,REGISTER_G0,0x11) +#define as_clr(rd) as_or(REGISTER_G0,REGISTER_G0,rd) +#define as_cmp(ra,rb) as_subcc(ra,rb,REGISTER_G0) +#define as_cmpi(ra,i) as_subcci(ra,i,REGISTER_G0) +#define as_dec(i,rd) as_i_aid2(rd,i,rd,4) +#define as_deccc(i,rd) as_i_aid2(rd,i,rd,0x14) +#define as_inc(i,rd) as_i_aid2(rd,i,rd,0) +#define as_inccc(i,rd) as_i_aid2(rd,i,rd,0x10) +#define as_mov(ra,rd) as_or(REGISTER_G0,ra,rd) +#define as_movi(i,rd) as_ori(REGISTER_G0,i,rd) +#define as_nop() as_sethi(0,REGISTER_G0) +#define as_retl() as_jmpli(8,REGISTER_O7,REGISTER_G0) +#define as_tst(ra) as_orcc(REGISTER_G0,ra,REGISTER_G0) +#define as_load(op,o,ra,rd) as_i_aod3(ra,o,rd,op) +#define as_load_x(op,ra,rb,rd) as_i_abd3(ra,rb,rd,op) +#define as_store(op,rd,o,ra) as_i_aod3(ra,o,rd,op) +#define as_store_x(op,rd,ra,rb) as_i_abd3(ra,rb,rd,op) + +#define as_st(rd,o,ra) as_store(ST_OP,rd,o,ra) + +static void as_set (int i,int rd) +{ + if (i>=-4096 && i<=4095) + as_movi (i,rd); + else { + as_sethi (i>>10,rd); + if ((i & 1023)!=0) + as_ori (rd,i & 1023,rd); + } +} + +enum { SIZE_LONG, SIZE_WORD, SIZE_BYTE }; + +static void as_ld_parameter (struct parameter *parameter,int rd) +{ + if (parameter->parameter_type==P_INDIRECT) + as_ld (parameter->parameter_offset,parameter->parameter_data.reg.r,rd); + else if (parameter->parameter_type==P_INDEXED && parameter->parameter_offset==0) + as_ld_x (parameter->parameter_data.ir->a_reg.r,parameter->parameter_data.ir->d_reg.r,rd); + else + internal_error_in_function ("as_ld_parameter"); +} + +static void as_ldsh_parameter (struct parameter *parameter,int rd) +{ + if (parameter->parameter_type==P_INDIRECT) + as_ldsh (parameter->parameter_offset,parameter->parameter_data.reg.r,rd); + else if (parameter->parameter_type==P_INDEXED && parameter->parameter_offset==0) + as_ldsh_x (parameter->parameter_data.ir->a_reg.r,parameter->parameter_data.ir->d_reg.r,rd); + else + internal_error_in_function ("as_ldsh_parameter"); +} + +static struct parameter as_register_parameter (struct parameter parameter,int size_flag) +{ + switch (parameter.parameter_type){ + case P_DESCRIPTOR_NUMBER: + as_sethi (0,REGISTER_O0); + as_hi_or_lo_label (parameter.parameter_data.l,2+(parameter.parameter_offset<<3),HI22_RELOCATION); + + as_ori (REGISTER_O0,0,REGISTER_O0); + as_hi_or_lo_label (parameter.parameter_data.l,2+(parameter.parameter_offset<<3),LO12_RELOCATION); + + parameter.parameter_type=P_REGISTER; + parameter.parameter_data.reg.r=REGISTER_O0; + break; + case P_IMMEDIATE: + if (parameter.parameter_data.i==0){ + parameter.parameter_type=P_REGISTER; + parameter.parameter_data.reg.r=REGISTER_G0; + } else { + as_set (parameter.parameter_data.i,REGISTER_O0); + + parameter.parameter_type=P_REGISTER; + parameter.parameter_data.reg.r=REGISTER_O0; + } + break; + case P_REGISTER: + break; + case P_INDIRECT: + as_load (size_flag==SIZE_LONG ? LD_OP : size_flag==SIZE_WORD ? LDSH_OP : LDUB_OP, + parameter.parameter_offset,parameter.parameter_data.reg.r,REGISTER_O0); + + parameter.parameter_type=P_REGISTER; + parameter.parameter_data.reg.r=REGISTER_O0; + break; + case P_INDEXED: + if (parameter.parameter_offset!=0) + internal_error_in_function ("as_register_parameter"); + + as_load_x (size_flag==SIZE_LONG ? LD_OP : size_flag==SIZE_WORD ? LDSH_OP : LDUB_OP, + parameter.parameter_data.ir->a_reg.r,parameter.parameter_data.ir->d_reg.r,REGISTER_O0); + + parameter.parameter_type=P_REGISTER; + parameter.parameter_data.reg.r=REGISTER_O0; + break; + default: + internal_error_in_function ("as_register_parameter"); + } + return parameter; +} + +static void as_move_instruction (struct instruction *instruction,int size_flag) +{ + switch (instruction->instruction_parameters[1].parameter_type){ + case P_REGISTER: + switch (instruction->instruction_parameters[0].parameter_type){ + case P_DESCRIPTOR_NUMBER: + as_sethi (0,instruction->instruction_parameters[1].parameter_data.reg.r); + as_hi_or_lo_label ( instruction->instruction_parameters[0].parameter_data.l, + 2+(instruction->instruction_parameters[0].parameter_offset<<3),HI22_RELOCATION); + + as_ori (instruction->instruction_parameters[1].parameter_data.reg.r,0, + instruction->instruction_parameters[1].parameter_data.reg.r); + as_hi_or_lo_label ( instruction->instruction_parameters[0].parameter_data.l, + 2+(instruction->instruction_parameters[0].parameter_offset<<3),LO12_RELOCATION); + break; + case P_IMMEDIATE: + as_set (instruction->instruction_parameters[0].parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r); + break; + case P_REGISTER: + as_mov (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDIRECT: + as_load (size_flag==SIZE_LONG ? LD_OP : size_flag==SIZE_WORD ? LDSH_OP : LDUB_OP, + instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + break; + case P_INDEXED: + if (instruction->instruction_parameters[0].parameter_offset!=0) + internal_error_in_function ("as_move_instruction"); + + as_load_x (size_flag==SIZE_LONG ? LD_OP : size_flag==SIZE_WORD ? LDSH_OP : LDUB_OP, + instruction->instruction_parameters[0].parameter_data.ir->a_reg.r, + instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + break; + default: + internal_error_in_function ("as_move_instruction"); + return; + } + return; + case P_INDIRECT: + { + struct parameter parameter_0; + int offset; + + parameter_0=as_register_parameter (instruction->instruction_parameters[0],size_flag); + + offset=instruction->instruction_parameters[1].parameter_offset; + + if (((offset << (32-13)) >> (32-13))==offset){ + as_store (size_flag==SIZE_LONG ? ST_OP : size_flag==SIZE_WORD ? STH_OP : STB_OP, + parameter_0.parameter_data.reg.r,offset,instruction->instruction_parameters[1].parameter_data.reg.r); + } else { + as_sethi (offset>>10,REGISTER_O1); + + as_add (REGISTER_O1,instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O1); + + as_store (size_flag==SIZE_LONG ? ST_OP : size_flag==SIZE_WORD ? STH_OP : STB_OP, + parameter_0.parameter_data.reg.r,offset & 1023,REGISTER_O1); + } + + return; + } + case P_INDEXED: + { + struct parameter parameter_0; + + if (instruction->instruction_parameters[1].parameter_offset!=0) + internal_error_in_function ("as_move_instruction"); + + parameter_0=as_register_parameter (instruction->instruction_parameters[0],size_flag); + + as_store_x (size_flag==SIZE_LONG ? ST_OP : size_flag==SIZE_WORD ? STH_OP : STB_OP, + parameter_0.parameter_data.reg.r,instruction->instruction_parameters[1].parameter_data.ir->a_reg.r, + instruction->instruction_parameters[1].parameter_data.ir->d_reg.r); + return; + } + default: + internal_error_in_function ("as_move_instruction"); + } +} + +static void as_lea_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER) + switch (instruction->instruction_parameters[0].parameter_type){ + case P_LABEL: + as_sethi (0,instruction->instruction_parameters[1].parameter_data.reg.r); + as_hi_or_lo_label ( instruction->instruction_parameters[0].parameter_data.l, + instruction->instruction_parameters[0].parameter_offset,HI22_RELOCATION); + + as_ori (instruction->instruction_parameters[1].parameter_data.reg.r,0, + instruction->instruction_parameters[1].parameter_data.reg.r); + as_hi_or_lo_label ( instruction->instruction_parameters[0].parameter_data.l, + instruction->instruction_parameters[0].parameter_offset,LO12_RELOCATION); + return; + case P_INDIRECT: + as_addi (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDEXED: + as_add (instruction->instruction_parameters[0].parameter_data.ir->a_reg.r, + instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + + internal_error_in_function ("as_lea_instruction"); +} + +static void as_sll_instruction (struct instruction *instruction) +{ + as_slli ( instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[2].parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r); +} + +static void as_logical_or_shift_instruction (struct instruction *instruction,int opcode) +{ + struct parameter parameter; + + parameter=instruction->instruction_parameters[0]; + + switch (parameter.parameter_type){ + case P_IMMEDIATE: + if ((unsigned)(parameter.parameter_data.i+4096)>=(unsigned)8192){ + as_set (parameter.parameter_data.i,REGISTER_O0); + + parameter.parameter_type=P_REGISTER; + parameter.parameter_data.reg.r=REGISTER_O0; + } else { + as_i_aid2 ( instruction->instruction_parameters[1].parameter_data.reg.r, + parameter.parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r,opcode); + return; + } + break; + case P_INDIRECT: + as_ld (parameter.parameter_offset,parameter.parameter_data.reg.r,REGISTER_O0); + + parameter.parameter_type=P_REGISTER; + parameter.parameter_data.reg.r=REGISTER_O0; + break; + case P_INDEXED: + if (parameter.parameter_offset!=0) + internal_error_in_function ("as_tryadic_instruction"); + + as_ld_x (parameter.parameter_data.ir->a_reg.r,parameter.parameter_data.ir->d_reg.r,REGISTER_O0); + + parameter.parameter_type=P_REGISTER; + parameter.parameter_data.reg.r=REGISTER_O0; + } + + as_i_abd2 ( instruction->instruction_parameters[1].parameter_data.reg.r, + parameter.parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r,opcode); +} + +static void as_add_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_add (instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_IMMEDIATE: + if ((unsigned)(instruction->instruction_parameters[0].parameter_data.i+4096)<(unsigned)8192){ + as_inc (instruction->instruction_parameters[0].parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } else { + as_set (instruction->instruction_parameters[0].parameter_data.i,REGISTER_O0); + + as_add (instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O0, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + default: + as_ld_parameter (&instruction->instruction_parameters[0],REGISTER_O0); + + as_add (instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O0, + instruction->instruction_parameters[1].parameter_data.reg.r); + } +} + +static void as_add_o_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_addcc ( instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_IMMEDIATE: + if ((unsigned)(instruction->instruction_parameters[0].parameter_data.i+4096)<(unsigned)8192){ + as_inccc ( instruction->instruction_parameters[0].parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } else { + as_set (instruction->instruction_parameters[0].parameter_data.i,REGISTER_O0); + + as_addcc (instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O0, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + default: + as_ld_parameter (&instruction->instruction_parameters[0],REGISTER_O0); + + as_addcc ( instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O0, + instruction->instruction_parameters[1].parameter_data.reg.r); + } +} + +static void as_sub_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_sub (instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_IMMEDIATE: + if ((unsigned)(instruction->instruction_parameters[0].parameter_data.i+4096)<(unsigned)8192){ + as_dec (instruction->instruction_parameters[0].parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } else { + as_set (instruction->instruction_parameters[0].parameter_data.i,REGISTER_O0); + + as_sub (instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O0, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + default: + as_ld_parameter (&instruction->instruction_parameters[0],REGISTER_O0); + + as_sub (instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O0, + instruction->instruction_parameters[1].parameter_data.reg.r); + } +} + +static void as_sub_o_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_subcc (instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_IMMEDIATE: + if ((unsigned)(instruction->instruction_parameters[0].parameter_data.i+4096)<(unsigned)8192){ + as_deccc (instruction->instruction_parameters[0].parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } else { + as_set (instruction->instruction_parameters[0].parameter_data.i,REGISTER_O0); + + as_subcc (instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O0, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + default: + as_ld_parameter (&instruction->instruction_parameters[0],REGISTER_O0); + + as_subcc (instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O0, + instruction->instruction_parameters[1].parameter_data.reg.r); + } +} + +static void as_cmp_instruction (struct instruction *instruction,int size_flag) +{ + struct parameter parameter_0,parameter_1; + + parameter_0=instruction->instruction_parameters[0]; + parameter_1=instruction->instruction_parameters[1]; + + if (parameter_1.parameter_type==P_INDIRECT){ + if (size_flag==SIZE_LONG) + as_ld (parameter_1.parameter_offset,parameter_1.parameter_data.reg.r,REGISTER_O1); + else + as_ldsh (parameter_1.parameter_offset,parameter_1.parameter_data.reg.r,REGISTER_O1); + + parameter_1.parameter_type=P_REGISTER; + parameter_1.parameter_data.reg.r=REGISTER_O1; + } else if (parameter_1.parameter_type==P_INDEXED){ + if (parameter_1.parameter_offset!=0) + internal_error_in_function ("as_cmp_instruction"); + + if (size_flag==SIZE_LONG) + as_ld_x (parameter_1.parameter_data.ir->a_reg.r,parameter_1.parameter_data.ir->d_reg.r,REGISTER_O1); + else + as_ldsh_x (parameter_1.parameter_data.ir->a_reg.r,parameter_1.parameter_data.ir->d_reg.r,REGISTER_O1); + + parameter_1.parameter_type=P_REGISTER; + parameter_1.parameter_data.reg.r=REGISTER_O1; + } + + switch (parameter_0.parameter_type){ + case P_DESCRIPTOR_NUMBER: + as_sethi (0,REGISTER_O0); + as_hi_or_lo_label (parameter_0.parameter_data.l,2+(parameter_0.parameter_offset<<3),HI22_RELOCATION); + + as_ori (REGISTER_O0,0,REGISTER_O0); + as_hi_or_lo_label (parameter_0.parameter_data.l,2+(parameter_0.parameter_offset<<3),LO12_RELOCATION); + + parameter_0.parameter_type=P_REGISTER; + parameter_0.parameter_data.reg.r=REGISTER_O0; + break; + case P_IMMEDIATE: + if ((unsigned)(parameter_0.parameter_data.i+4096)>=(unsigned)8192){ + as_set (parameter_0.parameter_data.i,REGISTER_O0); + + parameter_0.parameter_type=P_REGISTER; + parameter_0.parameter_data.reg.r=REGISTER_O0; + } else { + as_cmpi (parameter_1.parameter_data.reg.r,parameter_0.parameter_data.i); + return; + } + break; + case P_REGISTER: + break; + default: + switch (size_flag){ + case SIZE_WORD: + as_ldsh_parameter (¶meter_0,REGISTER_O0); + break; + case SIZE_LONG: + as_ld_parameter (¶meter_0,REGISTER_O0); + break; + default: + internal_error_in_function ("as_cmp_instruction"); + } + + parameter_0.parameter_type=P_REGISTER; + parameter_0.parameter_data.reg.r=REGISTER_O0; + } + + as_cmp (parameter_1.parameter_data.reg.r,parameter_0.parameter_data.reg.r); +} + +static void as_tst_instruction (struct instruction *instruction,int size_flag) +{ + struct parameter parameter_0; + + if (size_flag!=SIZE_LONG) + internal_error_in_function ("as_tst_instruction"); + + parameter_0=as_register_parameter (instruction->instruction_parameters[0],size_flag); + + as_tst (parameter_0.parameter_data.reg.r); +} + +static void as_btst_instruction (struct instruction *instruction) +{ + as_btst (instruction->instruction_parameters[0].parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r); +} + +void as_jmp_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_LABEL){ + if (instruction->instruction_parameters[0].parameter_data.l->label_flags & LOCAL_LABEL){ + as_i_bica (0,A_COND); + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,BRANCH_RELOCATION); + return; + } else { + as_i_call (0); + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,CALL_RELOCATION); + + as_nop(); + } + } else if (instruction->instruction_parameters[0].parameter_type==P_INDIRECT){ + as_jmpli ( instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_G0); + + as_nop(); + } else + internal_error_in_function ("as_jmp_instruction"); +} + +static void as_branch_instruction (struct instruction *instruction,int condition) +{ + as_i_bic (0,condition); + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,BRANCH_RELOCATION); + + as_nop(); +} + +static void as_index_error_branch_instruction (struct instruction *instruction) +{ + as_i_bic (12>>2,CS_COND); + + as_nop(); + + as_i_bica (0,A_COND); + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,BRANCH_RELOCATION); +} + +static void as_float_branch_instruction (struct instruction *instruction,int condition) +{ + as_nop(); + + as_i_fbic (0,condition); + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,BRANCH_RELOCATION); + + as_nop(); +} + +static void as_jsr_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_LABEL){ + as_i_call (0); + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,CALL_RELOCATION); + + if (instruction->instruction_parameters[1].parameter_type==P_INDIRECT) + as_st (REGISTER_O7,instruction->instruction_parameters[1].parameter_data.i,B_STACK_POINTER); + else + as_nop(); + } else if (instruction->instruction_parameters[1].parameter_type==P_INDIRECT){ + as_jmpli ( instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_O7); + + + as_st (REGISTER_O7,instruction->instruction_parameters[1].parameter_data.i,B_STACK_POINTER); + } else + internal_error_in_function ("as_jsr_instruction"); +} + +static void as_rts_instruction (struct instruction *instruction) +{ + int b_offset; + + as_ld (instruction->instruction_parameters[0].parameter_offset,B_STACK_POINTER,REGISTER_O7); + + as_retl(); + + b_offset=instruction->instruction_parameters[1].parameter_data.i; + if (b_offset==0) + as_nop(); + else { + if (b_offset<0) + as_dec (-b_offset,B_STACK_POINTER); + else + as_inc (b_offset,B_STACK_POINTER); + } +} + +static void as_set_condition_instruction (struct instruction *instruction,int condition) +{ + as_clr (instruction->instruction_parameters[0].parameter_data.reg.r); + + as_i_bica (2-1,condition); + + as_movi (-1,instruction->instruction_parameters[0].parameter_data.reg.r); +} + +static void as_set_float_condition_instruction (struct instruction *instruction,int condition) +{ + as_nop(); + + as_clr (instruction->instruction_parameters[0].parameter_data.reg.r); + + as_i_fbica (2-1,condition); + + as_movi (-1,instruction->instruction_parameters[0].parameter_data.reg.r); +} + +extern struct label *dot_rem_label,*dot_div_label,*dot_mul_label; + +static void w_as_mod_instruction (struct instruction *instruction) +{ + as_mov (instruction->instruction_parameters[2].parameter_data.reg.r,REGISTER_O0); + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_i_call (0); + as_branch_label (dot_rem_label,CALL_RELOCATION); + + as_mov (instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_O1); + break; + case P_IMMEDIATE: + { + long v; + + v=instruction->instruction_parameters[0].parameter_data.i; + + if ((unsigned)(v+4096) < (unsigned)8192){ + as_i_call (0); + as_branch_label (dot_rem_label,CALL_RELOCATION); + + as_movi (v,REGISTER_O1); + } else { + as_sethi (v>>10,REGISTER_O1); + + as_i_call (0); + as_branch_label (dot_rem_label,CALL_RELOCATION); + + as_ori (REGISTER_O1,v & 1023,REGISTER_O1); + } + break; + } + default: + as_i_call (0); + as_branch_label (dot_rem_label,CALL_RELOCATION); + + as_ld_parameter (&instruction->instruction_parameters[0],REGISTER_O1); + } + + as_mov (REGISTER_O0,instruction->instruction_parameters[1].parameter_data.reg.r); +} + +static void w_as_mul_or_div_instruction (struct instruction *instruction,struct label *mul_or_div_label) +{ + as_mov (instruction->instruction_parameters[1].parameter_data.reg.r,REGISTER_O0); + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_i_call (0); + as_branch_label (mul_or_div_label,CALL_RELOCATION); + + as_mov (instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_O1); + break; + case P_IMMEDIATE: + { + long v; + + v=instruction->instruction_parameters[0].parameter_data.i; + + if ((unsigned)(v+4096) < (unsigned)8192){ + as_i_call (0); + as_branch_label (mul_or_div_label,CALL_RELOCATION); + + as_movi (v,REGISTER_O1); + } else { + as_sethi (v>>10,REGISTER_O1); + + as_i_call (0); + as_branch_label (mul_or_div_label,CALL_RELOCATION); + + as_ori (REGISTER_O1,v & 1023,REGISTER_O1); + } + break; + } + default: + as_i_call (0); + as_branch_label (mul_or_div_label,CALL_RELOCATION); + + as_ld_parameter (&instruction->instruction_parameters[0],REGISTER_O1); + } + + as_mov (REGISTER_O0,instruction->instruction_parameters[1].parameter_data.reg.r); +} + +#ifndef FUNCTION_LEVEL_LINKING +static int data_section_alignment_mask; +#endif + +static void as_load_float_immediate (double float_value,int fp_reg) +{ + struct label *new_label; + + new_label=allocate_memory_from_heap_type (struct label); + + new_label->label_flags=DATA_LABEL; + new_label->label_id=DATA_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + new_label->label_object_label=data_object_label; + + data_object_label->object_section_align8=1; +#else + data_section_alignment_mask |= 7; +#endif + +#ifdef FUNCTION_LEVEL_LINKING + if ((((unsigned char*)data_buffer_p-current_data_buffer->data)-data_object_label->object_label_offset) & 4) +#else + if ((((unsigned char*)data_buffer_p-current_data_buffer->data) & 4)!=0) +#endif + store_long_word_in_data_section (0); + + new_label->label_offset=CURRENT_DATA_OFFSET; + + new_label->label_number=next_label_id++; + + store_long_word_in_data_section (((ULONG*)&float_value)[0]); + store_long_word_in_data_section (((ULONG*)&float_value)[1]); + + as_sethi (0,REGISTER_O0); + as_hi_or_lo_label (new_label,0,HI22_RELOCATION); + + as_lddf (0,REGISTER_O0,fp_reg<<1); + as_hi_or_lo_label (new_label,0,LO12_RELOCATION); +} + +static struct parameter as_float_parameter (struct parameter parameter) +{ + switch (parameter.parameter_type){ + case P_F_IMMEDIATE: + as_load_float_immediate (*parameter.parameter_data.r,15); + + parameter.parameter_type=P_F_REGISTER; + parameter.parameter_data.reg.r=15; + break; + case P_INDIRECT: + as_ldf (parameter.parameter_offset,parameter.parameter_data.reg.r,30); + as_ldf (parameter.parameter_offset+4,parameter.parameter_data.reg.r,31); + + parameter.parameter_type=P_F_REGISTER; + parameter.parameter_data.reg.r=15; + break; + case P_INDEXED: + as_add (parameter.parameter_data.ir->a_reg.r,parameter.parameter_data.ir->d_reg.r,REGISTER_O0); + + as_ldf (parameter.parameter_offset>>2,REGISTER_O0,30); + as_ldf ((parameter.parameter_offset>>2)+4,REGISTER_O0,31); + + parameter.parameter_type=P_F_REGISTER; + parameter.parameter_data.reg.r=15; + break; + } + return parameter; +} + +static void as_compare_float_instruction (struct instruction *instruction) +{ + struct parameter parameter_0; + + parameter_0=as_float_parameter (instruction->instruction_parameters[0]); + + as_fcmpd (instruction->instruction_parameters[1].parameter_data.reg.r<<1,parameter_0.parameter_data.reg.r<<1); +} + +static void as_sqrt_float_instruction (struct instruction *instruction) +{ + struct parameter parameter_0; + + parameter_0=as_float_parameter (instruction->instruction_parameters[0]); + + as_fsqrtd (parameter_0.parameter_data.reg.r<<1,instruction->instruction_parameters[1].parameter_data.reg.r<<1); +} + +static void as_neg_float_instruction (struct instruction *instruction) +{ + struct parameter parameter_0; + int freg1,freg2; + + parameter_0=as_float_parameter (instruction->instruction_parameters[0]); + + freg1=parameter_0.parameter_data.reg.r; + freg2=instruction->instruction_parameters[1].parameter_data.reg.r; + + as_fnegs (freg1<<1,freg2<<1); + + if (freg1!=freg2) + as_fmovs ((freg1<<1)+1,(freg2<<1)+1); +} + +static void as_tryadic_float_instruction (struct instruction *instruction,int opcode) +{ + struct parameter parameter_0; + + parameter_0=as_float_parameter (instruction->instruction_parameters[0]); + + as_i_fff2 (instruction->instruction_parameters[1].parameter_data.reg.r<<1, + parameter_0.parameter_data.reg.r<<1, + instruction->instruction_parameters[1].parameter_data.reg.r<<1, + 0x34,opcode); +} + +static struct instruction *as_fmove_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[1].parameter_type){ + case P_F_REGISTER: + switch (instruction->instruction_parameters[0].parameter_type){ + case P_F_REGISTER: + { + struct instruction *next_instruction; + int reg0,reg1; + + reg0=instruction->instruction_parameters[0].parameter_data.reg.r; + reg1=instruction->instruction_parameters[1].parameter_data.reg.r; + + next_instruction=instruction->instruction_next; + if (next_instruction) + switch (next_instruction->instruction_icode){ + case IFADD: case IFSUB: case IFMUL: case IFDIV: + if (next_instruction->instruction_parameters[1].parameter_data.reg.r==reg1) + { + struct parameter parameter_0; + int reg_s; + + parameter_0=as_float_parameter (next_instruction->instruction_parameters[0]); + + reg_s=parameter_0.parameter_data.reg.r; + if (reg_s==reg1) + reg_s=reg0; + + switch (next_instruction->instruction_icode){ + case IFADD: + as_faddd (reg0<<1,reg_s<<1,reg1<<1); + break; + case IFSUB: + as_fsubd (reg0<<1,reg_s<<1,reg1<<1); + break; + case IFMUL: + as_fmuld (reg0<<1,reg_s<<1,reg1<<1); + break; + case IFDIV: + as_fdivd (reg0<<1,reg_s<<1,reg1<<1); + break; + } + + return next_instruction; + } + } + + as_fmovs (reg0<<1,reg1<<1); + as_fmovs ((reg0<<1)+1,(reg1<<1)+1); + + return instruction; + } + case P_INDIRECT: + as_ldf (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r<<1); + + as_ldf (instruction->instruction_parameters[0].parameter_offset+4, + instruction->instruction_parameters[0].parameter_data.reg.r, + (instruction->instruction_parameters[1].parameter_data.reg.r<<1)+1); + + return instruction; + case P_INDEXED: + as_add (instruction->instruction_parameters[0].parameter_data.ir->a_reg.r, + instruction->instruction_parameters[0].parameter_data.ir->d_reg.r,REGISTER_O0); + + as_ldf (instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_O0, + instruction->instruction_parameters[1].parameter_data.reg.r<<1); + + as_ldf ((instruction->instruction_parameters[0].parameter_offset>>2)+4,REGISTER_O0, + (instruction->instruction_parameters[1].parameter_data.reg.r<<1)+1); + + return instruction; + case P_F_IMMEDIATE: + as_load_float_immediate (*instruction->instruction_parameters[0].parameter_data.r,instruction->instruction_parameters[1].parameter_data.reg.r); + return instruction; + } + break; + case P_INDIRECT: + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + as_stf (instruction->instruction_parameters[0].parameter_data.reg.r<<1, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + + as_stf ((instruction->instruction_parameters[0].parameter_data.reg.r<<1)+1, + instruction->instruction_parameters[1].parameter_offset+4, + instruction->instruction_parameters[1].parameter_data.reg.r); + + return instruction; + } + break; + case P_INDEXED: + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + as_add (instruction->instruction_parameters[1].parameter_data.ir->a_reg.r, + instruction->instruction_parameters[1].parameter_data.ir->d_reg.r,REGISTER_O0); + + as_stf (instruction->instruction_parameters[0].parameter_data.reg.r<<1, + instruction->instruction_parameters[1].parameter_offset>>2,REGISTER_O0); + + as_stf ((instruction->instruction_parameters[0].parameter_data.reg.r<<1)+1, + (instruction->instruction_parameters[1].parameter_offset>>2)+4,REGISTER_O0); + + return instruction; + } + } + internal_error_in_function ("as_fmove_instruction"); + return instruction; +} + +static void as_fmove_hl_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_INDIRECT + && instruction->instruction_parameters[1].parameter_type==P_F_REGISTER) + { + if (instruction->instruction_icode==IFMOVEHI) + as_ldf (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r<<1); + else + as_ldf (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r, + (instruction->instruction_parameters[1].parameter_data.reg.r<<1)+1); + return; + } + + internal_error_in_function ("as_fmove_hl_instruction"); +} + +static void as_fmovel_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + if (instruction->instruction_parameters[1].parameter_type!=P_REGISTER) + internal_error_in_function ("as_fmovel_instruction"); + + as_fdtoi (instruction->instruction_parameters[0].parameter_data.reg.r<<1,31); + + as_stf (31,-4,REGISTER_I6); + + as_ld (-4,REGISTER_I6,instruction->instruction_parameters[1].parameter_data.reg.r); + } else { + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_st (instruction->instruction_parameters[0].parameter_data.reg.r,-4,REGISTER_I6); + + as_ldf (-4,REGISTER_I6,31); + break; + case P_INDIRECT: + as_ldf (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,31); + break; + case P_INDEXED: + if (instruction->instruction_parameters[0].parameter_offset!=0) + internal_error_in_function ("as_movel_instruction"); + + as_ldf_x (instruction->instruction_parameters[0].parameter_data.ir->a_reg.r, + instruction->instruction_parameters[0].parameter_data.ir->d_reg.r,31); + break; + case P_IMMEDIATE: + as_set (instruction->instruction_parameters[0].parameter_data.i,REGISTER_O0); + + as_st (REGISTER_O0,-4,REGISTER_I6); + + as_ldf (-4,REGISTER_I6,31); + break; + default: + internal_error_in_function ("as_fmovel_instruction"); + } + + as_fitod (31,instruction->instruction_parameters[1].parameter_data.reg.r<<1); + } +} + +static void as_instructions (register struct instruction *instruction) +{ + while (instruction!=NULL){ + switch (instruction->instruction_icode){ + case IMOVE: + as_move_instruction (instruction,SIZE_LONG); + break; + case ILEA: + as_lea_instruction (instruction); + break; + case IADD: + as_add_instruction (instruction); + break; + case IADDI: + as_addi (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[2].parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r); + break; + case ISUB: + as_sub_instruction (instruction); + break; + case ICMP: + as_cmp_instruction (instruction,SIZE_LONG); + break; + case IJMP: + as_jmp_instruction (instruction); + break; + case IJSR: + as_jsr_instruction (instruction); + break; + case IRTS: + as_rts_instruction (instruction); + break; + case IBEQ: + as_branch_instruction (instruction,E_COND); + break; + case IBGE: + as_branch_instruction (instruction,GE_COND); + break; + case IBGT: + as_branch_instruction (instruction,G_COND); + break; + case IBHS: + as_index_error_branch_instruction (instruction); + break; + case IBLE: + as_branch_instruction (instruction,LE_COND); + break; + case IBLT: + as_branch_instruction (instruction,L_COND); + break; + case IBNE: + as_branch_instruction (instruction,NE_COND); + break; + case IBNO: + as_branch_instruction (instruction,VC_COND); + break; + case IBO: + as_branch_instruction (instruction,VS_COND); + break; + case ILSLI: + as_sll_instruction (instruction); + break; + case ILSL: + as_logical_or_shift_instruction (instruction,SLL_OP); + break; + case ILSR: + as_logical_or_shift_instruction (instruction,SRL_OP); + break; + case IASR: + as_logical_or_shift_instruction (instruction,SRA_OP); + break; + case IMUL: + w_as_mul_or_div_instruction (instruction,dot_mul_label); + break; + case IDIV: + w_as_mul_or_div_instruction (instruction,dot_div_label); + break; + case IMOD: + w_as_mod_instruction (instruction); + break; + case IAND: + as_logical_or_shift_instruction (instruction,AND_OP); + break; + case IOR: + as_logical_or_shift_instruction (instruction,OR_OP); + break; + case IEOR: + as_logical_or_shift_instruction (instruction,XOR_OP); + break; + case ISEQ: + as_set_condition_instruction (instruction,E_COND); + break; + case ISGE: + as_set_condition_instruction (instruction,GE_COND); + break; + case ISGT: + as_set_condition_instruction (instruction,G_COND); + break; + case ISLE: + as_set_condition_instruction (instruction,LE_COND); + break; + case ISLT: + as_set_condition_instruction (instruction,L_COND); + break; + case ISNE: + as_set_condition_instruction (instruction,NE_COND); + break; + case ISNO: + as_set_condition_instruction (instruction,VC_COND); + break; + case ISO: + as_set_condition_instruction (instruction,VS_COND); + break; + case ICMPW: + as_cmp_instruction (instruction,SIZE_WORD); + break; + case ITST: + as_tst_instruction (instruction,SIZE_LONG); + break; + case IBTST: + as_btst_instruction (instruction); + break; + case IMOVEW: + as_move_instruction (instruction,SIZE_WORD); + break; + case IMOVEB: + as_move_instruction (instruction,SIZE_BYTE); + break; + case IFMOVE: + instruction=as_fmove_instruction (instruction); + break; + case IFMOVEHI: + case IFMOVELO: + as_fmove_hl_instruction (instruction); + break; + case IFADD: + as_tryadic_float_instruction (instruction,FADDD_OP); + break; + case IFSUB: + as_tryadic_float_instruction (instruction,FSUBD_OP); + break; + case IFCMP: + as_compare_float_instruction (instruction); + break; + case IFDIV: + as_tryadic_float_instruction (instruction,FDIVD_OP); + break; + case IFMUL: + as_tryadic_float_instruction (instruction,FMULD_OP); + break; + case IFBEQ: + as_float_branch_instruction (instruction,FE_COND); + break; + case IFBGE: + as_float_branch_instruction (instruction,FGE_COND); + break; + case IFBGT: + as_float_branch_instruction (instruction,FG_COND); + break; + case IFBLE: + as_float_branch_instruction (instruction,FLE_COND); + break; + case IFBLT: + as_float_branch_instruction (instruction,FL_COND); + break; + case IFBNE: + as_float_branch_instruction (instruction,FNE_COND); + break; + case IFMOVEL: + as_fmovel_instruction (instruction); + break; + case IFSQRT: + as_sqrt_float_instruction (instruction); + break; + case IFNEG: + as_neg_float_instruction (instruction); + break; + case IFSEQ: + as_set_float_condition_instruction (instruction,FE_COND); + break; + case IFSGE: + as_set_float_condition_instruction (instruction,FGE_COND); + break; + case IFSGT: + as_set_float_condition_instruction (instruction,FG_COND); + break; + case IFSLE: + as_set_float_condition_instruction (instruction,FLE_COND); + break; + case IFSLT: + as_set_float_condition_instruction (instruction,FL_COND); + break; + case IFSNE: + as_set_float_condition_instruction (instruction,FNE_COND); + break; + case IWORD: + store_instruction (instruction->instruction_parameters[0].parameter_data.i); + break; + case IADDO: + as_add_o_instruction (instruction); + break; + case ISUBO: + as_sub_o_instruction (instruction); + break; + case IFTST: + default: + internal_error_in_function ("as_instructions"); + } + instruction=instruction->instruction_next; + } +} + +static void as_number_of_arguments (int n_node_arguments) +{ + store_instruction (n_node_arguments); +} + +struct call_and_jump { + struct call_and_jump * cj_next; + struct label * cj_call_label; + struct label cj_label; + struct label cj_jump_label; +}; + +static struct call_and_jump *first_call_and_jump,*last_call_and_jump; + +static void as_garbage_collect_test (struct basic_block *block) +{ + LONG n_cells; + struct call_and_jump *new_call_and_jump; + + new_call_and_jump=allocate_memory_from_heap (sizeof (struct call_and_jump)); + + new_call_and_jump->cj_next=NULL; + new_call_and_jump->cj_label.label_flags=0; + + switch (block->block_n_begin_a_parameter_registers){ + case 0: new_call_and_jump->cj_call_label=collect_0_label; break; + case 1: new_call_and_jump->cj_call_label=collect_1_label; break; + case 2: new_call_and_jump->cj_call_label=collect_2_label; break; + case 3: new_call_and_jump->cj_call_label=collect_3_label; break; + default: internal_error_in_function ("as_garbage_collect_test"); + } + + if (first_call_and_jump!=NULL) + last_call_and_jump->cj_next=new_call_and_jump; + else + first_call_and_jump=new_call_and_jump; + last_call_and_jump=new_call_and_jump; + + n_cells=block->block_n_new_heap_cells; + + if (n_cells<4096) + as_deccc (n_cells,REGISTER_D7); + else { + as_set (n_cells,REGISTER_O0); + as_subcc (REGISTER_D7,REGISTER_O0,REGISTER_D7); + } + + as_i_bica (0,CS_COND); + as_branch_label (&new_call_and_jump->cj_label,BRANCH_RELOCATION); + + as_dec (4,B_STACK_POINTER); + + new_call_and_jump->cj_jump_label.label_flags=0; + new_call_and_jump->cj_jump_label.label_id=TEXT_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + new_call_and_jump->cj_jump_label.label_object_label=code_object_label; +#endif + new_call_and_jump->cj_jump_label.label_offset=CURRENT_CODE_OFFSET; +} + +static void as_call_and_jump (struct call_and_jump *call_and_jump) +{ + call_and_jump->cj_label.label_id=TEXT_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + call_and_jump->cj_label.label_object_label=code_object_label; +#endif + call_and_jump->cj_label.label_offset=CURRENT_CODE_OFFSET; + + as_i_call (0); + as_branch_label (call_and_jump->cj_call_label,CALL_RELOCATION); + + as_st (REGISTER_O7,0,B_STACK_POINTER); + + as_i_bica (0,A_COND); + as_branch_label (&call_and_jump->cj_jump_label,BRANCH_RELOCATION); +} + +void initialize_assembler (FILE *output_file_d) +{ + output_file=output_file_d; + setvbuf (output_file,NULL,_IOFBF,IO_BUFFER_SIZE); + + n_object_labels=1; + + first_object_label=NULL; + last_object_label_l=&first_object_label; + + first_code_relocation=NULL; + first_data_relocation=NULL; + last_code_relocation_l=&first_code_relocation; + last_data_relocation_l=&first_data_relocation; + n_code_relocations=0; + n_data_relocations=0; +#ifndef FUNCTION_LEVEL_LINKING + data_section_alignment_mask=3; +#endif + + string_table_offset=1; + initialize_buffers(); + +#ifdef FUNCTION_LEVEL_LINKING + code_object_label=NULL; + n_code_sections=0; + + data_object_label=NULL; + n_data_sections=0; +#else + code_object_label=fast_memory_allocate_type (struct object_label); + ++n_object_labels; + *last_object_label_l=code_object_label; + last_object_label_l=&code_object_label->next; + code_object_label->next=NULL; + + code_object_label->object_label_offset=0; + code_object_label->object_label_length=0; + code_object_label->object_label_kind=CODE_CONTROL_SECTION; + + data_object_label=fast_memory_allocate_type (struct object_label); + ++n_object_labels; + *last_object_label_l=data_object_label; + last_object_label_l=&data_object_label->next; + data_object_label->next=NULL; + + data_object_label->object_label_offset=0; + data_object_label->object_label_length=0; + data_object_label->object_label_kind=DATA_CONTROL_SECTION; + data_object_label->object_section_align8=0; +#endif +} + +static void as_indirect_node_entry_jump (LABEL *label) +{ + long new_label_offset; + struct label *new_label; + +#ifdef FUNCTION_LEVEL_LINKING + as_new_code_module(); +#endif + + if (label->label_flags & EA_LABEL){ + int label_arity; + extern LABEL *eval_fill_label,*eval_upd_labels[]; + + label_arity=label->label_arity; + + if (label_arity<-2) + label_arity=1; + + if (label_arity>=0 && label->label_ea_label!=eval_fill_label){ + as_sethi (0,REGISTER_A2); + as_hi_or_lo_label (label->label_ea_label,0,HI22_RELOCATION); + + as_i_call (0); + as_branch_label (eval_upd_labels[label_arity],CALL_RELOCATION); + + as_ori (REGISTER_A2,0,REGISTER_A2); + as_hi_or_lo_label (label->label_ea_label,0,LO12_RELOCATION); + } else { + as_i_call (0); + as_branch_label (label->label_ea_label,CALL_RELOCATION); + + as_nop(); + as_nop(); + } + + if (label->label_arity<0 || parallel_flag){ + LABEL *descriptor_label; + + descriptor_label=label->label_descriptor; + + if (descriptor_label->label_id<0) + descriptor_label->label_id=next_label_id++; + + store_label_in_code_section (descriptor_label); + } else + as_number_of_arguments (0); + } else + if (label->label_arity<0 || parallel_flag){ + LABEL *descriptor_label; + + descriptor_label=label->label_descriptor; + + if (descriptor_label->label_id<0) + descriptor_label->label_id=next_label_id++; + + store_label_in_code_section (descriptor_label); + } + + as_number_of_arguments (label->label_arity); + + new_label_offset = CURRENT_CODE_OFFSET; + + new_label=allocate_memory_from_heap_type (struct label); + *new_label=*label; + + as_i_call (0); + as_branch_label (new_label,CALL_RELOCATION); + + label->label_id=TEXT_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + label->label_object_label=code_object_label; +#endif + label->label_offset=new_label_offset; + + as_nop(); +} + +static void as_import_labels (struct label_node *label_node) +{ + LABEL *label; + + if (label_node==NULL) + return; + + label=&label_node->label_node_label; + + if (!(label->label_flags & LOCAL_LABEL) && label->label_number==0){ + struct object_label *new_object_label; + int string_length; + + new_object_label=fast_memory_allocate_type (struct object_label); + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_label=label; + + label->label_id=n_object_labels; + ++n_object_labels; + + label->label_offset=0; + + string_length=strlen (label->label_name); + new_object_label->object_label_string_offset=string_table_offset; + string_table_offset+=string_length+1; + + new_object_label->object_label_kind=IMPORTED_LABEL; + } + + as_import_labels (label_node->label_node_left); + as_import_labels (label_node->label_node_right); +} + +static void write_c (int c) +{ + fputc (c,output_file); +} + +static void write_w (int c) +{ + fputc (c>>8,output_file); + fputc (c,output_file); +} + +static void write_l (int c) +{ + fputc (c>>24,output_file); + fputc (c>>16,output_file); + fputc (c>>8,output_file); + fputc (c,output_file); +} + +static void write_zstring (char *string) +{ + char c; + + do { + c=*string++; + write_c (c); + } while (c!='\0'); +} + +#ifdef FUNCTION_LEVEL_LINKING +static int compute_section_strings_size (int string_size_without_digits,int n_sections) +{ + int section_strings_size,max_n_digits,power10_max_n_digits; + + section_strings_size=0; + max_n_digits=1; + power10_max_n_digits=10; + while (n_sections>power10_max_n_digits){ + section_strings_size-=power10_max_n_digits; + ++max_n_digits; + power10_max_n_digits*=10; + } + section_strings_size+=(string_size_without_digits+max_n_digits+1)*n_sections; + + return section_strings_size; +} + +static int n_digits (int n) +{ + int i,power10; + + i=1; + power10=10; + + while (n>=power10){ + ++i; + power10*=10; + } + + return i; +} + +static int n_sections; +#endif + +static void write_file_header_and_section_headers (void) +{ + unsigned int offset; + +#ifdef FUNCTION_LEVEL_LINKING + int n_code_relocation_sections,n_data_relocation_sections; + int section_strings_size; + + n_sections=n_code_sections+n_data_sections; + + { + struct object_label *object_label,*previous_code_object_label,*previous_data_object_label; + struct relocation *code_relocation,*data_relocation; + int code_offset,data_offset; + + code_relocation=first_code_relocation; + code_offset=0; + n_code_relocation_sections=0; + previous_code_object_label=NULL; + + data_relocation=first_data_relocation; + data_offset=0; + n_data_relocation_sections=0; + previous_data_object_label=NULL; + + section_strings_size=0; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==CODE_CONTROL_SECTION){ + if (previous_code_object_label!=NULL){ + int code_section_length,n_code_relocations_in_section; + + code_section_length=object_label->object_label_offset-code_offset; + + n_code_relocations_in_section=0; + while (code_relocation!=NULL && + (code_relocation->relocation_offset < code_offset+code_section_length + || (code_relocation->relocation_offset==code_offset+code_section_length && code_relocation->relocation_kind==DUMMY_BRANCH_RELOCATION))) + { + code_relocation->relocation_offset-=code_offset; + ++n_code_relocations_in_section; + + code_relocation=code_relocation->next; + } + + previous_code_object_label->object_label_length=code_section_length; + previous_code_object_label->object_label_n_relocations=n_code_relocations_in_section; + + code_offset+=code_section_length; + if (n_code_relocations_in_section>0){ + section_strings_size+=13+n_digits (previous_code_object_label->object_label_section_n); + ++n_code_relocation_sections; + } + } + + previous_code_object_label=object_label; + } else if (object_label->object_label_kind==DATA_CONTROL_SECTION){ + if (previous_data_object_label!=NULL){ + int data_section_length,n_data_relocations_in_section; + + data_section_length=object_label->object_label_offset-data_offset; + + n_data_relocations_in_section=0; + while (data_relocation!=NULL && data_relocation->relocation_offset < data_offset+data_section_length){ + data_relocation->relocation_offset-=data_offset; + ++n_data_relocations_in_section; + + data_relocation=data_relocation->next; + } + + previous_data_object_label->object_label_length=data_section_length; + previous_data_object_label->object_label_n_relocations=n_data_relocations_in_section; + + data_offset+=data_section_length; + if (n_data_relocations_in_section>0){ + section_strings_size+=13+n_digits (previous_data_object_label->object_label_section_n); + ++n_data_relocation_sections; + } + } + + previous_data_object_label=object_label; + } + } + + if (previous_code_object_label!=NULL){ + int code_section_length,n_code_relocations_in_section; + + code_section_length=code_buffer_offset-code_offset; + + n_code_relocations_in_section=0; + while (code_relocation!=NULL){ + code_relocation->relocation_offset-=code_offset; + ++n_code_relocations_in_section; + + code_relocation=code_relocation->next; + } + + previous_code_object_label->object_label_n_relocations=n_code_relocations_in_section; + previous_code_object_label->object_label_length=code_section_length; + + if (n_code_relocations_in_section>0){ + section_strings_size+=13+n_digits (previous_code_object_label->object_label_section_n); + ++n_code_relocation_sections; + } + } + + if (previous_data_object_label!=NULL){ + int data_section_length,n_data_relocations_in_section; + + data_section_length=data_buffer_offset-data_offset; + + n_data_relocations_in_section=0; + while (data_relocation!=NULL){ + data_relocation->relocation_offset-=data_offset; + ++n_data_relocations_in_section; + + data_relocation=data_relocation->next; + } + + previous_data_object_label->object_label_n_relocations=n_data_relocations_in_section; + previous_data_object_label->object_label_length=data_section_length; + + if (n_data_relocations_in_section>0){ + section_strings_size+=13+n_digits (previous_data_object_label->object_label_section_n); + ++n_data_relocation_sections; + } + } + } + + section_strings_size+=compute_section_strings_size (7,n_code_sections)+ + compute_section_strings_size (7,n_data_sections); +#endif + + /* header: */ + write_l (0x7f454c46); + write_l (0x01020100); + write_l (0); + write_l (0); + write_l (0x00010002); + write_l (1); + write_l (0); + write_l (0); + write_l (0x34); + write_l (0); + write_l (0x00340000); + write_l (0x00000028); +#ifdef FUNCTION_LEVEL_LINKING + write_l (0x00000001 | ((n_sections+n_code_relocation_sections+n_data_relocation_sections+4)<<16)); +#else + write_l (0x00080001); +#endif + + /* offet 0x34: section header 0 */ + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + +#ifdef FUNCTION_LEVEL_LINKING + offset=0xd4+40*(n_sections+n_code_relocation_sections+n_data_relocation_sections); +#else + offset=0x174; +#endif + + /* offset 0x5c: section header 1 */ + write_l (1); /* .shstrtab offset */ + write_l (SHT_STRTAB); + write_l (0); + write_l (0); + write_l (offset); /* offset */ +#ifdef FUNCTION_LEVEL_LINKING + write_l ((27+section_strings_size+3) & -4); +#else + write_l (64); /* size */ +#endif + write_l (0); + write_l (0); + write_l (1); /* align */ + write_l (0); +#ifdef FUNCTION_LEVEL_LINKING + offset+=(27+section_strings_size+3) & -4; +#else + offset+=64; +#endif + +#ifdef FUNCTION_LEVEL_LINKING + { + struct object_label *object_label; + int code_offset,data_offset,code_relocations_offset,data_relocations_offset,section_string_offset; + + code_offset=0; + section_string_offset=11; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==CODE_CONTROL_SECTION){ + int code_section_length; + + code_section_length=object_label->object_label_length; + + write_l (section_string_offset); + write_l (SHT_PROGBITS); + write_l (SHF_ALLOC | SHF_EXECINSTR); + write_l (0); + write_l (offset+code_offset); + write_l (code_section_length); + write_l (0); + write_l (0); + write_l (4); + write_l (0); + + section_string_offset+=8+n_digits (object_label->object_label_section_n); + code_offset+=code_section_length; + } + } + offset+=(code_offset+3) & -4; + + data_offset=0; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==DATA_CONTROL_SECTION){ + int data_section_length; + + data_section_length=object_label->object_label_length; + + write_l (section_string_offset); + write_l (SHT_PROGBITS); + write_l (SHF_ALLOC | SHF_WRITE); + write_l (0); + write_l (offset+data_offset); + write_l (data_section_length); + write_l (0); + write_l (0); + write_l (object_label->object_section_align8 ? 8 : 4); + write_l (0); + + section_string_offset+=8+n_digits (object_label->object_label_section_n); + data_offset+=data_section_length; + } + } + + offset+=(data_offset+3) & -4; + + code_relocations_offset=0; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==CODE_CONTROL_SECTION){ + int n_code_relocations_in_section; + + n_code_relocations_in_section=object_label->object_label_n_relocations; + + if (n_code_relocations_in_section>0){ + write_l (section_string_offset); + write_l (SHT_RELA); + write_l (0); + write_l (0); + write_l (offset+code_relocations_offset); + write_l (12*n_code_relocations_in_section); + write_l (n_sections+n_code_relocation_sections+n_data_relocation_sections+2); + write_l (2+object_label->object_label_section_n); + write_l (4); + write_l (12); + section_string_offset+=13+n_digits (object_label->object_label_section_n); + code_relocations_offset+=12*n_code_relocations_in_section; + } + } + } + offset+=12*n_code_relocations; + + data_relocations_offset=0; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==DATA_CONTROL_SECTION){ + int n_data_relocations_in_section; + + n_data_relocations_in_section=object_label->object_label_n_relocations; + + if (n_data_relocations_in_section>0){ + write_l (section_string_offset); + write_l (SHT_RELA); + write_l (0); + write_l (0); + write_l (offset+data_relocations_offset); + write_l (12*n_data_relocations_in_section); + write_l (n_sections+n_code_relocation_sections+n_data_relocation_sections+2); + write_l (2+n_code_sections+object_label->object_label_section_n); + write_l (4); + write_l (12); + section_string_offset+=13+n_digits (object_label->object_label_section_n); + data_relocations_offset+=12*n_data_relocations_in_section; + } + } + } + offset+=12*n_data_relocations; + } +#else + /* offset 0x84: section header 2 */ + write_l (11); /* .text offset */ + write_l (SHT_PROGBITS); + write_l (SHF_ALLOC | SHF_EXECINSTR); + write_l (0); + write_l (offset); + write_l (code_buffer_offset); /* size */ + write_l (0); + write_l (0); + write_l (4); /* align */ + write_l (0); + offset+=code_buffer_offset; + /* offset 0xac: section header 3 */ + write_l (17); /* .data offset */ + write_l (SHT_PROGBITS); + write_l (SHF_ALLOC | SHF_WRITE); + write_l (0); + write_l (offset); + write_l (data_buffer_offset); /* size */ + write_l (0); + write_l (0); + write_l (data_section_alignment_mask+1); /* align */ + write_l (0); + offset+=data_buffer_offset; + /* offet 0xd4: section header 4 */ + write_l (23); /* .rela.text offset */ + write_l (SHT_RELA); + write_l (0); + write_l (0); + write_l (offset); + write_l (12*n_code_relocations); /* size */ + write_l (6); /* symbol table index */ + write_l (2); /* text section index */ + write_l (4); /* align */ + write_l (12); + offset+=12*n_code_relocations; + /* offset 0xfc: section header 5 */ + write_l (34); /* .rela.data offset */ + write_l (SHT_RELA); + write_l (0); + write_l (0); + write_l (offset); + write_l (12*n_data_relocations); /* size */ + write_l (6); /* symbol table index */ + write_l (3); /* data section index */ + write_l (4); /* align */ + write_l (12); + offset+=12*n_data_relocations; +#endif + + /* offset 0x124: section header 6 */ +#ifdef FUNCTION_LEVEL_LINKING + write_l (11+section_strings_size); +#else + write_l (45); /* .symtab offset */ +#endif + write_l (SHT_SYMTAB); + write_l (0); + write_l (0); + write_l (offset); + write_l (16*(n_object_labels+n_sections)); +#ifdef FUNCTION_LEVEL_LINKING + write_l (n_sections+n_code_relocation_sections+n_data_relocation_sections+3); + write_l (1+n_sections); +#else + write_l (7); /* string table index */ + write_l (3); +#endif + write_l (4); /* align */ + write_l (16); + offset+=16*(n_object_labels+n_sections); + /* offset 0x14c: section header 7 */ +#ifdef FUNCTION_LEVEL_LINKING + write_l (19+section_strings_size); +#else + write_l (53); /* .strtab offset */ +#endif + write_l (SHT_STRTAB); + write_l (0); + write_l (0); + write_l (offset); + write_l (string_table_offset); /* size */ + write_l (0); + write_l (0); + write_l (0); /* align */ + write_l (0); + + /* offset 0x174: section 1 */ + write_c (0); + write_zstring (".shstrtab"); /* 1 */ +#ifdef FUNCTION_LEVEL_LINKING + { + struct object_label *object_label; + int section_n; + char section_name[20]; + + for (section_n=0; section_n<n_code_sections; ++section_n){ + sprintf (section_name,".text.m%d",section_n); + write_zstring (section_name); + } + + for (section_n=0; section_n<n_data_sections; ++section_n){ + sprintf (section_name,".data.m%d",section_n); + write_zstring (section_name); + } + + for_l (object_label,first_object_label,next) + if (object_label->object_label_kind==CODE_CONTROL_SECTION && object_label->object_label_n_relocations>0){ + sprintf (section_name,".rela.text.m%d",object_label->object_label_section_n); + write_zstring (section_name); + } + + for_l (object_label,first_object_label,next) + if (object_label->object_label_kind==DATA_CONTROL_SECTION && object_label->object_label_n_relocations>0){ + sprintf (section_name,".rela.data.m%d",object_label->object_label_section_n); + write_zstring (section_name); + } + } +#else + write_zstring (".text"); /* 11 */ + write_zstring (".data"); /* 17 */ + write_zstring (".rela.text");/* 23 */ + write_zstring (".rela.data");/* 34 */ +#endif + write_zstring (".symtab"); /* 45 */ + write_zstring (".strtab"); /* 53 */ + /* 61 */ +#ifdef FUNCTION_LEVEL_LINKING + if (((27+section_strings_size) & 3)!=0){ + int n; + + n=4-((27+section_strings_size) & 3); + do { + write_c (0); + } while (--n); + } +#else + write_c (0); + write_c (0); + write_c (0); + /* offset 0x1b4 */ +#endif +} + +static void as_indirect_node_entry_jumps (struct label_node *label_node) +{ + LABEL *label; + + if (label_node==NULL) + return; + + label=&label_node->label_node_label; + + if (!(label->label_flags & LOCAL_LABEL) && label->label_number==0) + if (label->label_flags & NODE_ENTRY_LABEL) + as_indirect_node_entry_jump (label); + + as_indirect_node_entry_jumps (label_node->label_node_left); + as_indirect_node_entry_jumps (label_node->label_node_right); +} + +void write_code (void) +{ + struct basic_block *block; + struct call_and_jump *call_and_jump; + + first_call_and_jump=NULL; + + as_indirect_node_entry_jumps (labels); + +#ifdef FUNCTION_LEVEL_LINKING + if (first_block!=NULL && !(first_block->block_begin_module && !first_block->block_link_module)) + first_block->block_begin_module=1; +#endif + + for_l (block,first_block,block_next){ +#ifdef FUNCTION_LEVEL_LINKING + if (block->block_begin_module){ + if (block->block_link_module){ + if (code_object_label!=NULL && CURRENT_CODE_OFFSET!=code_object_label->object_label_offset && block->block_labels){ + struct relocation *new_relocation; + + new_relocation=fast_memory_allocate_type (struct relocation); + ++n_code_relocations; + + *last_code_relocation_l=new_relocation; + last_code_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + U5 (new_relocation, + relocation_label=block->block_labels->block_label_label, + relocation_offset=CURRENT_CODE_OFFSET, + relocation_object_label=code_object_label, + relocation_kind=DUMMY_BRANCH_RELOCATION, + relocation_addend=0); + + as_new_code_module(); + } + } else + as_new_code_module(); + } +#endif + + if (block->block_n_node_arguments>-100){ + if (block->block_ea_label!=NULL){ + int n_node_arguments; + extern LABEL *eval_fill_label,*eval_upd_labels[]; + + n_node_arguments=block->block_n_node_arguments; + + if (n_node_arguments<-2) + n_node_arguments=1; + + if (n_node_arguments>=0 && block->block_ea_label!=eval_fill_label){ + as_sethi (0,REGISTER_A2); + as_hi_or_lo_label (block->block_ea_label,0,HI22_RELOCATION); + + as_i_call (0); + as_branch_label (eval_upd_labels[n_node_arguments],CALL_RELOCATION); + + as_ori (REGISTER_A2,0,REGISTER_A2); + as_hi_or_lo_label (block->block_ea_label,0,LO12_RELOCATION); + } else { + as_i_call (0); + as_branch_label (block->block_ea_label,CALL_RELOCATION); + + as_nop(); + as_nop(); + } + + if (block->block_descriptor!=NULL && (block->block_n_node_arguments<0 || parallel_flag)){ + store_label_in_code_section (block->block_descriptor); + } else + as_number_of_arguments (0); + } else + if (block->block_descriptor!=NULL) + store_label_in_code_section (block->block_descriptor); + else + as_number_of_arguments (0); + + as_number_of_arguments (block->block_n_node_arguments); + } + + as_labels (block->block_labels); + + if (block->block_n_new_heap_cells>0) + as_garbage_collect_test (block); + + as_instructions (block->block_instructions); + } + + for (call_and_jump=first_call_and_jump; call_and_jump!=NULL; call_and_jump=call_and_jump->cj_next){ +#ifdef FUNCTION_LEVEL_LINKING + as_new_code_module(); +#endif + as_call_and_jump (call_and_jump); + } + +#ifndef FUNCTION_LEVEL_LINKING + as_nop(); +#endif +} + +static void relocate_code (void) +{ + struct relocation *relocation,**relocation_p; + struct object_buffer *object_buffer; + int buffer_offset; + struct label *label; + int instruction_offset; + ULONG *instruction_p; + + object_buffer=first_code_buffer; + buffer_offset=0; + + relocation_p=&first_code_relocation; + + while (relocation=*relocation_p,relocation!=NULL){ + label=relocation->relocation_label; + + switch (relocation->relocation_kind){ + case BRANCH_RELOCATION: + if (label->label_id==TEXT_LABEL_ID +#ifdef FUNCTION_LEVEL_LINKING + && label->label_object_label==relocation->relocation_object_label +#endif + ){ + instruction_offset=relocation->relocation_offset; + while (instruction_offset >= buffer_offset+BUFFER_SIZE){ + object_buffer=object_buffer->next; + buffer_offset+=BUFFER_SIZE; + } + + instruction_p=(ULONG*)((char*)(object_buffer->data)+(instruction_offset-buffer_offset)); + + *instruction_p= ((*instruction_p)& 0xffc00000) | (((label->label_offset-instruction_offset+relocation->relocation_addend)>>2) & 0x3fffff); + + *relocation_p=relocation->next; + --n_code_relocations; + continue; + } +#ifdef FUNCTION_LEVEL_LINKING + else if (label->label_id==TEXT_LABEL_ID || label->label_id==DATA_LABEL_ID){ + if (label->label_object_label==NULL) + internal_error_in_function ("relocate_code"); + + relocation->relocation_addend -= label->label_object_label->object_label_offset; + } +#endif + break; + case CALL_RELOCATION: + if (label->label_id==TEXT_LABEL_ID +#ifdef FUNCTION_LEVEL_LINKING + && label->label_object_label==relocation->relocation_object_label +#endif + ){ + instruction_offset=relocation->relocation_offset; + while (instruction_offset >= buffer_offset+BUFFER_SIZE){ + object_buffer=object_buffer->next; + buffer_offset+=BUFFER_SIZE; + } + + instruction_p=(ULONG*)((char*)(object_buffer->data)+(instruction_offset-buffer_offset)); + + *instruction_p= ((*instruction_p)& 0xc0000000) | (((label->label_offset-instruction_offset+relocation->relocation_addend)>>2) & 0x3fffffff); + + *relocation_p=relocation->next; + --n_code_relocations; + continue; + } +#ifdef FUNCTION_LEVEL_LINKING + else if (label->label_id==TEXT_LABEL_ID || label->label_id==DATA_LABEL_ID){ + if (label->label_object_label==NULL) + internal_error_in_function ("relocate_code"); + + relocation->relocation_addend -= label->label_object_label->object_label_offset; + } +#endif + break; +#ifdef FUNCTION_LEVEL_LINKING + case HI22_RELOCATION: + case LO12_RELOCATION: + case LONG_WORD_RELOCATION: + if (label->label_id==TEXT_LABEL_ID || label->label_id==DATA_LABEL_ID){ + if (label->label_object_label==NULL) + internal_error_in_function ("relocate_code"); + + relocation->relocation_addend -= label->label_object_label->object_label_offset; + } + break; + case DUMMY_BRANCH_RELOCATION: + if (label->label_id==TEXT_LABEL_ID){ + if (label->label_object_label!=relocation->relocation_object_label){ + relocation->relocation_addend -= label->label_object_label->object_label_offset; + relocation_p=&relocation->next; + } else { + *relocation_p=relocation->next; + --n_code_relocations; + } + continue; + } else { + internal_error_in_function ("relocate_code"); + *relocation_p=relocation->next; + } +#endif + } + + relocation_p=&relocation->next; + } +} + +static void relocate_data (void) +{ +#ifdef FUNCTION_LEVEL_LINKING + struct relocation *relocation; + + for_l (relocation,first_data_relocation,next){ + switch (relocation->relocation_kind){ + case LONG_WORD_RELOCATION: + { + struct label *label; + + label=relocation->relocation_label; + + if (label->label_id==TEXT_LABEL_ID || label->label_id==DATA_LABEL_ID){ + if (label->label_object_label==NULL) + internal_error_in_function ("relocate_data"); + + relocation->relocation_addend -= label->label_object_label->object_label_offset; + } + } + } + } +#endif +} + +#ifdef FUNCTION_LEVEL_LINKING +static int elf_label_number (struct label *label) +{ + int label_n; + + label_n=label->label_id; + if (label_n==TEXT_LABEL_ID){ + label_n=label->label_object_label->object_label_number; + if (label_n==0) + return 1+label->label_object_label->object_label_section_n; + else + return label_n+n_sections; + } else if (label_n==DATA_LABEL_ID){ + label_n=label->label_object_label->object_label_number; + if (label_n==0) + return 1+n_code_sections+label->label_object_label->object_label_section_n; + else + return label_n+n_sections; + } else { + if (label_n==-1) + internal_error_in_function ("elf_label_number"); + return label_n+n_sections; + } +} +#endif + +static void write_code_relocations (void) +{ + struct relocation *relocation; + + for_l (relocation,first_code_relocation,next){ + struct label *label; + + label=relocation->relocation_label; + + switch (relocation->relocation_kind){ + case BRANCH_RELOCATION: + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_SPARC_WDISP22)); +#else + write_l (ELF32_R_INFO (label->label_id,R_SPARC_WDISP22)); +#endif + write_l (relocation->relocation_addend+label->label_offset); + break; + case CALL_RELOCATION: + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_SPARC_WDISP30)); +#else + write_l (ELF32_R_INFO (label->label_id,R_SPARC_WDISP30)); +#endif + write_l (relocation->relocation_addend+label->label_offset); + break; + case HI22_RELOCATION: + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_SPARC_HI22)); +#else + write_l (ELF32_R_INFO (label->label_id,R_SPARC_HI22)); +#endif + write_l (relocation->relocation_addend+label->label_offset); + break; + case LO12_RELOCATION: + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_SPARC_LO10)); +#else + write_l (ELF32_R_INFO (label->label_id,R_SPARC_LO10)); +#endif + write_l (relocation->relocation_addend+label->label_offset); + break; + case LONG_WORD_RELOCATION: + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_SPARC_32)); +#else + write_l (ELF32_R_INFO (label->label_id,R_SPARC_32)); +#endif + write_l (relocation->relocation_addend+label->label_offset); + break; + case DUMMY_BRANCH_RELOCATION: + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_SPARC_NONE)); +#else + write_l (ELF32_R_INFO (label->label_id,R_SPARC_NONE)); +#endif + write_l (relocation->relocation_addend+label->label_offset); + break; + default: + internal_error_in_function ("write_code_relocations"); + } + } +} + +static void write_data_relocations (void) +{ + struct relocation *relocation; + + for_l (relocation,first_data_relocation,next){ + struct label *label; + + label=relocation->relocation_label; + switch (relocation->relocation_kind){ + case LONG_WORD_RELOCATION: + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_SPARC_32)); +#else + write_l (ELF32_R_INFO (label->label_id,R_SPARC_32)); +#endif + write_l (relocation->relocation_addend+label->label_offset); + break; + default: + internal_error_in_function ("write_data_relocations"); + } + } +} + +static void write_object_labels (void) +{ + struct object_label *object_label; + int code_section_number,data_section_number; +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + struct object_label *current_text_or_data_object_label; + + current_text_or_data_object_label=NULL; +#endif + + code_section_number=0; + data_section_number=0; + + write_l (0); + write_l (0); + write_l (0); + write_l (0); +# ifndef FUNCTION_LEVEL_LINKING + write_l (0); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_SECTION)); + write_c (0); + write_w (2); + + write_l (0); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_SECTION)); + write_c (0); + write_w (3); +#else + { + int section_n; + + for (section_n=0; section_n<n_code_sections; ++section_n){ + write_l (0); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_SECTION)); + write_c (0); + write_w (2+section_n); + } + + for (section_n=0; section_n<n_data_sections; ++section_n){ + write_l (0); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_SECTION)); + write_c (0); + write_w (2+n_code_sections+section_n); + } + } +# endif + + for_l (object_label,first_object_label,next){ + switch (object_label->object_label_kind){ + case CODE_CONTROL_SECTION: + break; + case DATA_CONTROL_SECTION: +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + current_text_or_data_object_label=object_label; +#endif + break; + case IMPORTED_LABEL: + write_l (object_label->object_label_string_offset); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_GLOBAL,STT_NOTYPE)); + write_c (0); + write_w (0); + break; + case EXPORTED_CODE_LABEL: + { + struct label *label; + + label=object_label->object_label_label; + + write_l (object_label->object_label_string_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (label->label_offset - label->label_object_label->object_label_offset); +#else + write_l (label->label_offset); +#endif + write_l (0); + write_c (ELF32_ST_INFO (STB_GLOBAL,STT_FUNC)); + write_c (0); +#ifdef FUNCTION_LEVEL_LINKING + write_w (2+label->label_object_label->object_label_section_n); +#else + write_w (2); +#endif + break; + } + case EXPORTED_DATA_LABEL: + { + struct label *label; + + label=object_label->object_label_label; + + write_l (object_label->object_label_string_offset); +#ifdef FUNCTION_LEVEL_LINKING +# ifdef RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL + write_l (label->label_offset - current_text_or_data_object_label->object_label_offset); +# else + write_l (label->label_offset - label->label_object_label->object_label_offset); +#endif +#else + write_l (label->label_offset); +#endif + write_l (0); + write_c (ELF32_ST_INFO (STB_GLOBAL,STT_OBJECT)); + write_c (0); +#ifdef FUNCTION_LEVEL_LINKING + write_w (2+n_code_sections+label->label_object_label->object_label_section_n); +#else + write_w (3); +#endif + break; + } + default: + internal_error_in_function ("write_object_labels"); + } + } +} + +static void write_string_table (void) +{ + struct object_label *object_label; + + write_c (0); + + for_l (object_label,first_object_label,next){ + int object_label_kind; + + object_label_kind=object_label->object_label_kind; + + if ((object_label_kind==IMPORTED_LABEL || object_label_kind==EXPORTED_CODE_LABEL || object_label_kind==EXPORTED_DATA_LABEL) + && object_label->object_label_string_offset!=0) + { + char *s,c; + + s=object_label->object_label_label->label_name; + + do { + c=*s++; + write_c (c); + } while (c!='\0'); + } + } +} + +void assemble_code (void) +{ + as_import_labels (labels); + + write_code(); + + flush_data_buffer(); + flush_code_buffer(); + +#ifndef FUNCTION_LEVEL_LINKING + code_object_label->object_label_length=code_buffer_offset; + data_object_label->object_label_length=data_buffer_offset; +#endif + + relocate_code(); + relocate_data(); + + write_file_header_and_section_headers(); + + write_buffers_and_release_memory (&first_code_buffer); + write_buffers_and_release_memory (&first_data_buffer); + + write_code_relocations(); + write_data_relocations(); + + write_object_labels(); + + write_string_table(); +} |