/* File: cgarmas.c Author: John van Groningen Machine: ARM */ #define RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL #include #include #include #ifdef LINUX_ELF # define ELF #endif #if defined (_WINDOWS_) || defined (ELF) # define FUNCTION_LEVEL_LINKING #endif #include "cgport.h" #include "cgrconst.h" #include "cgtypes.h" #include "cg.h" #include "cgiconst.h" #include "cgcode.h" #include "cgarmas.h" #include "cginstructions.h" #ifdef ELF # include # ifdef ANDROID # include # ifndef EF_ARM_EABI_VER5 # define EF_ARM_EABI_VER5 0x05000000 # endif # endif # ifndef ELF32_ST_INFO # define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) # endif # ifndef ELF32_R_INFO # define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) # endif # ifndef R_ARM_LDR_PC_G0 /* R_ARM_PC13 */ # define R_ARM_LDR_PC_G0 4 # endif # ifndef R_ARM_CALL # define R_ARM_CALL 28 # endif # ifndef R_ARM_JUMP24 # define R_ARM_JUMP24 29 # endif # ifndef R_ARM_LDC_PC_G0 # define R_ARM_LDC_PC_G0 67 # endif #endif #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 #ifdef FUNCTION_LEVEL_LINKING # define TEXT_LABEL_ID (-2) # define DATA_LABEL_ID (-3) #else # ifdef ELF # define TEXT_LABEL_ID 1 # define DATA_LABEL_ID 2 # else # define TEXT_LABEL_ID 0 # define DATA_LABEL_ID 2 # endif #endif #define IO_BUFFER_SIZE 8192 #define BUFFER_SIZE 4096 #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 static struct object_label *first_object_label,**last_object_label_l; struct object_buffer { struct object_buffer *next; int size; unsigned char data [BUFFER_SIZE]; }; static struct object_buffer *first_code_buffer,*current_code_buffer; static int code_buffer_free,code_buffer_offset; static unsigned char *code_buffer_p; static struct object_buffer *first_data_buffer,*current_data_buffer; static int data_buffer_free,data_buffer_offset; static unsigned char *data_buffer_p; static void initialize_buffers (void) { struct object_buffer *new_code_buffer,*new_data_buffer; new_code_buffer=memory_allocate (sizeof (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=(void*)new_code_buffer->data; new_data_buffer=memory_allocate (sizeof (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=new_data_buffer->data; } static FILE *output_file; static void write_c (int c) { fputc (c,output_file); } static void write_w (int c) { fputc (c,output_file); fputc (c>>8,output_file); } static void write_l (int c) { fputc (c,output_file); fputc (c>>8,output_file); fputc (c>>16,output_file); fputc (c>>24,output_file); } #define LONG_WORD_RELOCATION 0 #define CALL_RELOCATION 1 #define BRANCH_RELOCATION 2 #define JUMP_RELOCATION 3 #define DUMMY_BRANCH_RELOCATION 5 #define LDR_OFFSET_RELOCATION 6 /* R_ARM_LDR_PC_G0 */ #define VLDR_OFFSET_RELOCATION 7 /* R_ARM_LDC_PC_G0 */ struct relocation { struct relocation * next; unsigned long relocation_offset; union { struct { WORD s_align1; WORD s_align2; } u_s; struct label * u_label; } relocation_u; #ifdef FUNCTION_LEVEL_LINKING struct object_label * relocation_object_label; #endif short relocation_kind; }; #define relocation_label relocation_u.u_label #define relocation_align1 relocation_u.u_s.s_align1 #define relocation_align2 relocation_u.u_s.s_align2 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; } static struct relocation *first_code_relocation,**last_code_relocation_l; static struct relocation *first_data_relocation,**last_data_relocation_l; static int n_code_relocations,n_data_relocations; static int n_object_labels; static unsigned long string_table_offset; static struct object_label *code_object_label,*data_object_label; #ifdef FUNCTION_LEVEL_LINKING static int n_code_sections,n_data_sections; #endif struct call_and_jump { struct call_and_jump *cj_next; struct label *cj_call_label; struct label cj_label; struct label cj_jump; }; static struct call_and_jump *first_call_and_jump,*last_call_and_jump; void initialize_assembler (FILE *output_file_d) { output_file=output_file_d; #ifdef ELF n_object_labels=1; #else n_object_labels=0; #endif setvbuf (output_file,NULL,_IOFBF,IO_BUFFER_SIZE); 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; first_call_and_jump=NULL; #ifdef ELF string_table_offset=13; #else string_table_offset=4; #endif 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); # ifdef ELF ++n_object_labels; # else n_object_labels+=2; # endif *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); # ifdef ELF ++n_object_labels; # else n_object_labels+=2; # endif *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 } #define MAX_LITERAL_INSTRUCTION_OFFSET 4092 static unsigned long literal_table_at_offset; static unsigned char *literal_table_at_buffer_p; static void write_branch_and_literals (void); static void store_c (int c) { if (code_buffer_free>0){ --code_buffer_free; *code_buffer_p++=c; } else { struct object_buffer *new_buffer; current_code_buffer->size=BUFFER_SIZE; new_buffer=memory_allocate (sizeof (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-1; code_buffer_p=new_buffer->data; *code_buffer_p++=c; if (literal_table_at_offset-(unsigned long)code_buffer_offset <= (unsigned long) BUFFER_SIZE) literal_table_at_buffer_p = current_code_buffer->data + (literal_table_at_offset-(unsigned long)code_buffer_offset); } } static void store_l (register ULONG i) { if (code_buffer_p>=literal_table_at_buffer_p) write_branch_and_literals(); store_c (i); store_c (i>>8); store_c (i>>16); store_c (i>>24); } void store_long_word_in_data_section (ULONG c) { if (data_buffer_free>=4){ data_buffer_free-=4; *(ULONG*)data_buffer_p=c; data_buffer_p+=4; } else { struct object_buffer *new_buffer; current_data_buffer->size=BUFFER_SIZE; new_buffer=memory_allocate (sizeof (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=(void*)new_buffer->data; *(ULONG*)data_buffer_p=c; data_buffer_p+=4; } } void store_2_words_in_data_section (UWORD w1,UWORD w2) { store_long_word_in_data_section (((UWORD)w1) | (w2<<16)); } 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; } 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=0; while (length>0){ d |= string_p[0]<=4){ store_long_word_in_data_section (*(ULONG*)string_p); string_p+=4; length-=4; } d=0; shift=0; while (length>0){ d |= string_p[0]<data)) #define CURRENT_DATA_OFFSET (data_buffer_offset+(data_buffer_p-current_data_buffer->data)) static void store_label_in_code_section (struct label *label) { 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=LONG_WORD_RELOCATION; } struct literal_entry { LABEL * le_label; int le_offset; DOUBLE * le_r_p; struct label le_load_instruction_label; struct literal_entry * le_next; }; struct literal_entry *first_literal_entry,**literal_entry_l; static void write_literals (void) { struct literal_entry *literal_entry; literal_entry=first_literal_entry; if (literal_entry!=NULL){ for (; literal_entry!=NULL; literal_entry=literal_entry->le_next){ literal_entry->le_load_instruction_label.label_flags=0; literal_entry->le_load_instruction_label.label_id=TEXT_LABEL_ID; #ifdef FUNCTION_LEVEL_LINKING literal_entry->le_load_instruction_label.label_object_label=code_object_label; #endif literal_entry->le_load_instruction_label.label_offset=CURRENT_CODE_OFFSET; if (literal_entry->le_label){ literal_entry->le_label->label_flags &= ~HAS_LITERAL_ENTRY; store_l (literal_entry->le_offset); store_label_in_code_section (literal_entry->le_label); } else { if (literal_entry->le_r_p==NULL){ store_l (literal_entry->le_offset); } else { // to do: align 8 store_l (((LONG*)(literal_entry->le_r_p))[0]); store_l (((LONG*)(literal_entry->le_r_p))[1]); } } } literal_entry_l=&first_literal_entry; first_literal_entry=NULL; } literal_table_at_offset = 0ul-1ul; literal_table_at_buffer_p = (unsigned char*)0ul-1ul; } static void as_branch_label (struct label *label,int relocation_kind) { struct relocation *new_relocation; new_relocation=fast_memory_allocate_type (struct relocation); *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; } static void write_branch_and_literals (void) { LABEL *new_label; literal_table_at_offset = 0ul-1ul; literal_table_at_buffer_p = (unsigned char*)0ul-1ul; new_label=allocate_memory_from_heap (sizeof (struct label)); store_l (0xea000000); /* b */ as_branch_label (new_label,JUMP_RELOCATION); write_literals(); new_label->label_flags=0; new_label->label_id=TEXT_LABEL_ID; #ifdef FUNCTION_LEVEL_LINKING new_label->label_object_label=code_object_label; #endif new_label->label_offset=CURRENT_CODE_OFFSET; } static void as_literal_label (struct label *label,int relocation_kind) { struct relocation *new_relocation; unsigned long current_code_offset; new_relocation=fast_memory_allocate_type (struct relocation); *last_code_relocation_l=new_relocation; last_code_relocation_l=&new_relocation->next; new_relocation->next=NULL; current_code_offset = CURRENT_CODE_OFFSET-4; if (current_code_offset+MAX_LITERAL_INSTRUCTION_OFFSET < literal_table_at_offset){ literal_table_at_offset = current_code_offset+MAX_LITERAL_INSTRUCTION_OFFSET; if (literal_table_at_offset-(unsigned long)code_buffer_offset <= (unsigned long) BUFFER_SIZE) literal_table_at_buffer_p = current_code_buffer->data + (literal_table_at_offset-(unsigned long)code_buffer_offset); } new_relocation->relocation_label=label; new_relocation->relocation_offset=current_code_offset; #ifdef FUNCTION_LEVEL_LINKING new_relocation->relocation_object_label=code_object_label; #endif new_relocation->relocation_kind=relocation_kind; } static void as_literal_entry (LABEL *label,int offset) { struct literal_entry *new_literal_entry; if (label!=NULL && label->label_flags & HAS_LITERAL_ENTRY && label->label_literal_entry->le_offset==offset) new_literal_entry=label->label_literal_entry; else { new_literal_entry=allocate_memory_from_heap (sizeof (struct literal_entry)); new_literal_entry->le_label=label; new_literal_entry->le_offset=offset; new_literal_entry->le_r_p=NULL; *literal_entry_l=new_literal_entry; literal_entry_l=&new_literal_entry->le_next; new_literal_entry->le_next=NULL; if (label!=NULL){ label->label_flags |= HAS_LITERAL_ENTRY; label->label_literal_entry=new_literal_entry; } } as_literal_label (&new_literal_entry->le_load_instruction_label,LDR_OFFSET_RELOCATION); } static void as_float_load_int_literal_entry (int offset) { struct literal_entry *new_literal_entry; new_literal_entry=allocate_memory_from_heap (sizeof (struct literal_entry)); new_literal_entry->le_label=NULL; new_literal_entry->le_offset=offset; new_literal_entry->le_r_p=NULL; *literal_entry_l=new_literal_entry; literal_entry_l=&new_literal_entry->le_next; new_literal_entry->le_next=NULL; as_literal_label (&new_literal_entry->le_load_instruction_label,VLDR_OFFSET_RELOCATION); } static void as_float_literal_entry (DOUBLE *r_p) { struct literal_entry *new_literal_entry; new_literal_entry=allocate_memory_from_heap (sizeof (struct literal_entry)); new_literal_entry->le_r_p=r_p; new_literal_entry->le_label=NULL; new_literal_entry->le_offset=0; *literal_entry_l=new_literal_entry; literal_entry_l=&new_literal_entry->le_next; new_literal_entry->le_next=NULL; as_literal_label (&new_literal_entry->le_load_instruction_label,VLDR_OFFSET_RELOCATION); } #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; # ifdef ELF data_section_label_number=0; # else data_section_label_number=n_object_labels; n_object_labels+=2; # endif 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; # ifdef ELF code_section_label_number=0; # else code_section_label_number=n_object_labels; n_object_labels+=2; # endif 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 (offset); 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; } #define reg_num(r) (real_reg_num[(r)+7]) static unsigned char real_reg_num [16] = { 13, 10, 9, 11, 8, 7, 6, 4, 3, 2, 1, 0, 5, 12, 14, 15 }; #define ESP (-6) #define EBP (-3) #define EAX 0 #define REGISTER_PC 8 #define REGISTER_R5 5 #define REGISTER_S0 6 #define REGISTER_S1 7 static int immediate_shift (unsigned int i) { if ((i & ~0xff)==0) return 0; if ((i & ~0x3fc)==0) return 2; if ((i & ~0xff0)==0) return 4; if ((i & ~0x3fc0)==0) return 6; if ((i & ~0xff00)==0) return 8; if ((i & ~0x3fc00)==0) return 10; if ((i & ~0xff000)==0) return 12; if ((i & ~0x3fc0000)==0) return 14; if ((i & ~0xff0000)==0) return 16; if ((i & ~0x3fc0000)==0) return 18; if ((i & ~0xff00000)==0) return 20; if ((i & ~0x3fc00000)==0) return 22; if ((i & ~0xff000000)==0) return 24; if ((i & ~0xfc000003)==0) return 26; if ((i & ~0xf000000f)==0) return 28; if ((i & ~0xc000003f)==0) return 30; return -1; } static void store_l_is (int i_code,int i,int shift) { if (shift==0){ i_code |= i & 255; } else { i_code |= (((32-shift)>>1)<<8); i_code |= (unsigned int)i >> (unsigned int)shift; if (shift>=24) i_code |= ((unsigned int)i << (unsigned int)(32-shift)) & 255; } store_l (i_code); } static void as_move_i_r (int i,int reg1) { int shift; shift = immediate_shift (i); if (shift>=0) store_l_is (0xe3a00000 | (reg_num (reg1)<<12),i,shift); /* mov rd,#i<=0) store_l_is (0xe3e00000 | (reg_num (reg1)<<12),~i,shift); /* mvn rd,#i<>=2; if (offset<0) i_code |= (-offset) & 0xff; else i_code |= (1<<23) | (offset & 0xff); store_l (i_code); } static void as_vldr_s_id (int sreg,int offset,int sa_reg) { int i_code; i_code = 0xed100a00 | (reg_num (sa_reg)<<16) | (sreg<<12); offset>>=2; if (offset<0) i_code |= (-offset) & 0xff; else i_code |= (1<<23) | (offset & 0xff); store_l (i_code); } static void as_vstr_r_id (int dreg,int offset,int da_reg) { int i_code; i_code = 0xed000b00 | (reg_num (da_reg)<<16) | (dreg<<12); offset>>=2; if (offset<0) i_code |= (-offset) & 0xff; else i_code |= (1<<23) | (offset & 0xff); store_l (i_code); } static void as_vstr_s_id (int sreg,int offset,int da_reg) { int i_code; i_code = 0xed000a00 | (reg_num (da_reg)<<16) | (sreg<<12); offset>>=2; if (offset<0) i_code |= (-offset) & 0xff; else i_code |= (1<<23) | (offset & 0xff); store_l (i_code); } #define ARM_OP_AND 0 #define ARM_OP_EOR 1 #define ARM_OP_SUB 2 #define ARM_OP_RSB 3 #define ARM_OP_ADD 4 #define ARM_OP_ADC 5 #define ARM_OP_SBC 6 #define ARM_OP_CMP 10 #define ARM_OP_CMN 11 #define ARM_OP_ORR 12 #define ARM_OP_BIC 14 #define ARM_OP_MVN 15 static void as_op_r_r_r (int op,int reg_m,int reg_n,int reg_d) { store_l (0xe0000000 | (op<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | reg_num(reg_m)); } static void as_x_op_r_r_r (int x_op,int reg_m,int reg_n,int reg_d) { store_l (0xe0000000 | (x_op<<20) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | reg_num(reg_m)); } static void as_op_is_r_r (int op,int i,int shift,int s_reg,int d_reg) { store_l_is (0xe2000000 | (op<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); } static void as_x_op_is_r_r (int x_op,int i,int shift,int s_reg,int d_reg) { store_l_is (0xe2000000 | (x_op<<20) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); } static void as_add_r_r_r (int reg_m,int reg_n,int reg_d) { store_l (0xe0000000 | (ARM_OP_ADD<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | reg_num(reg_m)); } static void as_add_r_lsl_r_r (int reg_m,int lsl_m,int reg_n,int reg_d) { store_l (0xe0000000 | (ARM_OP_ADD<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsl_m<<7) | reg_num(reg_m)); } static void as_add_r_lsr_r_r (int reg_m,int lsr_m,int reg_n,int reg_d) { store_l (0xe0000020 | (ARM_OP_ADD<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsr_m<<7) | reg_num(reg_m)); } static void as_add_r_asr_r_r (int reg_m,int asr_m,int reg_n,int reg_d) { store_l (0xe0000040 | (ARM_OP_ADD<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (asr_m<<7) | reg_num(reg_m)); } static void as_add_is_r_r (int i,int shift,int s_reg,int d_reg) { store_l_is (0xe2000000 | (ARM_OP_ADD<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); } static void as_add_cc_is_r_r (int cc,int i,int shift,int s_reg,int d_reg) { store_l_is (0x02000000 | (cc<<28) | (ARM_OP_ADD<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); } static void as_sub_r_r_r (int reg_m,int reg_n,int reg_d) { store_l (0xe0000000 | (ARM_OP_SUB<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | reg_num(reg_m)); } static void as_sub_r_lsl_r_r (int reg_m,int lsl_m,int reg_n,int reg_d) { store_l (0xe0000000 | (ARM_OP_SUB<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsl_m<<7) | reg_num(reg_m)); } static void as_sub_r_lsr_r_r (int reg_m,int lsr_m,int reg_n,int reg_d) { store_l (0xe0000020 | (ARM_OP_SUB<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsr_m<<7) | reg_num(reg_m)); } static void as_sub_r_asr_r_r (int reg_m,int asr_m,int reg_n,int reg_d) { store_l (0xe0000040 | (ARM_OP_SUB<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (asr_m<<7) | reg_num(reg_m)); } static void as_sub_is_r_r (int i,int shift,int s_reg,int d_reg) { store_l_is (0xe2000000 | (ARM_OP_SUB<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); } static void as_sub_cc_is_r_r (int cc,int i,int shift,int s_reg,int d_reg) { store_l_is (0x02000000 | (cc<<28) | (ARM_OP_SUB<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); } static void as_rsb_is_r_r (int i,int shift,int s_reg,int d_reg) { store_l_is (0xe2000000 | (ARM_OP_RSB<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); } static void as_cmp_r_r (int reg_m,int reg_n) { store_l (0xe0100000 | (ARM_OP_CMP<<21) | (reg_num (reg_n)<<16) | reg_num(reg_m)); } static void as_cmp_is_r (int i,int shift,int s_reg) { store_l_is (0xe2100000 | (ARM_OP_CMP<<21) | (reg_num (s_reg)<<16),i,shift); } static void as_cmn_is_r (int i,int shift,int s_reg) { store_l_is (0xe2100000 | (ARM_OP_CMN<<21) | (reg_num (s_reg)<<16),i,shift); } static void as_and_is_r_r (int i,int shift,int s_reg,int d_reg) { store_l_is (0xe2000000 | (ARM_OP_AND<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); } static void as_and_r_lsr_r_r (int reg_m,int lsr_m,int reg_n,int reg_d) { store_l (0xe0000020 | (ARM_OP_AND<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsr_m<<7) | reg_num(reg_m)); } static void as_mla_r_r_r_r (int n_reg,int m_reg,int a_reg,int d_reg) { store_l (0xe0200090 | (reg_num (d_reg)<<16) | (reg_num (a_reg)<<12) | (reg_num (m_reg)<<8) | reg_num (n_reg)); } static void as_mls_r_r_r_r (int n_reg,int m_reg,int a_reg,int d_reg) { store_l (0xe0600090 | (reg_num (d_reg)<<16) | (reg_num (a_reg)<<12) | (reg_num (m_reg)<<8) | reg_num (n_reg)); } static void as_smmul_r_r_r (int n_reg,int m_reg,int d_reg) { store_l (0xe750f010 | (reg_num (d_reg)<<16) | (reg_num (m_reg)<<8) | reg_num (n_reg)); } static void as_smmla_r_r_r (int n_reg,int m_reg,int a_reg,int d_reg) { store_l (0xe7500010 | (reg_num (d_reg)<<16) | (reg_num (a_reg)<<12) | (reg_num (m_reg)<<8) | reg_num (n_reg)); } static void as_smmls_r_r_r (int n_reg,int m_reg,int a_reg,int d_reg) { store_l (0xe75000d0 | (reg_num (d_reg)<<16) | (reg_num (a_reg)<<12) | (reg_num (m_reg)<<8) | reg_num (n_reg)); } static void as_load_indexed_reg (int offset,struct index_registers *index_registers,int reg) { int reg1,reg2; reg1=index_registers->a_reg.r; reg2=index_registers->d_reg.r; if ((offset & -4)!=0){ int shift; shift = immediate_shift (offset>>2); if (shift>=0){ as_add_is_r_r (offset>>2,shift,reg1,REGISTER_S0); as_ldr_ix_r (REGISTER_S0,reg2,offset & 3,reg); return; } } else { as_ldr_ix_r (reg1,reg2,offset & 3,reg); return; } internal_error_in_function ("as_load_indexed_reg"); } static void as_store_b_reg_indexed (int reg,int offset,struct index_registers *index_registers,int scratch_reg) { int reg1,reg2; reg1=index_registers->a_reg.r; reg2=index_registers->d_reg.r; if ((offset & -4)!=0){ int shift; shift = immediate_shift (offset>>2); if (shift>=0){ as_add_is_r_r (offset>>2,shift,reg1,scratch_reg); as_strb_r_ix (reg,scratch_reg,reg2,offset & 3); return; } } else { as_strb_r_ix (reg,reg1,reg2,offset & 3); return; } internal_error_in_function ("as_store_b_reg_indexed"); } static void as_load_parameter_to_scratch_register (struct parameter *parameter_p) { switch (parameter_p->parameter_type){ case P_INDIRECT: as_ldr_id_r (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,REGISTER_S0); break; case P_INDEXED: as_load_indexed_reg (parameter_p->parameter_offset,parameter_p->parameter_data.ir,REGISTER_S0); break; case P_POST_INCREMENT: as_ldr_id_r_post_add (4,parameter_p->parameter_data.reg.r,REGISTER_S0); break; case P_INDIRECT_WITH_UPDATE: as_ldr_id_r_update (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,REGISTER_S0); break; case P_INDIRECT_POST_ADD: as_ldr_id_r_post_add (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,REGISTER_S0); break; default: internal_error_in_function ("as_load_parameter_to_scratch_register"); return; } } static void as_move_parameter_reg (struct parameter *parameter_p,int reg) { switch (parameter_p->parameter_type){ case P_REGISTER: as_mov_r_r (parameter_p->parameter_data.reg.r,reg); return; case P_DESCRIPTOR_NUMBER: as_move_d_r (parameter_p->parameter_data.l,parameter_p->parameter_offset,reg); return; case P_IMMEDIATE: as_move_i_r (parameter_p->parameter_data.i,reg); return; case P_INDIRECT: as_ldr_id_r (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,reg); return; case P_INDEXED: as_load_indexed_reg (parameter_p->parameter_offset,parameter_p->parameter_data.ir,reg); return; case P_POST_INCREMENT: as_ldr_id_r_post_add (4,parameter_p->parameter_data.reg.r,reg); return; case P_INDIRECT_WITH_UPDATE: as_ldr_id_r_update (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,reg); return; case P_INDIRECT_POST_ADD: as_ldr_id_r_post_add (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,reg); return; case P_LABEL: as_move_l_r (parameter_p->parameter_data.l,reg); as_ldr_id_r (0,reg,reg); return; default: internal_error_in_function ("as_move_parameter_reg"); return; } } static void as_move_instruction (struct instruction *instruction) { if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ as_move_parameter_reg (&instruction->instruction_parameters[0], instruction->instruction_parameters[1].parameter_data.reg.r); return; } else if (instruction->instruction_parameters[0].parameter_type==P_REGISTER){ switch (instruction->instruction_parameters[1].parameter_type){ case P_INDIRECT: as_str_r_id (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_PRE_DECREMENT: as_str_r_id_update (instruction->instruction_parameters[0].parameter_data.reg.r, -4,instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_INDEXED: { int reg_0,reg_s,reg1,reg2,offset; reg_0 = instruction->instruction_parameters[0].parameter_data.reg.r; reg_s = REGISTER_S0; offset=instruction->instruction_parameters[1].parameter_offset; reg1=instruction->instruction_parameters[1].parameter_data.ir->a_reg.r; reg2=instruction->instruction_parameters[1].parameter_data.ir->d_reg.r; if ((offset & -4)!=0){ int shift; shift = immediate_shift (offset>>2); if (shift>=0){ as_add_is_r_r (offset>>2,shift,reg1,reg_s); as_str_r_ix (reg_0,reg_s,reg2,offset & 3); return; } } else { as_str_r_ix (reg_0,reg1,reg2,offset & 3); return; } internal_error_in_function ("as_move_instruction"); return; } case P_POST_INCREMENT: as_ldr_id_r_post_add (4,instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_INDIRECT_WITH_UPDATE: as_str_r_id_update (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_INDIRECT_POST_ADD: as_str_r_id_post_add (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_LABEL: as_move_l_r (instruction->instruction_parameters[1].parameter_data.l,REGISTER_S0); as_str_r_id (instruction->instruction_parameters[0].parameter_data.reg.r,0,REGISTER_S0); return; } } else { switch (instruction->instruction_parameters[0].parameter_type){ case P_INDIRECT: as_ldr_id_r (instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); break; case P_INDEXED: as_load_indexed_reg (instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.ir,REGISTER_S0); break; case P_DESCRIPTOR_NUMBER: as_move_d_r (instruction->instruction_parameters[0].parameter_data.l, instruction->instruction_parameters[0].parameter_offset,REGISTER_S0); break; case P_IMMEDIATE: as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,REGISTER_S0); break; case P_POST_INCREMENT: as_ldr_id_r_post_add (4,instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); break; case P_INDIRECT_WITH_UPDATE: as_ldr_id_r_update (instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); break; case P_INDIRECT_POST_ADD: as_ldr_id_r_post_add (instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); break; default: internal_error_in_function ("as_move_instruction"); return; } switch (instruction->instruction_parameters[1].parameter_type){ case P_INDIRECT: as_str_r_id (REGISTER_S0, instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_PRE_DECREMENT: as_str_r_id_update (REGISTER_S0,-4,instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_INDEXED: { int reg_0,reg_s,reg1,reg2,offset; reg_0 = REGISTER_S0; reg_s = REGISTER_S1; offset=instruction->instruction_parameters[1].parameter_offset; reg1=instruction->instruction_parameters[1].parameter_data.ir->a_reg.r; reg2=instruction->instruction_parameters[1].parameter_data.ir->d_reg.r; if ((offset & -4)!=0){ int shift; shift = immediate_shift (offset>>2); if (shift>=0){ as_add_is_r_r (offset>>2,shift,reg1,reg_s); as_str_r_ix (reg_0,reg_s,reg2,offset & 3); return; } } else { as_str_r_ix (reg_0,reg1,reg2,offset & 3); return; } internal_error_in_function ("as_move_instruction"); return; } case P_INDIRECT_WITH_UPDATE: as_str_r_id_update (REGISTER_S0,instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_INDIRECT_POST_ADD: as_str_r_id_post_add (REGISTER_S0,instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_LABEL: as_move_l_r (instruction->instruction_parameters[1].parameter_data.l,REGISTER_S1); as_str_r_id (REGISTER_S0,0,REGISTER_S1); return; } } internal_error_in_function ("as_move_instruction"); } static void as_moveb_instruction (struct instruction *instruction) { switch (instruction->instruction_parameters[1].parameter_type){ case P_REGISTER: { int reg; reg=instruction->instruction_parameters[1].parameter_data.reg.r; switch (instruction->instruction_parameters[0].parameter_type){ case P_IMMEDIATE: as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,reg); return; case P_INDIRECT: as_ldrb_id_r (instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r,reg); return; case P_INDEXED: { int offset,reg1,reg2; reg1=instruction->instruction_parameters[0].parameter_data.ir->a_reg.r; reg2=instruction->instruction_parameters[0].parameter_data.ir->d_reg.r; offset=instruction->instruction_parameters[0].parameter_offset; if ((offset & -4)!=0){ int shift; shift = immediate_shift (offset>>2); if (shift>=0){ as_add_is_r_r (offset>>2,shift,reg1,REGISTER_S0); as_ldrb_ix_r (REGISTER_S0,reg2,offset & 3,reg); return; } else { shift = immediate_shift (-(offset>>2)); if (shift>=0){ as_sub_is_r_r (-(offset>>2),shift,reg1,REGISTER_S0); as_ldrb_ix_r (REGISTER_S0,reg2,offset & 3,reg); return; } } } else { as_ldrb_ix_r (reg1,reg2,offset & 3,reg); return; } internal_error_in_function ("as_moveb_instruction"); return; } } break; } case P_INDIRECT: switch (instruction->instruction_parameters[0].parameter_type){ case P_IMMEDIATE: as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,REGISTER_S0); as_strb_r_id (REGISTER_S0, instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_REGISTER: as_strb_r_id (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; } break; case P_INDEXED: switch (instruction->instruction_parameters[0].parameter_type){ case P_IMMEDIATE: as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,REGISTER_S0); as_store_b_reg_indexed (REGISTER_S0, instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.ir,REGISTER_S1); return; case P_REGISTER: as_store_b_reg_indexed (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.ir,REGISTER_S0); return; } break; } internal_error_in_function ("as_moveb_instruction"); } static void as_movew_instruction (struct instruction *instruction) { switch (instruction->instruction_parameters[1].parameter_type){ case P_REGISTER: { int reg; reg=instruction->instruction_parameters[1].parameter_data.reg.r; switch (instruction->instruction_parameters[0].parameter_type){ case P_INDIRECT: as_ldrsh_id_r (instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r,reg); return; } break; } } internal_error_in_function ("as_movew_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_move_d_r (instruction->instruction_parameters[0].parameter_data.l, instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_INDIRECT: { int shift,i; i = instruction->instruction_parameters[0].parameter_offset; shift = immediate_shift (i); if (shift>=0){ as_add_is_r_r (i,shift, instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } else { shift = immediate_shift (-i); if (shift>=0){ as_sub_is_r_r (-i,shift, instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } } break; } case P_INDEXED: if (instruction->instruction_parameters[0].parameter_offset==0){ as_add_r_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, instruction->instruction_parameters[0].parameter_data.ir->a_reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } } } internal_error_in_function ("as_lea_instruction"); } static void as_movem_instruction (struct instruction *instruction) { int n_regs; unsigned short register_list; n_regs = instruction->instruction_arity-1; register_list = 0u; if (instruction->instruction_parameters[0].parameter_type!=P_REGISTER){ int s_reg,n; s_reg = instruction->instruction_parameters[0].parameter_data.reg.r; for (n=0; ninstruction_parameters[1+n].parameter_data.reg.r); if (instruction->instruction_parameters[0].parameter_type==P_PRE_DECREMENT){ store_l (0xe9300000 | (reg_num (s_reg)<<16) | register_list); /* ldmdb */ return; } else if (instruction->instruction_parameters[0].parameter_type==P_POST_INCREMENT){ store_l (0xe8b00000 | (reg_num (s_reg)<<16) | register_list); /* ldmia */ return; } } else { int d_reg,n; d_reg = instruction->instruction_parameters[n_regs].parameter_data.reg.r; for (n=0; ninstruction_parameters[n].parameter_data.reg.r); if (instruction->instruction_parameters[n_regs].parameter_type==P_PRE_DECREMENT){ store_l (0xe9200000 | (reg_num (d_reg)<<16) | register_list); /* stmdb */ return; } else if (instruction->instruction_parameters[n_regs].parameter_type==P_POST_INCREMENT){ store_l (0xe8a00000 | (reg_num (d_reg)<<16) | register_list); /* stmia */ return; } } internal_error_in_function ("as_movem_instruction"); } static void as_add_instruction (struct instruction *instruction) { switch (instruction->instruction_parameters[0].parameter_type){ case P_REGISTER: as_add_r_r_r (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_IMMEDIATE: { int shift,i; i = instruction->instruction_parameters[0].parameter_data.i; shift = immediate_shift (i); if (shift>=0){ as_add_is_r_r (i,shift, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } shift = immediate_shift (-i); if (shift>=0){ as_sub_is_r_r (-i,shift, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ as_literal_entry (NULL,i); break; } default: as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); } as_add_r_r_r (REGISTER_S0,instruction->instruction_parameters[1].parameter_data.reg.r, 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_r_r_r (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_IMMEDIATE: { int shift,i; i = instruction->instruction_parameters[0].parameter_data.i; shift = immediate_shift (i); if (shift>=0){ as_sub_is_r_r (i,shift, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } shift = immediate_shift (-i); if (shift>=0){ as_add_is_r_r (-i,shift, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ as_literal_entry (NULL,i); break; } default: as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); } as_sub_r_r_r (REGISTER_S0,instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); } static void as_addi_instruction (struct instruction *instruction) { int s_reg,d_reg,i,shift; s_reg = instruction->instruction_parameters[0].parameter_data.reg.r; d_reg = instruction->instruction_parameters[1].parameter_data.reg.r; i = instruction->instruction_parameters[2].parameter_data.i; shift = immediate_shift (i); if (shift>=0){ as_add_is_r_r (i,shift,s_reg,d_reg); return; } shift = immediate_shift (-i); if (shift>=0){ as_sub_is_r_r (-i,shift,s_reg,d_reg); return; } store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ as_literal_entry (NULL,i); as_add_r_r_r (REGISTER_S0,s_reg,d_reg); } static void as_add_or_sub_x_instruction (struct instruction *instruction,int arm_x_op,int arm_x_op_r) { switch (instruction->instruction_parameters[0].parameter_type){ case P_REGISTER: as_x_op_r_r_r (arm_x_op,instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_IMMEDIATE: { int shift,i; i = instruction->instruction_parameters[0].parameter_data.i; shift = immediate_shift (i); if (shift>=0){ as_x_op_is_r_r (arm_x_op,i,shift, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } shift = immediate_shift (-i); if (shift>=0){ as_x_op_is_r_r (arm_x_op_r,-i,shift, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ as_literal_entry (NULL,i); break; } default: as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); } as_x_op_r_r_r (arm_x_op,REGISTER_S0,instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); } enum { SIZE_LONG, SIZE_WORD, SIZE_BYTE }; static void as_cmp_i_parameter (int i,struct parameter *parameter) { int reg,reg_i,shift; switch (parameter->parameter_type){ case P_REGISTER: reg=parameter->parameter_data.reg.r; reg_i=REGISTER_S0; break; default: as_load_parameter_to_scratch_register (parameter); reg=REGISTER_S0; reg_i=REGISTER_S1; } shift = immediate_shift (i); if (shift>=0){ as_cmp_is_r (i,shift,reg); return; } else { shift = immediate_shift (-i); if (shift>=0){ as_cmn_is_r (-i,shift,reg); return; } } store_l (0xe59f0000 | (reg_num (reg_i)<<12)); /* ldr rt,[pc+imm] */ as_literal_entry (NULL,i); as_cmp_r_r (reg_i,reg); } static void as_cmp_instruction (struct instruction *instruction) { switch (instruction->instruction_parameters[0].parameter_type){ case P_DESCRIPTOR_NUMBER: switch (instruction->instruction_parameters[1].parameter_type){ case P_REGISTER: as_move_d_r (instruction->instruction_parameters[0].parameter_data.l, instruction->instruction_parameters[0].parameter_offset,REGISTER_S1); as_cmp_r_r (REGISTER_S1,instruction->instruction_parameters[1].parameter_data.reg.r); return; default: as_load_parameter_to_scratch_register (&instruction->instruction_parameters[1]); as_move_d_r (instruction->instruction_parameters[0].parameter_data.l, instruction->instruction_parameters[0].parameter_offset,REGISTER_S1); as_cmp_r_r (REGISTER_S1,REGISTER_S0); return; } break; case P_IMMEDIATE: as_cmp_i_parameter (instruction->instruction_parameters[0].parameter_data.i, &instruction->instruction_parameters[1]); return; } if (instruction->instruction_parameters[1].parameter_type==P_REGISTER) switch (instruction->instruction_parameters[0].parameter_type){ case P_REGISTER: as_cmp_r_r (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; default: as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); as_cmp_r_r (REGISTER_S0,instruction->instruction_parameters[1].parameter_data.reg.r); return; } internal_error_in_function ("as_cmp_instruction"); } 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); } static void as_jmp_instruction (struct instruction *instruction) { switch (instruction->instruction_parameters[0].parameter_type){ case P_LABEL: store_l (0xea000000); as_branch_label (instruction->instruction_parameters[0].parameter_data.l,JUMP_RELOCATION); break; case P_INDIRECT: as_ldr_id_r (instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_PC); break; case P_REGISTER: as_mov_r_r (instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_PC); break; default: internal_error_in_function ("as_jmp_instruction"); } write_literals(); } static void as_jmpp_instruction (struct instruction *instruction) { #if 0 switch (instruction->instruction_parameters[0].parameter_type){ case P_LABEL: { int offset; offset=instruction->instruction_parameters[0].parameter_offset; if (offset==0){ store_l (0xeb000000); /* bl */ as_branch_label (profile_t_label,CALL_RELOCATION); } store_l (0xea000000); /* b */ /* store_c (0351); store_l (offset); */ as_branch_label (instruction->instruction_parameters[0].parameter_data.l,JUMP_RELOCATION); break; } case P_INDIRECT: store_c (0350); store_l (0); as_branch_label (profile_t_label,CALL_RELOCATION); as_id (0377,040,instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r); break; case P_REGISTER: store_c (0350); store_l (0); as_branch_label (profile_t_label,CALL_RELOCATION); store_c (0377); store_c (0340 | reg_num (instruction->instruction_parameters[0].parameter_data.reg.r)); break; default: internal_error_in_function ("as_jmpp_instruction"); } #else internal_error_in_function ("as_jmpp_instruction"); #endif } static void as_jsr_instruction (struct instruction *instruction) { switch (instruction->instruction_parameters[0].parameter_type){ case P_LABEL: if (instruction->instruction_arity>1) switch (instruction->instruction_parameters[1].parameter_type){ case P_INDIRECT_WITH_UPDATE: as_str_r_id_update (REGISTER_PC,instruction->instruction_parameters[1].parameter_offset,B_STACK_POINTER); break; case P_INDIRECT: as_str_r_id (REGISTER_PC,instruction->instruction_parameters[1].parameter_offset,B_STACK_POINTER); } store_l (0xeb000000); /* bl */ as_branch_label (instruction->instruction_parameters[0].parameter_data.l,CALL_RELOCATION); break; case P_INDIRECT: as_ldr_id_r (instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); if (instruction->instruction_arity>1) if (instruction->instruction_parameters[1].parameter_type==P_INDIRECT_WITH_UPDATE) as_str_r_id_update (REGISTER_PC,-4,B_STACK_POINTER); store_l (0xe12fff30 | reg_num (REGISTER_S0)); /* blx r12*/ break; case P_REGISTER: if (instruction->instruction_arity>1) if (instruction->instruction_parameters[1].parameter_type==P_INDIRECT_WITH_UPDATE) as_str_r_id_update (REGISTER_PC,-4,B_STACK_POINTER); store_l (0xe12fff30 | reg_num (instruction->instruction_parameters[0].parameter_data.reg.r)); /* blx rm*/ break; default: internal_error_in_function ("as_jsr_instruction"); } } static void as_rts_instruction (struct instruction *instruction) { store_l (0xe49df004); /* ldr pc,[sp],#4 */ write_literals(); } static void as_branch_instruction (struct instruction *instruction,int condition_code) { store_l ((condition_code<<28) | 0x0a000000); /* b */ as_branch_label (instruction->instruction_parameters[0].parameter_data.l,BRANCH_RELOCATION); } static void as_nop (void) { /* mov r0,r0 */ store_l (0xe1A00000); } static void as_shift_instruction (struct instruction *instruction,int shift_code) { if (instruction->instruction_parameters[0].parameter_type==P_IMMEDIATE){ as_shift_i_r_r (shift_code,instruction->instruction_parameters[0].parameter_data.i & 31, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); } else { int s_reg,d_reg; s_reg = instruction->instruction_parameters[0].parameter_data.reg.r; d_reg = instruction->instruction_parameters[1].parameter_data.reg.r; as_shift_r_r_r (shift_code,s_reg,d_reg,d_reg); } } static void as_lsli_instruction (struct instruction *instruction) { as_lsl_i_r_r (instruction->instruction_parameters[2].parameter_data.i & 31, instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); } static void as_logic_instruction (struct instruction *instruction,int arm_op) { switch (instruction->instruction_parameters[0].parameter_type){ case P_REGISTER: as_op_r_r_r (arm_op,instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_IMMEDIATE: { int shift,i; i = instruction->instruction_parameters[0].parameter_data.i; shift = immediate_shift (i); if (shift>=0){ as_op_is_r_r (arm_op,i,shift, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } shift = immediate_shift (~i); if (shift>=0){ if (arm_op==ARM_OP_AND){ as_op_is_r_r (ARM_OP_BIC,~i,shift, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); } else { store_l_is (0xe3e00000 | (reg_num (REGISTER_S0)<<12),~i,shift); /* mvn rd,#i<instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); } return; } store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ as_literal_entry (NULL,i); as_op_r_r_r (arm_op,REGISTER_S0, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } default: as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); as_op_r_r_r (arm_op,REGISTER_S0, instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_data.reg.r); return; } } static void as_mul_instruction (struct instruction *instruction) { int s_regn,real_d_regn; switch (instruction->instruction_parameters[0].parameter_type){ case P_REGISTER: s_regn = instruction->instruction_parameters[0].parameter_data.reg.r; break; case P_IMMEDIATE: as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,REGISTER_S0); s_regn = REGISTER_S0; default: as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); s_regn = REGISTER_S0; } real_d_regn = reg_num (instruction->instruction_parameters[1].parameter_data.reg.r); store_l (0xe0000090 | (real_d_regn<<16) | (real_d_regn<<8) | reg_num (s_regn)); /* mul rd,rn,rm */ } #define CONDITION_EQ 0 #define CONDITION_NE 1 #define CONDITION_HS 2 #define CONDITION_LO 3 #define CONDITION_MI 4 #define CONDITION_PL 5 #define CONDITION_VS 6 #define CONDITION_VC 7 #define CONDITION_HI 8 #define CONDITION_LS 9 #define CONDITION_GE 10 #define CONDITION_LT 11 #define CONDITION_GT 12 #define CONDITION_LE 13 /* From The PowerPC Compiler Writer's Guide, Warren, Henry S., Jr., IBM Research Report RC 18601 [1992]. Changing Division by a Constant to Multiplication in Two's Complement Arithmetic, (December 21), Granlund, Torbjorn and Montgomery, Peter L. [1994]. SIGPLAN Notices, 29 (June), 61. */ struct ms magic (int d) /* must have 2 <= d <= 231-1 or -231 <= d <= -2 */ { int p; unsigned int ad, anc, delta, q1, r1, q2, r2, t; const unsigned int two31 = 2147483648u;/* 231 */ struct ms mag; ad = abs(d); t = two31 + ((unsigned int)d >> 31); anc = t - 1 - t%ad; /* absolute value of nc */ p = 31; /* initialize p */ q1 = two31/anc; /* initialize q1 = 2p/abs(nc) */ r1 = two31 - q1*anc;/* initialize r1 = rem(2p,abs(nc)) */ q2 = two31/ad; /* initialize q2 = 2p/abs(d) */ r2 = two31 - q2*ad; /* initialize r2 = rem(2p,abs(d)) */ do { p = p + 1; q1 = 2*q1; /* update q1 = 2p/abs(nc) */ r1 = 2*r1; /* update r1 = rem(2p/abs(nc)) */ if (r1 >= anc) {/* must be unsigned comparison */ q1 = q1 + 1; r1 = r1 - anc; } q2 = 2*q2; /* update q2 = 2p/abs(d) */ r2 = 2*r2; /* update r2 = rem(2p/abs(d)) */ if (r2 >= ad) { /* must be unsigned comparison */ q2 = q2 + 1; r2 = r2 - ad; } delta = ad - r2; } while (q1 < delta || (q1 == delta && r1 == 0)); mag.m = q2 + 1; if (d < 0) mag.m = -mag.m; /* resulting magic number */ mag.s = p - 32; /* resulting shift */ return mag; } static void as_div_instruction (struct instruction *instruction) { int i,abs_i,d_reg; struct ms ms; if (instruction->instruction_parameters[0].parameter_type!=P_IMMEDIATE) internal_error_in_function ("as_div_instruction"); i=instruction->instruction_parameters[0].parameter_data.i; d_reg=instruction->instruction_parameters[1].parameter_data.reg.r; if (i==0){ internal_error_in_function ("as_div_instruction"); return; } abs_i=abs (i); if ((abs_i & (abs_i-1))==0){ int log2i; unsigned int i2; if (abs_i==1){ if (i<0) as_rsb_is_r_r (0,0,d_reg,d_reg); return; } log2i=0; i2=abs_i; while (i2>1){ i2>>=1; ++log2i; } if (log2i==1) as_add_r_lsr_r_r (d_reg,31,d_reg,d_reg); else { as_cmp_is_r (0,0,d_reg); if (log2i<=8) as_add_cc_is_r_r (CONDITION_LT,abs_i-1,0,d_reg,d_reg); else { as_add_is_r_r (abs_i,immediate_shift (abs_i),d_reg,REGISTER_S0); as_sub_cc_is_r_r (CONDITION_LT,1,0,REGISTER_S0,d_reg); } } if (i>0) as_asr_i_r_r (log2i,d_reg,d_reg); else { as_move_i_r (0,REGISTER_S0); as_sub_r_asr_r_r (d_reg,log2i,REGISTER_S0,d_reg); } return; } ms=magic (abs_i); as_move_i_r (ms.m,REGISTER_S0); if (ms.s==0){ if (ms.m>=0){ as_lsr_i_r_r (31,d_reg,REGISTER_S1); as_smmla_r_r_r (d_reg,REGISTER_S0,REGISTER_S1,d_reg); if (i<0) as_rsb_is_r_r (0,0,d_reg,d_reg); } else { if (ms.m>=0) as_smmul_r_r_r (REGISTER_S0,d_reg,REGISTER_S0); else as_smmla_r_r_r (REGISTER_S0,d_reg,d_reg,REGISTER_S0); if (i>=0) as_add_r_lsr_r_r (d_reg,31,REGISTER_S0,d_reg); else as_sub_r_asr_r_r (d_reg,31,REGISTER_S0,d_reg); } } else { if (ms.m>=0) as_smmul_r_r_r (REGISTER_S0,d_reg,REGISTER_S0); else as_smmla_r_r_r (REGISTER_S0,d_reg,d_reg,REGISTER_S0); if (i>=0){ as_lsr_i_r_r (31,d_reg,d_reg); as_add_r_asr_r_r (REGISTER_S0,ms.s,d_reg,d_reg); } else { as_asr_i_r_r (31,d_reg,d_reg); as_sub_r_asr_r_r (REGISTER_S0,ms.s,d_reg,d_reg); } } } static void as_rem_instruction (struct instruction *instruction) { int i,d_reg; struct ms ms; if (instruction->instruction_parameters[0].parameter_type!=P_IMMEDIATE) internal_error_in_function ("as_rem_instruction"); i=instruction->instruction_parameters[0].parameter_data.i; d_reg=instruction->instruction_parameters[1].parameter_data.reg.r; if (i==0){ internal_error_in_function ("as_rem_instruction"); return; } i=abs (i); if ((i & (i-1))==0){ int log2i; unsigned int i2; if (i==1){ as_move_i_r (0,d_reg); return; } as_sub_r_lsr_r_r (d_reg,31,d_reg,REGISTER_S0); log2i=0; i2=i; while (i2>1){ i2>>=1; ++log2i; } if (i<=256){ if (log2i!=1) as_asr_i_r_r (log2i-1,d_reg,d_reg); as_and_is_r_r (i-1,0,REGISTER_S0,REGISTER_S0); } else { as_move_i_r (-1,REGISTER_S1); as_asr_i_r_r (log2i-1,d_reg,d_reg); as_and_r_lsr_r_r (REGISTER_S1,32-log2i,REGISTER_S0,REGISTER_S0); } as_sub_r_lsr_r_r (d_reg,32-log2i,REGISTER_S0,d_reg); return; } ms=magic (i); as_move_i_r (ms.m,REGISTER_S0); if (ms.s==0){ if (ms.m>=0){ as_lsr_i_r_r (31,d_reg,REGISTER_S1); as_smmla_r_r_r (d_reg,REGISTER_S0,REGISTER_S1,REGISTER_S0); } else { if (ms.m>=0) as_smmul_r_r_r (REGISTER_S0,d_reg,REGISTER_S0); else as_smmla_r_r_r (REGISTER_S0,d_reg,d_reg,REGISTER_S0); as_add_r_lsr_r_r (d_reg,31,REGISTER_S0,REGISTER_S0); } } else { if (ms.m>=0) as_smmul_r_r_r (REGISTER_S0,d_reg,REGISTER_S0); else as_smmla_r_r_r (REGISTER_S0,d_reg,d_reg,REGISTER_S0); as_lsr_i_r_r (31,d_reg,REGISTER_S1); as_add_r_asr_r_r (REGISTER_S0,ms.s,REGISTER_S1,REGISTER_S0); } { unsigned int i2; i2=i & (i-1); if ((i2 & (i2-1))==0){ unsigned int n; int n_shifts; n=i; n_shifts=0; while (n>0){ while ((n & 1)==0){ n>>=1; ++n_shifts; } if (n_shifts>0) as_sub_r_lsl_r_r (REGISTER_S0,n_shifts,d_reg,d_reg); else as_sub_r_r_r (REGISTER_S0,d_reg,d_reg); n>>=1; n_shifts=1; } } else { #if 1 as_move_i_r (-i,REGISTER_S1); as_mla_r_r_r_r (REGISTER_S0,REGISTER_S1,d_reg,d_reg); #else /* mls is an illegal instruction on the raspberry pi b+ */ as_move_i_r (i,REGISTER_S1); as_mls_r_r_r_r (REGISTER_S0,REGISTER_S1,d_reg,d_reg); #endif } } } static void as_set_condition_instruction (struct instruction *instruction,int condition_code_true,int condition_code_false) { unsigned int rn; rn = reg_num (instruction->instruction_parameters[0].parameter_data.reg.r); store_l (0x03a00001 | (condition_code_true<<28) | (rn<<12)); /* movcc rd,#1 */ store_l (0x03a00000 | (condition_code_false<<28) | (rn<<12)); /* movcc rd,#0 */ } static void as_tst_instruction (struct instruction *instruction) { as_cmp_i_parameter (0,&instruction->instruction_parameters[0]); } static void as_btst_instruction (struct instruction *instruction) { int reg1,shift; if (instruction->instruction_parameters[1].parameter_type==P_REGISTER) reg1=instruction->instruction_parameters[1].parameter_data.reg.r; else { reg1=instruction->instruction_parameters[1].parameter_data.reg.r; as_ldr_id_r (instruction->instruction_parameters[1].parameter_offset,reg1,REGISTER_S0); reg1 = REGISTER_S0; } shift = immediate_shift (instruction->instruction_parameters[0].parameter_data.i); if (shift>=0){ as_tst_ir_r (instruction->instruction_parameters[0].parameter_data.i,shift,reg1); return; } internal_error_in_function ("as_btst_instruction"); } static void as_neg_instruction (struct instruction *instruction) { int reg; reg = instruction->instruction_parameters[0].parameter_data.reg.r; as_rsb_is_r_r (0,0,reg,reg); } static void as_not_instruction (struct instruction *instruction) { unsigned int regn; regn = reg_num (instruction->instruction_parameters[0].parameter_data.reg.r); store_l (0xe0000000 | (ARM_OP_MVN<<21) | (regn<<12) | regn); /* mvn rd,rm */ } static void 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: { int reg0,reg1; reg0=instruction->instruction_parameters[0].parameter_data.reg.r; reg1=instruction->instruction_parameters[1].parameter_data.reg.r; store_l (0xeeb00b40 | (reg1<<12) | reg0); /* vmov dd,dm */ return; } case P_INDIRECT: as_vldr_r_id (instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r); return; case P_INDEXED: as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, instruction->instruction_parameters[0].parameter_offset & 3, instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); as_vldr_r_id (instruction->instruction_parameters[1].parameter_data.reg.r, instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); return; case P_F_IMMEDIATE: as_vldr_r_id (instruction->instruction_parameters[1].parameter_data.reg.r,0,REGISTER_PC); as_float_literal_entry (instruction->instruction_parameters[0].parameter_data.r); return; default: internal_error_in_function ("as_fmove_instruction"); return; } case P_INDIRECT: if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ as_vstr_r_id (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; } break; case P_INDEXED: if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ as_add_r_lsl_r_r (instruction->instruction_parameters[1].parameter_data.ir->d_reg.r, instruction->instruction_parameters[1].parameter_offset & 3, instruction->instruction_parameters[1].parameter_data.ir->a_reg.r,REGISTER_S0); as_vstr_r_id (instruction->instruction_parameters[0].parameter_data.reg.r, instruction->instruction_parameters[1].parameter_offset>>2,REGISTER_S0); return; } } internal_error_in_function ("as_fmove_instruction"); return; } static void as_floads_instruction (struct instruction *instruction) { if (instruction->instruction_parameters[1].parameter_type==P_F_REGISTER){ int freg; switch (instruction->instruction_parameters[0].parameter_type){ case P_INDIRECT: freg=instruction->instruction_parameters[1].parameter_data.reg.r; as_vldr_s_id (freg,instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r); break; case P_INDEXED: freg=instruction->instruction_parameters[1].parameter_data.reg.r; as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, instruction->instruction_parameters[0].parameter_offset & 3, instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); as_vldr_s_id (freg,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); break; default: internal_error_in_function ("as_floads_instruction"); return; } store_l (0xeeb70ac0 | (freg<<12) | freg); /* vcvtr.f64.f32 dd,sm */ return; } internal_error_in_function ("as_floads_instruction"); } static void as_fmoves_instruction (struct instruction *instruction) { if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ int s_freg; s_freg=instruction->instruction_parameters[0].parameter_data.reg.r; store_l (0xeeb70bc0 | (15<<12) | s_freg); /* vcvtr.f32.f64 sd,dm */ switch (instruction->instruction_parameters[1].parameter_type){ case P_INDIRECT: as_vstr_s_id (15,instruction->instruction_parameters[1].parameter_offset, instruction->instruction_parameters[1].parameter_data.reg.r); return; case P_INDEXED: as_add_r_lsl_r_r (instruction->instruction_parameters[1].parameter_data.ir->d_reg.r, instruction->instruction_parameters[1].parameter_offset & 3, instruction->instruction_parameters[1].parameter_data.ir->a_reg.r,REGISTER_S0); as_vstr_r_id (15,instruction->instruction_parameters[1].parameter_offset>>2,REGISTER_S0); return; } } internal_error_in_function ("as_fmoves_instruction"); return; } static void as_dyadic_float_instruction (struct instruction *instruction,int code) { int d_freg,s_freg; switch (instruction->instruction_parameters[0].parameter_type){ case P_F_IMMEDIATE: as_vldr_r_id (15,0,REGISTER_PC); as_float_literal_entry (instruction->instruction_parameters[0].parameter_data.r); s_freg=15; break; case P_INDIRECT: as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r); s_freg=15; break; case P_INDEXED: as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, instruction->instruction_parameters[0].parameter_offset & 3, instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); s_freg=15; break; case P_F_REGISTER: s_freg = instruction->instruction_parameters[0].parameter_data.reg.r; break; default: internal_error_in_function ("as_dyadic_float_instruction"); return; } d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; store_l (0xee000b00 | code | (d_freg<<16) | (d_freg<<12) | s_freg); } static void as_vcmp_f64_r_r (int freg_1,int freg_2) { store_l (0xeeb40b40 | (freg_2<<12) | freg_1); /* vcmp.f64 dd,dm */ } static void as_compare_float_instruction (struct instruction *instruction) { int d_freg; int code1,code2; d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; switch (instruction->instruction_parameters[0].parameter_type){ case P_F_IMMEDIATE: { DOUBLE *r_p; r_p=instruction->instruction_parameters[0].parameter_data.r; if ((((LONG*)r_p)[0] | ((LONG*)r_p)[1])==0){ store_l (0xeeb50b40 | (d_freg<<12)); /* vcmp.f64 dd,#0.0 */ } else { as_vldr_r_id (15,0,REGISTER_PC); as_float_literal_entry (instruction->instruction_parameters[0].parameter_data.r); as_vcmp_f64_r_r (15,d_freg); } return; } case P_INDIRECT: as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r); as_vcmp_f64_r_r (15,d_freg); return; case P_INDEXED: as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, instruction->instruction_parameters[0].parameter_offset & 3, instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); as_vcmp_f64_r_r (15,d_freg); return; case P_F_REGISTER: as_vcmp_f64_r_r (instruction->instruction_parameters[0].parameter_data.reg.r,d_freg); return; default: internal_error_in_function ("as_compare_float_instruction"); return; } } static void as_monadic_float_instruction (struct instruction *instruction,int code) { int s_freg,d_freg; switch (instruction->instruction_parameters[0].parameter_type){ case P_F_IMMEDIATE: as_vldr_r_id (15,0,REGISTER_PC); as_float_literal_entry (instruction->instruction_parameters[0].parameter_data.r); s_freg=15; break; case P_INDIRECT: as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r); s_freg=15; break; case P_INDEXED: as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, instruction->instruction_parameters[0].parameter_offset & 3, instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); s_freg=15; break; case P_F_REGISTER: s_freg = instruction->instruction_parameters[0].parameter_data.reg.r; break; default: internal_error_in_function ("as_dyadic_float_instruction"); return; } d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; store_l (0xeeb00b40 | code | (d_freg<<12) | s_freg); } static void as_test_floating_point_condition_code (void) { store_l (0xeef1fa10); /* vmrs APSR_nzcv,fpscr */ /* APSR_nzcv is encoded as register 15, fpscr as register 1 */ } static void as_float_branch_instruction (struct instruction *instruction,int condition_code) { as_test_floating_point_condition_code(); /* Z N C V equal 1 0 1 0 less than 0 1 0 0 greater than 0 0 1 0 unordered 0 0 1 1 bgt Z==0 && N==V ble Z==1 || N!=V */ store_l ((condition_code<<28) | 0x0a000000); /* b */ as_branch_label (instruction->instruction_parameters[0].parameter_data.l,BRANCH_RELOCATION); } static void as_set_float_condition_instruction (struct instruction *instruction,int condition_code_true,int condition_code_false) { as_test_floating_point_condition_code(); as_set_condition_instruction (instruction,condition_code_true,condition_code_false); } 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); #ifndef ELF if (string_length<8) new_object_label->object_label_string_offset=0; else #endif { 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; } } 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_fmovel_instruction (struct instruction *instruction) { if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ int s_freg; s_freg=instruction->instruction_parameters[0].parameter_data.reg.r; /* s30 */ store_l (0xeebd0b40 | (15<<12) | s_freg); /* vcvtr.s32.f64 sd,dm */ store_l (0xee100a10 | (15<<16) | (reg_num (instruction->instruction_parameters[1].parameter_data.reg.r)<<12)); /* vmov rt,sn */ return; } else internal_error_in_function ("as_fmovel_instruction"); } else { int freg; switch (instruction->instruction_parameters[0].parameter_type){ case P_REGISTER: freg=instruction->instruction_parameters[1].parameter_data.reg.r; store_l (0xee000a10 | (freg<<16) | (reg_num (instruction->instruction_parameters[0].parameter_data.reg.r)<<12)); /* vmov sn,rt */ break; case P_INDIRECT: as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset, instruction->instruction_parameters[0].parameter_data.reg.r); freg=instruction->instruction_parameters[1].parameter_data.reg.r; store_l (0xee000a10 | (freg<<16) | (reg_num (REGISTER_S0)<<12)); /* vmov sn,rt */ break; case P_INDEXED: as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, instruction->instruction_parameters[0].parameter_offset & 3, instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); freg=instruction->instruction_parameters[1].parameter_data.reg.r; store_l (0xee000a10 | (freg<<16) | (reg_num (REGISTER_S0)<<12)); /* vmov sn,rt */ break; case P_IMMEDIATE: freg=instruction->instruction_parameters[1].parameter_data.reg.r; as_vldr_s_id (freg,0,REGISTER_PC); as_float_load_int_literal_entry (instruction->instruction_parameters[0].parameter_data.i); break; default: internal_error_in_function ("as_fmovel_instruction"); return; } store_l (0xeeb80bc0 | (freg<<12) | freg); /* vcvt.f64.s32 dd,sm */ return; } } 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; ++n_object_labels; string_length=strlen (label->label_name); #ifndef ELF if (string_length<8) new_object_label->object_label_string_offset=0; else #endif { 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; } } } static void as_instructions (struct instruction *instruction) { while (instruction!=NULL){ switch (instruction->instruction_icode){ case IMOVE: as_move_instruction (instruction); break; case ILEA: as_lea_instruction (instruction); break; case IADD: as_add_instruction (instruction); break; case ISUB: as_sub_instruction (instruction); break; case ICMP: as_cmp_instruction (instruction); break; case IJMP: as_jmp_instruction (instruction); break; case IJMPP: as_jmpp_instruction (instruction); break; case IJSR: as_jsr_instruction (instruction); break; case IRTS: as_rts_instruction (instruction); break; case IRTSP: store_l (0xea000000); /* b */ as_branch_label (profile_r_label,JUMP_RELOCATION); break; case IBEQ: as_branch_instruction (instruction,CONDITION_EQ); break; case IBGE: as_branch_instruction (instruction,CONDITION_GE); break; case IBGEU: as_branch_instruction (instruction,CONDITION_HS); break; case IBGT: as_branch_instruction (instruction,CONDITION_GT); break; case IBGTU: as_branch_instruction (instruction,CONDITION_HI); break; case IBLE: as_branch_instruction (instruction,CONDITION_LE); break; case IBLEU: as_branch_instruction (instruction,CONDITION_LS); break; case IBLT: as_branch_instruction (instruction,CONDITION_LT); break; case IBLTU: as_branch_instruction (instruction,CONDITION_LO); break; case IBNE: as_branch_instruction (instruction,CONDITION_NE); break; case IBO: as_branch_instruction (instruction,CONDITION_VS); break; case IBNO: as_branch_instruction (instruction,CONDITION_VC); break; case ILSL: as_shift_instruction (instruction,ARM_OP_LSL); break; case ILSR: as_shift_instruction (instruction,ARM_OP_LSR); break; case IASR: as_shift_instruction (instruction,ARM_OP_ASR); break; case IMUL: as_mul_instruction (instruction); break; case IDIV: as_div_instruction (instruction); break; case IREM: as_rem_instruction (instruction); break; case IAND: as_logic_instruction (instruction,ARM_OP_AND); break; case IOR: as_logic_instruction (instruction,ARM_OP_ORR); break; case IEOR: as_logic_instruction (instruction,ARM_OP_EOR); break; case IADDI: as_addi_instruction (instruction); break; case ILSLI: as_lsli_instruction (instruction); break; case ISEQ: as_set_condition_instruction (instruction,CONDITION_EQ,CONDITION_NE); break; case ISGE: as_set_condition_instruction (instruction,CONDITION_GE,CONDITION_LT); break; case ISGEU: as_set_condition_instruction (instruction,CONDITION_HS,CONDITION_LO); break; case ISGT: as_set_condition_instruction (instruction,CONDITION_GT,CONDITION_LE); break; case ISGTU: as_set_condition_instruction (instruction,CONDITION_HI,CONDITION_LS); break; case ISLE: as_set_condition_instruction (instruction,CONDITION_LE,CONDITION_GT); break; case ISLEU: as_set_condition_instruction (instruction,CONDITION_LS,CONDITION_HI); break; case ISLT: as_set_condition_instruction (instruction,CONDITION_LT,CONDITION_GE); break; case ISLTU: as_set_condition_instruction (instruction,CONDITION_LO,CONDITION_HS); break; case ISNE: as_set_condition_instruction (instruction,CONDITION_NE,CONDITION_EQ); break; case ISO: as_set_condition_instruction (instruction,CONDITION_VS,CONDITION_VC); break; case ISNO: as_set_condition_instruction (instruction,CONDITION_VC,CONDITION_VS); break; case ITST: as_tst_instruction (instruction); break; case IBTST: as_btst_instruction (instruction); break; case IMOVEDB: as_movew_instruction (instruction); break; case IMOVEB: as_moveb_instruction (instruction); break; case INEG: as_neg_instruction (instruction); break; case INOT: as_not_instruction (instruction); break; case IMOVEM: as_movem_instruction (instruction); break; case IADC: as_add_or_sub_x_instruction (instruction,ARM_OP_ADC<<1,ARM_OP_SBC<<1); break; case ISBB: as_add_or_sub_x_instruction (instruction,ARM_OP_SBC<<1,ARM_OP_ADC<<1); break; case IWORD: store_c (instruction->instruction_parameters[0].parameter_data.i); break; case IROTR: as_shift_instruction (instruction,ARM_OP_ROR); break; case IADDO: as_add_or_sub_x_instruction (instruction,(ARM_OP_ADD<<1) | 1,(ARM_OP_SUB<<1) | 1); break; case ISUBO: as_add_or_sub_x_instruction (instruction,(ARM_OP_SUB<<1) | 1,(ARM_OP_ADD<<1) | 1); break; case IFMOVE: as_fmove_instruction (instruction); break; case IFADD: as_dyadic_float_instruction (instruction,0x00300000); break; case IFSUB: as_dyadic_float_instruction (instruction,0x00300040); break; case IFCMP: as_compare_float_instruction (instruction); break; case IFDIV: as_dyadic_float_instruction (instruction,0x00800000); break; case IFMUL: as_dyadic_float_instruction (instruction,0x00200000); break; case IFBEQ: as_float_branch_instruction (instruction,CONDITION_EQ); break; case IFBGE: as_float_branch_instruction (instruction,CONDITION_PL); break; case IFBGT: as_float_branch_instruction (instruction,CONDITION_GT); break; case IFBLE: as_float_branch_instruction (instruction,CONDITION_LE); break; case IFBLT: as_float_branch_instruction (instruction,CONDITION_MI); break; case IFBNE: as_float_branch_instruction (instruction,CONDITION_NE); break; case IFMOVEL: as_fmovel_instruction (instruction); break; case IFLOADS: as_floads_instruction (instruction); break; case IFMOVES: as_fmoves_instruction (instruction); break; case IFSQRT: as_monadic_float_instruction (instruction,0x10080); break; case IFNEG: as_monadic_float_instruction (instruction,0x10000); break; case IFABS: as_monadic_float_instruction (instruction,0x00080); break; case IFSEQ: as_set_float_condition_instruction (instruction,CONDITION_EQ,CONDITION_NE); break; case IFSGE: as_set_float_condition_instruction (instruction,CONDITION_PL,CONDITION_MI); break; case IFSGT: as_set_float_condition_instruction (instruction,CONDITION_GT,CONDITION_LE); break; case IFSLE: as_set_float_condition_instruction (instruction,CONDITION_LE,CONDITION_GT); break; case IFSLT: as_set_float_condition_instruction (instruction,CONDITION_MI,CONDITION_PL); break; case IFSNE: as_set_float_condition_instruction (instruction,CONDITION_NE,CONDITION_EQ); break; default: internal_error_in_function ("as_instructions"); } instruction=instruction->instruction_next; } } static void as_garbage_collect_test (struct basic_block *block) { LONG n_cells; struct call_and_jump *new_call_and_jump; int shift; n_cells=block->block_n_new_heap_cells; new_call_and_jump=allocate_memory_from_heap (sizeof (struct call_and_jump)); new_call_and_jump->cj_next=NULL; 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"); return; } 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; shift = immediate_shift (n_cells); if (shift>=0){ as_subs_is_r_r (n_cells,shift,REGISTER_R5,REGISTER_R5); } else { store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ as_literal_entry (NULL,n_cells); as_x_op_r_r_r ((ARM_OP_SUB<<1) | 1,REGISTER_S0,REGISTER_R5,REGISTER_R5); /* subs */ } store_l ((CONDITION_LO<<28) | 0x0a000000); /* blo */ as_branch_label (&new_call_and_jump->cj_label,BRANCH_RELOCATION); new_call_and_jump->cj_jump.label_flags=0; new_call_and_jump->cj_jump.label_id=TEXT_LABEL_ID; #ifdef FUNCTION_LEVEL_LINKING new_call_and_jump->cj_jump.label_object_label=code_object_label; #endif new_call_and_jump->cj_jump.label_offset=CURRENT_CODE_OFFSET; } static void as_call_and_jump (struct call_and_jump *call_and_jump) { call_and_jump->cj_label.label_flags=0; 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; store_l (0xeb000000); /* bl */ as_branch_label (call_and_jump->cj_call_label,CALL_RELOCATION); store_l (0xea000000); /* b */ as_branch_label (&call_and_jump->cj_jump,JUMP_RELOCATION); } static void as_check_stack (struct basic_block *block) { #if 0 if (block->block_a_stack_check_size>0){ if (block->block_a_stack_check_size<=32) as_r_a (0073,A_STACK_POINTER,end_a_stack_label); /* cmp */ else { as_id_r (0215,block->block_a_stack_check_size,A_STACK_POINTER,REGISTER_S0); /* lea */ as_r_a (0073,REGISTER_S0,end_a_stack_label); /* cmp */ } store_c (0x0f); store_c (0x83); /* jae */ store_l (0); as_branch_label (stack_overflow_label,BRANCH_RELOCATION); } if (block->block_b_stack_check_size>0){ if (block->block_b_stack_check_size<=32) as_r_a (0073,B_STACK_POINTER,end_b_stack_label); /* cmp */ else { as_id_r (0215,block->block_b_stack_check_size,B_STACK_POINTER,REGISTER_S0); /* lea */ as_r_a (0073,REGISTER_S0,end_b_stack_label); /* cmp */ } store_c (0x0f); store_c (0x82); /* jb */ store_l (0); as_branch_label (stack_overflow_label,BRANCH_RELOCATION); } #else internal_error_in_function ("as_check_stack"); #endif } static void as_profile_call (struct basic_block *block) { LABEL *profile_label; as_move_d_r (block->block_profile_function_label,0,REGISTER_A2); if (block->block_n_node_arguments>-100) profile_label=block->block_profile==2 ? profile_n2_label : profile_n_label; else { switch (block->block_profile){ case 2: profile_label=profile_s2_label; break; case 4: profile_label=profile_l_label; break; case 5: profile_label=profile_l2_label; break; default: profile_label=profile_s_label; } } store_l (0xeb000000); /* bl */ as_branch_label (profile_label,CALL_RELOCATION); } #ifdef NEW_APPLY extern LABEL *add_empty_node_labels[]; static void as_apply_update_entry (struct basic_block *block) { if (block->block_profile) as_profile_call (block); if (block->block_n_node_arguments==-200){ store_l (0xea000000); /* b */ as_branch_label (block->block_ea_label,JUMP_RELOCATION); as_nop(); } else { store_l (0xeb000000); /* bl */ as_branch_label (add_empty_node_labels[block->block_n_node_arguments+200],CALL_RELOCATION); store_l (0xea000000); /* b */ as_branch_label (block->block_ea_label,JUMP_RELOCATION); } } #endif static void as_node_entry_info (struct basic_block *block) { if (block->block_ea_label!=NULL){ extern LABEL *eval_fill_label,*eval_upd_labels[]; int n_node_arguments; 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){ #if 1 if (!block->block_profile){ as_move_l_r (block->block_ea_label,REGISTER_A3); store_l (0xea000000); /* b */ as_branch_label (eval_upd_labels[n_node_arguments],JUMP_RELOCATION); as_nop(); } else { as_move_l_r (block->block_ea_label,REGISTER_D0); as_move_l_r (block->block_profile_function_label,REGISTER_A3); store_l (0xea000000); /* b */ as_branch_label (eval_upd_labels[n_node_arguments],JUMP_RELOCATION); } #else as_move_l_r (eval_upd_labels[n_node_arguments],REGISTER_D0); as_move_l_r (block->block_ea_label,REGISTER_A3); store_c (0377); store_c (0340 | reg_num (REGISTER_D0)); /* jmp d0 */ #endif } else { store_l (0xea000000); /* b */ as_branch_label (block->block_ea_label,JUMP_RELOCATION); as_nop(); as_nop(); } if (block->block_descriptor!=NULL && (block->block_n_node_arguments<0 || parallel_flag || module_info_flag)){ store_l (0); store_label_in_code_section (block->block_descriptor); } else store_l (0); } else if (block->block_descriptor!=NULL && (block->block_n_node_arguments<0 || parallel_flag || module_info_flag)){ store_l (0); store_label_in_code_section (block->block_descriptor); } /* else store_l (0); */ store_l (block->block_n_node_arguments); } static void write_code (void) { struct basic_block *block; struct call_and_jump *call_and_jump; #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 literal_entry_l=&first_literal_entry; first_literal_entry=NULL; 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){ #if 1 switch (3 & -(CURRENT_CODE_OFFSET-code_object_label->object_label_offset)){ case 0: break; case 1: store_c (0x90); break; case 2: store_c (0213); store_c (0300 | (reg_num (EBP)<<3) | reg_num (EBP)); break; case 3: store_c (0215); store_c (0x40 | (reg_num (EBP)<<3) | reg_num (EBP)); store_c (0); break; } #else while (((CURRENT_CODE_OFFSET-code_object_label->object_label_offset) & 3)!=0) store_c (0x90); #endif { struct relocation *new_relocation; new_relocation=fast_memory_allocate_type (struct relocation); *last_code_relocation_l=new_relocation; last_code_relocation_l=&new_relocation->next; new_relocation->next=NULL; U4 (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); } #ifdef FUNCTION_LEVEL_LINKING as_new_code_module(); #endif *(struct object_label**)&block->block_last_instruction = code_object_label; } else *(struct object_label**)&block->block_last_instruction = NULL; } else { #ifdef FUNCTION_LEVEL_LINKING write_literals(); as_new_code_module(); #endif *(struct object_label**)&block->block_last_instruction = code_object_label; } } else *(struct object_label**)&block->block_last_instruction = NULL; #endif if (block->block_n_node_arguments>-100){ #ifndef FUNCTION_LEVEL_LINKING while ((code_buffer_free & 3)!=0) store_c (0x90); #endif as_node_entry_info (block); } #ifdef NEW_APPLY else if (block->block_n_node_arguments<-100) as_apply_update_entry (block); #endif as_labels (block->block_labels); if (block->block_profile) as_profile_call (block); if (block->block_n_new_heap_cells>0) as_garbage_collect_test (block); if (check_stack && (block->block_a_stack_check_size>0 || block->block_b_stack_check_size>0)) as_check_stack (block); as_instructions (block->block_instructions); } write_literals(); for_l (call_and_jump,first_call_and_jump,cj_next){ #ifdef FUNCTION_LEVEL_LINKING as_new_code_module(); #endif as_call_and_jump (call_and_jump); } } static void write_string_8 (char *string) { int i; i=0; while (i<8){ char c; c=string[i++]; write_c (c); if (c=='\0'){ while (i<8){ write_c ('\0'); ++i; } return; } } } #ifdef ELF static void write_zstring (char *string) { char c; do { c=*string++; write_c (c); } while (c!='\0'); } #endif extern char *this_module_name; #if defined (ELF) && defined (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; int n_code_relocation_sections,n_data_relocation_sections; int section_strings_size; #ifdef FUNCTION_LEVEL_LINKING 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+=12+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+=12+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+=12+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+=12+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 write_l (0x464c457f); write_l (0x00010101); write_l (0); write_l (0); write_l (0x00280001); write_l (1); write_l (0); write_l (0); write_l (0x34); write_l (EF_ARM_EABI_VER5); write_l (0x00000034); write_l (0x00280000); #ifdef FUNCTION_LEVEL_LINKING write_l (0x00010000 | (n_sections+n_code_relocation_sections+n_data_relocation_sections+4)); #else write_l (0x00010008); #endif 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 write_l (1); write_l (SHT_STRTAB); write_l (0); write_l (0); write_l (offset); #ifdef FUNCTION_LEVEL_LINKING write_l ((27+section_strings_size+3) & -4); #else write_l (60); #endif write_l (0); write_l (0); write_l (1); write_l (0); #ifdef FUNCTION_LEVEL_LINKING offset+=(27+section_strings_size+3) & -4; #else offset+=60; #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_REL); write_l (0); write_l (0); write_l (offset+code_relocations_offset); write_l (8*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 (8); section_string_offset+=12+n_digits (object_label->object_label_section_n); code_relocations_offset+=8*n_code_relocations_in_section; } } } offset+=8*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_REL); write_l (0); write_l (0); write_l (offset+data_relocations_offset); write_l (8*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 (8); section_string_offset+=12+n_digits (object_label->object_label_section_n); data_relocations_offset+=8*n_data_relocations_in_section; } } } offset+=8*n_data_relocations; } #else write_l (11); write_l (SHT_PROGBITS); write_l (SHF_ALLOC | SHF_EXECINSTR); write_l (0); write_l (offset); write_l (code_buffer_offset); write_l (0); write_l (0); write_l (4); write_l (0); offset+=(code_buffer_offset+3 ) & ~3; write_l (17); write_l (SHT_PROGBITS); write_l (SHF_ALLOC | SHF_WRITE); write_l (0); write_l (offset); write_l (data_buffer_offset); write_l (0); write_l (0); write_l (4); write_l (0); offset+=(data_buffer_offset+3) & ~3; write_l (23); write_l (SHT_REL); write_l (0); write_l (0); write_l (offset); write_l (8*n_code_relocations); write_l (6); write_l (2); write_l (4); write_l (8); offset+=8*n_code_relocations; write_l (33); write_l (SHT_REL); write_l (0); write_l (0); write_l (offset); write_l (8*n_data_relocations); write_l (6); write_l (3); write_l (4); write_l (8); offset+=8*n_data_relocations; #endif #ifdef FUNCTION_LEVEL_LINKING write_l (11+section_strings_size); #else write_l (43); #endif write_l (SHT_SYMTAB); write_l (0); write_l (0); write_l (offset); #ifdef FUNCTION_LEVEL_LINKING write_l (16*(n_object_labels+n_sections)); write_l (n_sections+n_code_relocation_sections+n_data_relocation_sections+3); write_l (1+n_sections); #else write_l (16*n_object_labels); write_l (7); write_l (3); #endif write_l (4); write_l (16); #ifdef FUNCTION_LEVEL_LINKING offset+=16*(n_object_labels+n_sections); #else offset+=16*n_object_labels; #endif #ifdef FUNCTION_LEVEL_LINKING write_l (19+section_strings_size); #else write_l (51); #endif write_l (SHT_STRTAB); write_l (0); write_l (0); write_l (offset); write_l (string_table_offset); write_l (0); write_l (0); write_l (0); write_l (0); write_c (0); write_zstring (".shstrtab"); #ifdef FUNCTION_LEVEL_LINKING { struct object_label *object_label; int section_n; char section_name[20]; for (section_n=0; section_nobject_label_kind==CODE_CONTROL_SECTION && object_label->object_label_n_relocations>0){ sprintf (section_name,".rel.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,".rel.data.m%d",object_label->object_label_section_n); write_zstring (section_name); } } #else write_zstring (".text"); write_zstring (".data"); write_zstring (".rel.text"); write_zstring (".rel.data"); #endif write_zstring (".symtab"); write_zstring (".strtab"); if (((27+section_strings_size) & 3)!=0){ int n; n=4-((27+section_strings_size) & 3); do { write_c (0); } while (--n); } } static void relocate_code (void) { struct relocation *relocation,**relocation_p; struct object_buffer *object_buffer; int code_buffer_offset; struct label *label; int instruction_offset; LONG v; object_buffer=first_code_buffer; code_buffer_offset=0; relocation_p=&first_code_relocation; while ((relocation=*relocation_p)!=NULL){ label=relocation->relocation_label; switch (relocation->relocation_kind){ case CALL_RELOCATION: case BRANCH_RELOCATION: case JUMP_RELOCATION: if (label->label_id==TEXT_LABEL_ID){ instruction_offset=relocation->relocation_offset; #ifdef FUNCTION_LEVEL_LINKING if (label->label_object_label!=relocation->relocation_object_label){ v=label->label_offset-label->label_object_label->object_label_offset; v-=8; ++n_code_relocations; relocation_p=&relocation->next; } else #endif { v=label->label_offset-(instruction_offset+8); *relocation_p=relocation->next; } } else { ++n_code_relocations; relocation_p=&relocation->next; instruction_offset=relocation->relocation_offset; v= -8; } while (instruction_offset >= code_buffer_offset+BUFFER_SIZE){ object_buffer=object_buffer->next; code_buffer_offset+=BUFFER_SIZE; } if (instruction_offset-code_buffer_offset<=BUFFER_SIZE-4){ LONG *instruction_p; instruction_p=(LONG*)(object_buffer->data+(instruction_offset-code_buffer_offset)); v >>= 2; *instruction_p = (*instruction_p & 0xff000000) | (v & 0x00ffffff); } else { unsigned char *p0,*p1,*p2,*end_buffer; p0=object_buffer->data+(instruction_offset-code_buffer_offset); end_buffer=object_buffer->data+BUFFER_SIZE; p1=p0+1; if (p1==end_buffer) p1=object_buffer->next->data; p2=p1+1; if (p2==end_buffer) p2=object_buffer->next->data; v >>= 2; v += (*p0 | (*p1<<8) | (*p2<<16)); *p0=v; *p1=v>>8; *p2=v>>16; } continue; case LDR_OFFSET_RELOCATION: if (label->label_id==TEXT_LABEL_ID){ instruction_offset=relocation->relocation_offset; #ifdef FUNCTION_LEVEL_LINKING if (label->label_object_label!=relocation->relocation_object_label){ v=label->label_offset-label->label_object_label->object_label_offset; v-=8; ++n_code_relocations; relocation_p=&relocation->next; } else #endif { v=label->label_offset-(instruction_offset+8); *relocation_p=relocation->next; } } else { ++n_code_relocations; relocation_p=&relocation->next; instruction_offset=relocation->relocation_offset; v= -8; } while (instruction_offset >= code_buffer_offset+BUFFER_SIZE){ object_buffer=object_buffer->next; code_buffer_offset+=BUFFER_SIZE; } if (instruction_offset-code_buffer_offset<=BUFFER_SIZE-4){ LONG *instruction_p; instruction_p=(LONG*)(object_buffer->data+(instruction_offset-code_buffer_offset)); if (v>=0) *instruction_p = (*instruction_p & 0xfffff000) | (v & 0x00000fff); else *instruction_p = (*instruction_p & 0xff7ff000) | ((-v) & 0x00000fff); /* clear add bit (23) */ } else { unsigned char *p0,*p1,*end_buffer; p0=object_buffer->data+(instruction_offset-code_buffer_offset); end_buffer=object_buffer->data+BUFFER_SIZE; p1=p0+1; if (p1==end_buffer) p1=object_buffer->next->data; v += (*p0 | (*p1<<8)) & 0xfff; if (v<0){ unsigned char *p2; p2=p1+1; if (p2==end_buffer) p2=object_buffer->next->data; v = -v; *p2 &= 0x7f; /* clear add bit (23) */ } *p0 = v; *p1 = (*p1) | ((v>>8) & 0xf); } continue; case VLDR_OFFSET_RELOCATION: if (label->label_id==TEXT_LABEL_ID){ instruction_offset=relocation->relocation_offset; #ifdef FUNCTION_LEVEL_LINKING if (label->label_object_label!=relocation->relocation_object_label){ v=label->label_offset-label->label_object_label->object_label_offset; v-=8; ++n_code_relocations; relocation_p=&relocation->next; } else #endif { v=label->label_offset-(instruction_offset+8); *relocation_p=relocation->next; } } else { ++n_code_relocations; relocation_p=&relocation->next; instruction_offset=relocation->relocation_offset; v= -8; } while (instruction_offset >= code_buffer_offset+BUFFER_SIZE){ object_buffer=object_buffer->next; code_buffer_offset+=BUFFER_SIZE; } { unsigned char *p0; p0=object_buffer->data+(instruction_offset-code_buffer_offset); *p0 += (v>>2); } continue; case LONG_WORD_RELOCATION: relocation_p=&relocation->next; if (label->label_id==TEXT_LABEL_ID || (label->label_id==DATA_LABEL_ID #if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) && !((label->label_flags & EXPORT_LABEL) && label->label_object_label->object_label_kind==EXPORTED_DATA_LABEL) #endif )) { instruction_offset=relocation->relocation_offset; v=label->label_offset; #ifdef FUNCTION_LEVEL_LINKING v -= label->label_object_label->object_label_offset; #endif break; } else continue; #ifdef FUNCTION_LEVEL_LINKING case DUMMY_BRANCH_RELOCATION: if (label->label_id==TEXT_LABEL_ID){ if (label->label_object_label!=relocation->relocation_object_label){ ++n_code_relocations; relocation_p=&relocation->next; continue; } *relocation_p=relocation->next; continue; } else { internal_error_in_function ("relocate_code"); *relocation_p=relocation->next; } #endif default: internal_error_in_function ("relocate_code"); } while (instruction_offset >= code_buffer_offset+BUFFER_SIZE){ object_buffer=object_buffer->next; code_buffer_offset+=BUFFER_SIZE; } if (instruction_offset-code_buffer_offset<=BUFFER_SIZE-4){ LONG *instruction_p; instruction_p=(LONG*)(object_buffer->data+(instruction_offset-code_buffer_offset)); *instruction_p += v; } else { unsigned char *p0,*p1,*p2,*p3,*end_buffer; p0=object_buffer->data+(instruction_offset-code_buffer_offset); end_buffer=object_buffer->data+BUFFER_SIZE; p1=p0+1; if (p1==end_buffer) p1=object_buffer->next->data; p2=p1+1; if (p2==end_buffer) p2=object_buffer->next->data; p3=p2+1; if (p3==end_buffer) p3=object_buffer->next->data; v+= (*p0) | (*p1<<8) | (*p2<<16) | (*p3<<24); *p0=v; *p1=v>>8; *p2=v>>16; *p3=v>>24; } } } static void relocate_data (void) { struct relocation *relocation; struct object_buffer *object_buffer; int data_buffer_offset; object_buffer=first_data_buffer; data_buffer_offset=0; for_l (relocation,first_data_relocation,next){ struct label *label; label=relocation->relocation_label; if (relocation->relocation_kind==LONG_WORD_RELOCATION){ if (label->label_id==TEXT_LABEL_ID || (label->label_id==DATA_LABEL_ID #if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) && !((label->label_flags & EXPORT_LABEL) && label->label_object_label->object_label_kind==EXPORTED_DATA_LABEL) #endif )) { int data_offset,v; data_offset=relocation->relocation_offset; while (data_offset >= data_buffer_offset+BUFFER_SIZE){ object_buffer=object_buffer->next; data_buffer_offset+=BUFFER_SIZE; } v = label->label_offset; #ifdef FUNCTION_LEVEL_LINKING v -= label->label_object_label->object_label_offset; #endif if (data_offset-data_buffer_offset<=BUFFER_SIZE-4){ LONG *data_p; data_p=(LONG*)(object_buffer->data+(data_offset-data_buffer_offset)); *data_p += v; } else { unsigned char *p0,*p1,*p2,*p3,*end_buffer; p0=object_buffer->data+(data_offset-data_buffer_offset); end_buffer=object_buffer->data+BUFFER_SIZE; p1=p0+1; if (p1==end_buffer) p1=object_buffer->next->data; p2=p1+1; if (p2==end_buffer) p2=object_buffer->next->data; p3=p2+1; if (p3==end_buffer) p3=object_buffer->next->data; v+= (*p0) | (*p1<<8) | (*p2<<16) | (*p3<<24); *p0=v; *p1=v>>8; *p2=v>>16; *p3=v>>24; } } } } } 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); #ifndef ELF if (string_length<8) new_object_label->object_label_string_offset=0; else #endif { 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); } #define C_EXT 2 #define C_STAT 3 static void write_object_labels (void) { struct object_label *object_label; #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 #ifdef ELF write_l (0); write_l (0); write_l (0); write_l (0); # ifndef FUNCTION_LEVEL_LINKING write_l (1); write_l (0); write_l (0); write_c (ELF32_ST_INFO (STB_LOCAL,STT_SECTION)); write_c (0); write_w (2); write_l (7); 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_nobject_label_kind){ case CODE_CONTROL_SECTION: { #ifndef ELF write_string_8 (".text"); # ifdef FUNCTION_LEVEL_LINKING write_l (0); write_w (1+object_label->object_label_section_n); # else write_l (object_label->object_label_offset); write_w (1); # endif write_w (0); write_c (C_STAT); write_c (1); write_l (object_label->object_label_length); # ifdef FUNCTION_LEVEL_LINKING write_w (object_label->object_label_n_relocations); # else write_w (n_code_relocations); # endif write_w (0); write_l (0); write_l (0); write_w (0); #endif 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 #ifndef ELF write_string_8 (".data"); # ifdef FUNCTION_LEVEL_LINKING write_l (0); write_w (1+n_code_sections+object_label->object_label_section_n); # else write_l (object_label->object_label_offset); write_w (2); # endif write_w (0); write_c (C_STAT); write_c (1); write_l (object_label->object_label_length); # ifdef FUNCTION_LEVEL_LINKING write_w (object_label->object_label_n_relocations); # else write_w (n_data_relocations); # endif write_w (0); write_l (0); write_l (0); write_w (0); #endif break; } case IMPORTED_LABEL: { struct label *label; label=object_label->object_label_label; #ifdef ELF 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); #else if (object_label->object_label_string_offset==0) write_string_8 (label->label_name); else { write_l (0); write_l (object_label->object_label_string_offset); } write_l (0); write_w (0); write_w (0); write_c (C_EXT); write_c (0); #endif break; } case EXPORTED_CODE_LABEL: { struct label *label; label=object_label->object_label_label; #ifdef ELF 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 #else if (object_label->object_label_string_offset==0) write_string_8 (label->label_name); else { write_l (0); write_l (object_label->object_label_string_offset); } #ifdef FUNCTION_LEVEL_LINKING write_l (label->label_offset - label->label_object_label->object_label_offset); write_w (1+label->label_object_label->object_label_section_n); #else write_l (label->label_offset); write_w (1); #endif write_w (0); write_c (C_EXT); write_c (0); #endif break; } case EXPORTED_DATA_LABEL: { struct label *label; label=object_label->object_label_label; #ifdef ELF 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 #else if (object_label->object_label_string_offset==0) write_string_8 (label->label_name); else { write_l (0); 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 write_w (1+n_code_sections+label->label_object_label->object_label_section_n); #else write_l (label->label_offset); write_w (2); #endif write_w (0); write_c (C_EXT); write_c (0); #endif break; } default: internal_error_in_function ("write_object_labels"); } } } static void write_string_table (void) { struct object_label *object_label; #ifdef ELF write_c (0); write_zstring (".text"); write_zstring (".data"); #else if (string_table_offset==4) return; write_l (string_table_offset); #endif 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'); } } } #define R_DIR32 6 #if defined (ELF) && defined (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 return label_n+n_sections; } #endif static void write_code_relocations (void) { struct relocation *relocation; for_l (relocation,first_code_relocation,next){ switch (relocation->relocation_kind){ case BRANCH_RELOCATION: case JUMP_RELOCATION: { struct label *label; label=relocation->relocation_label; #ifdef FUNCTION_LEVEL_LINKING if (label->label_id==-1) #else if (label->label_id<0) #endif internal_error_in_function ("write_code_relocations"); write_l (relocation->relocation_offset); #ifdef FUNCTION_LEVEL_LINKING write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_JUMP24)); #else write_l (ELF32_R_INFO (label->label_id,R_ARM_JUMP24)); #endif break; } case CALL_RELOCATION: { struct label *label; label=relocation->relocation_label; #ifdef FUNCTION_LEVEL_LINKING if (label->label_id==-1) #else if (label->label_id<0) #endif internal_error_in_function ("write_code_relocations"); write_l (relocation->relocation_offset); #ifdef FUNCTION_LEVEL_LINKING write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_CALL)); #else write_l (ELF32_R_INFO (label->label_id,R_ARM_CALL)); #endif break; } case LDR_OFFSET_RELOCATION: { struct label *label; label=relocation->relocation_label; #ifdef FUNCTION_LEVEL_LINKING if (label->label_id==-1) #else if (label->label_id<0) #endif internal_error_in_function ("write_code_relocations"); write_l (relocation->relocation_offset); #ifdef FUNCTION_LEVEL_LINKING write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_LDR_PC_G0)); #else write_l (ELF32_R_INFO (label->label_id,R_ARM_LDR_PC_G0)); #endif break; } case VLDR_OFFSET_RELOCATION: { struct label *label; label=relocation->relocation_label; #ifdef FUNCTION_LEVEL_LINKING if (label->label_id==-1) #else if (label->label_id<0) #endif internal_error_in_function ("write_code_relocations"); write_l (relocation->relocation_offset); #ifdef FUNCTION_LEVEL_LINKING write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_LDC_PC_G0)); #else write_l (ELF32_R_INFO (label->label_id,R_ARM_LDC_PC_G0)); #endif break; } case LONG_WORD_RELOCATION: { struct label *label; label=relocation->relocation_label; #ifdef FUNCTION_LEVEL_LINKING if (label->label_id==-1) #else if (label->label_id<0) #endif internal_error_in_function ("write_code_relocations"); write_l (relocation->relocation_offset); #ifdef FUNCTION_LEVEL_LINKING write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_ABS32)); #else write_l (ELF32_R_INFO (label->label_id,R_ARM_ABS32)); #endif break; } #ifdef FUNCTION_LEVEL_LINKING case DUMMY_BRANCH_RELOCATION: { struct label *label; label=relocation->relocation_label; if (label->label_id==-1) internal_error_in_function ("write_code_relocations"); write_l (relocation->relocation_offset - 4); write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_NONE)); break; } #endif default: internal_error_in_function ("write_code_relocations"); } } } static void write_data_relocations (void) { 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; #ifdef FUNCTION_LEVEL_LINKING if (label->label_id==-1) #else if (label->label_id<0) #endif internal_error_in_function ("write_data_relocations"); write_l (relocation->relocation_offset); #ifdef ELF # ifdef FUNCTION_LEVEL_LINKING write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_ABS32)); # else write_l (ELF32_R_INFO (label->label_id,R_ARM_ABS32)); # endif #else # ifdef FUNCTION_LEVEL_LINKING if (label->label_id==TEXT_LABEL_ID || label->label_id==DATA_LABEL_ID) write_l (label->label_object_label->object_label_number); else # endif write_l (label->label_id); write_w (R_DIR32); #endif break; } default: internal_error_in_function ("write_data_relocations"); } } } void assemble_code (void) { literal_table_at_offset = 0ul-1ul; literal_table_at_buffer_p = (unsigned char*)0ul-1ul; as_import_labels (labels); write_code(); if (code_buffer_free & 1) store_c (0x90); 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); # ifdef ELF if ((code_buffer_offset & 3)!=0){ int n; n=4-(code_buffer_offset & 3); do { write_c (0); } while (--n); } # endif write_buffers_and_release_memory (&first_data_buffer); # ifdef ELF if ((data_buffer_offset & 3)!=0){ int n; n=4-(data_buffer_offset & 3); do { write_c (0); } while (--n); } # endif write_code_relocations(); write_data_relocations(); write_object_labels(); write_string_table(); }