/*****************************************************************************/ /* */ /* midipix target interfaces */ /* */ /* Copyright (C) 2014,2015,2019 Z. Gilboa */ /* */ /* This program is free software: you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation, either version 3 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ /* */ /*****************************************************************************/ #include "config.h" #include "system.h" #include "coretypes.h" #include "tm.h" #include "rtl.h" #include "output.h" #include "tree.h" #include "flags.h" #include "target.h" #include "i386-protos.h" #include "function.h" #include "cgraph.h" /* got support */ int flag_got_established_section = 0; /* common specs */ const int TARGET_NOP_FUN_DLLIMPORT = 0; const int use_pe_aligned_common = 1; const int flag_writable_rel_rdata = 0; /* pointer annotation */ static const char winnt_ptrsize_long[] = ".long"; static const char winnt_ptrsize_quad[] = ".quad"; /* target SEH providers */ #define TARGET_SEH_WINNT (TARGET_SEH && TARGET_NT64) #define TARGET_SEH_MIDIPIX (TARGET_SEH && TARGET_NT32) /* 64-bit seh provided by winnt */ void winnt_x86_64_pe_seh_init(FILE *); void winnt_x86_64_pe_seh_end_prologue(FILE *); void winnt_x86_64_pe_seh_unwind_emit(FILE *, rtx); void winnt_x86_64_pe_seh_emit_except_personality(rtx); void winnt_x86_64_pe_seh_init_sections(void); /* 32-bit seh provided by midipix */ void midipix_i386_pe_seh_init(FILE *); void midipix_i386_pe_seh_end_prologue(FILE *); void midipix_i386_pe_seh_unwind_emit(FILE *, rtx); void midipix_i386_pe_seh_emit_except_personality(rtx); void midipix_i386_pe_seh_init_sections(void); /* debugging */ unsigned int midipix_dbx_get_register_number(unsigned int n) { if (TARGET_NT64 ) return dbx64_register_map[n]; else if (write_symbols == DWARF2_DEBUG) return svr4_dbx_register_map[n]; else return dbx_register_map[n]; } unsigned int midipix_dbx_get_dwarf_frame_register_number(unsigned int n) { if (TARGET_NT64) return dbx64_register_map[n]; else return svr4_dbx_register_map[n]; } void midipix_asm_output_dwarf_offset( FILE * gas_exhaled, unsigned size, const char * label, section * section __attribute__((unused))) { #define PE_SIZE_IDENTIFIER 4 #define PEP_SIZE_IDENTIFIER 8 extern void assemble_name (FILE *, const char *); if ((size == PE_SIZE_IDENTIFIER) || (size == PEP_SIZE_IDENTIFIER)) { fputs ("\t.secrel32\t", gas_exhaled); assemble_name(gas_exhaled, label); /* in PE32+, section relocation need to be zero-extended */ if (size == PEP_SIZE_IDENTIFIER) fputs ("\n\t.int\t0", gas_exhaled); } else gcc_unreachable(); } /* assembler labels */ void midipix_asm_output_label_ref (FILE * gas_exhaled, const char * name) { extern const char * user_label_prefix; /* in __fastcall labels the @ prefix is already present */ if (*name != FASTCALL_PREFIX) fputs(user_label_prefix, gas_exhaled); fputs(name, gas_exhaled); } void midipix_asm_generate_internal_label ( char * strbuf, const char * prefix, unsigned long number) { sprintf (strbuf, "*%s%s%ld", LOCAL_LABEL_PREFIX, prefix, number); } static void midipix_pe_create_got_entry(FILE * stream, const char * name, tree decl) { const char * ptrsize = TARGET_64BIT ? winnt_ptrsize_quad : winnt_ptrsize_long; fputs("\n",stream); fputs(GAS_SECTION,stream); if (decl->decl_with_vis.weak_flag) { fputs(GOT_SECTION_NAME,stream); } else if (decl->decl_with_vis.visibility == VISIBILITY_INTERNAL) { fputs(INTERNAL_SECTION_NAME,stream); } else { fputs(GOT_SECTION_NAME,stream); } fputs("$",stream); assemble_name(stream,name); fputs(GOT_SECTION_ATTR,stream); if (decl->decl_with_vis.weak_flag) fputs("\n\t.global __imp_",stream); else fputs("\n\t.global __imp_",stream); assemble_name(stream,name); fputs("\n__imp_",stream); assemble_name(stream,name); fputs(":\n\t",stream); fputs(ptrsize,stream); fputs("\t",stream); assemble_name(stream,name); fputs("\n",stream); fputs("\t.linkonce discard\n\n",stream); } void midipix_asm_output_got_entry( FILE * asmout, const char * name, tree decl, section * sect) { if (!decl->base.public_flag) return; /* .got entry */ midipix_pe_create_got_entry(asmout,name,decl); /* re-establish generic named section */ if (in_section && in_section->common.flags & (SECTION_STYLE_MASK == SECTION_NAMED)) targetm.asm_out.named_section( in_section->named.name, in_section->named.common.flags, in_section->named.decl); /* re-establish .bss section */ else if ((sect == bss_noswitch_section) || (in_section == bss_noswitch_section)) fputs("\t.bss\n",asmout); /* re-establish .data section */ else if ((sect == data_section) || (sect == data_section)) fputs("\t.data\n",asmout); /* re-establish .text section (default) */ else fputs("\t.text\n",asmout); flag_got_established_section = 1; } void midipix_asm_declare_object_name(FILE * gas_exhaled, const char * name, tree decl) { extern void assemble_name (FILE *, const char *); extern void i386_pe_maybe_record_exported_symbol (tree, const char *, int); i386_pe_maybe_record_exported_symbol(decl, name, true); assemble_name(gas_exhaled, name); fputs (":\n", gas_exhaled); } void midipix_asm_drectve_section(void) { extern FILE * asm_out_file; extern section * in_section; in_section = (section *)0; fprintf (asm_out_file, "%s%s\n", GAS_SECTION, DRECTVE_SECTION_NAME); } int midipix_target_use_local_thunk_alias(tree decl) { return !DECL_ONE_ONLY(decl); } void midipix_asm_output_external( FILE * asmout __attribute__((unused)), tree decl, const char * name) { if (decl->base.code == FUNCTION_DECL) i386_pe_record_external_function( decl,name); } void midipix_asm_output_external_libcall (FILE * asmout, rtx fn) { i386_pe_declare_function_type( asmout, XSTR(fn,0), true); } void midipix_asm_output_def_from_decls( FILE * asmout, tree decl, tree target) { const char * sym; sym = (const char *)decl->decl_with_vis.assembler_name->identifier.id.str; i386_pe_maybe_record_exported_symbol( decl,sym,false); if (decl->base.code == FUNCTION_DECL) i386_pe_declare_function_type( asmout,sym,decl->base.public_flag); ASM_OUTPUT_DEF( asmout, sym, IDENTIFIER_POINTER(target)); if (!decl->decl_with_vis.weak_flag) midipix_asm_output_got_entry(asmout,sym,decl,0); } /* visibility */ void midipix_i386_pe_assemble_visibility ( tree decl __attribute__((unused)), int visible __attribute__((unused))) { /* cf. midipix_pe_create_got_entry */ } /* seh hook selectors */ void midipix_seh_hook__pe_seh_init(FILE * f) { if (TARGET_SEH_WINNT) winnt_x86_64_pe_seh_init(f); else if (TARGET_SEH_MIDIPIX) midipix_i386_pe_seh_init(f); } void midipix_seh_hook__pe_seh_end_prologue(FILE * f) { if (TARGET_SEH_WINNT) winnt_x86_64_pe_seh_end_prologue(f); else if (TARGET_SEH_MIDIPIX) midipix_i386_pe_seh_end_prologue(f); } void midipix_seh_hook__pe_seh_unwind_emit(FILE * f, rtx r) { if (TARGET_SEH_WINNT) winnt_x86_64_pe_seh_unwind_emit(f,r); else if (TARGET_SEH_MIDIPIX) midipix_i386_pe_seh_unwind_emit(f,r); } void midipix_seh_hook__pe_seh_emit_except_personality(rtx r) { if (TARGET_SEH_WINNT) winnt_x86_64_pe_seh_emit_except_personality(r); else if (TARGET_SEH_MIDIPIX) midipix_i386_pe_seh_emit_except_personality(r); } void midipix_seh_hook__pe_seh_init_sections(void) { if (TARGET_SEH_WINNT) winnt_x86_64_pe_seh_init_sections(); else if (TARGET_SEH_MIDIPIX) midipix_i386_pe_seh_init_sections(); } /* 64-bit seh hooks (winnt) */ void winnt_x86_64_pe_seh_init(FILE * f) { i386_pe_seh_init(f); } void winnt_x86_64_pe_seh_end_prologue(FILE * f) { i386_pe_seh_end_prologue(f); } void winnt_x86_64_pe_seh_unwind_emit(FILE * f, rtx r) { i386_pe_seh_unwind_emit(f,r); } void winnt_x86_64_pe_seh_emit_except_personality(rtx r __attribute__((unused))) { /* i386_pe_seh_emit_except_personality(r); */ } void winnt_x86_64_pe_seh_init_sections(void) { /* i386_pe_seh_init_sections(); */ } /* 32-bit seh hooks (midipix) */ void midipix_i386_pe_seh_init(FILE * f __attribute__((unused))) { } void midipix_i386_pe_seh_end_prologue(FILE * f __attribute__((unused))) { } void midipix_i386_pe_seh_unwind_emit( FILE * f __attribute__((unused)), rtx r __attribute__((unused))) { } void midipix_i386_pe_seh_emit_except_personality(rtx r __attribute__((unused))) { } void midipix_i386_pe_seh_init_sections(void) { } section * midipix_i386_pe_function_section ( tree decl, enum node_frequency freq, bool startup, bool exit) { extern section * default_function_section ( tree decl, enum node_frequency freq, bool startup, bool exit); const char * fname; bool weak; section * asm_section; char * secname; size_t size; /* .got entry */ fname = (const char *)decl->decl_with_vis.assembler_name->identifier.id.str; weak = (decl->decl_with_vis.dllimport_flag && decl->decl_with_vis.weak_flag); /* section entry */ #ifdef MIDIPIX_TARGET_DEBUG fputs ("\t# <", asm_out_file); assemble_name (asm_out_file, fname); fputs (": section>\n", asm_out_file); #endif if (weak) { #ifdef MIDIPIX_TARGET_DEBUG fputs("\t# (weak symbol section)\n",asm_out_file); #endif size = strlen(fname) + 6; /* .text$ */ if (!(secname = (char *)xmalloc(size))) gcc_unreachable(); sprintf(secname,".text$%s",fname); asm_section = get_named_section(decl, secname, 1); free(secname); } else if (decl) { #ifdef MIDIPIX_TARGET_DEBUG fputs("\t# (strong symbol section)\n",asm_out_file); #endif asm_section = default_function_section(decl, freq, startup, exit); } else { fputs("\t# should never get here?\n",asm_out_file); asm_section = (section *)0; } #ifdef MIDIPIX_TARGET_DEBUG fputs ("\t# \n", asm_out_file); #endif return asm_section; } void midipix_i386_pe_asm_output_aligned_decl_common( FILE * stream, tree decl, const char * name, HOST_WIDE_INT size, HOST_WIDE_INT align) { i386_pe_asm_output_aligned_decl_common( stream,decl,name,size,align); } void midipix_i386_pe_start_function (FILE * gas_exhaled, const char *name, tree decl) { #ifdef MIDIPIX_TARGET_DEBUG fputs ("\t# <", gas_exhaled); assemble_name (gas_exhaled, name); fputs (">\n", gas_exhaled); #endif i386_pe_start_function (gas_exhaled, name, decl); } void midipix_i386_pe_end_function (FILE * gas_exhaled, const char * name, tree decl) { if (cfun->is_thunk) return; if (TARGET_SEH) fputs ("\t.seh_endproc\n", gas_exhaled); /* avoid duplicate GOT entries */ if (decl && !decl->decl_with_vis.weak_flag) midipix_asm_output_got_entry(gas_exhaled,name,decl,0); } void midipix_i386_pe_asm_weaken_decl( FILE * gas_exhaled, tree decl, const char * name, const char * alias __attribute__((unused))) { midipix_asm_output_got_entry(gas_exhaled,name,decl,0); fputs ("\t.weak\t", gas_exhaled); assemble_name (gas_exhaled, name); fputs ("\n", gas_exhaled); } void midipix_i386_pe_asm_weaken_label(FILE * gas_exhaled, const char * name) { midipix_i386_pe_asm_weaken_decl( gas_exhaled, (tree)0, name, (const char *)0); } int midipix_symbol_ref_dllimport_p(rtx symbol) { tree decl = SYMBOL_REF_DECL(symbol); return decl && decl->base.public_flag && (!decl->decl_with_vis.visibility_specified || (decl->decl_with_vis.visibility == VISIBILITY_DEFAULT)); }