| /* seh pdata/xdata coff object file format |
| Copyright 2009 |
| Free Software Foundation, Inc. |
| |
| This file is part of GAS. |
| |
| GAS 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, or (at your option) |
| any later version. |
| |
| GAS 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 GAS; see the file COPYING. If not, write to the Free |
| Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
| 02110-1301, USA. */ |
| |
| /* Short overview: |
| There are at the moment three different function entry formats preset. |
| The first is the MIPS one. The second version |
| is for ARM, PPC, SH3, and SH4 mainly for Windows CE. |
| The third is the IA64 and x64 version. Note, the IA64 isn't implemented yet, |
| but to find information about it, please see specification about IA64 on |
| http://download.intel.com/design/Itanium/Downloads/245358.pdf file. |
| |
| The first version has just entries in the pdata section: BeginAddress, |
| EndAddress, ExceptionHandler, HandlerData, and PrologueEndAddress. Each |
| value is a pointer to the corresponding data and has size of 4 bytes. |
| |
| The second variant has the following entries in the pdata section. |
| BeginAddress, PrologueLength (8 bits), EndAddress (22 bits), |
| Use-32-bit-instruction (1 bit), and Exception-Handler-Exists (1 bit). |
| If the FunctionLength is zero, or the Exception-Handler-Exists bit |
| is true, a PDATA_EH block is placed directly before function entry. |
| |
| The third version has a function entry block of BeginAddress (RVA), |
| EndAddress (RVA), and UnwindData (RVA). The description of the |
| prologue, excepetion-handler, and additional SEH data is stored |
| within the UNWIND_DATA field in the xdata section. |
| |
| The pseudos: |
| .seh_proc <fct_name> |
| .seh_endprologue |
| .seh_handler <handler>[,<handler-data>]] |
| .seh_eh |
| .seh_32/.seh_no32 |
| .seh_endproc |
| .seh_setframe <reg>,<offset> |
| .seh_stackalloc |
| .seh_pushreg |
| .seh_savereg |
| .seh_savemm |
| .seh_savexmm |
| .seh_pushframe |
| .seh_scope |
| */ |
| |
| /* architecture specific pdata/xdata handling. */ |
| #define SEH_CMDS \ |
| {"seh_proc", obj_coff_seh_proc, 0}, \ |
| {"seh_endproc", obj_coff_seh_endproc, 0}, \ |
| {"seh_pushreg", obj_coff_seh_push, 0}, \ |
| {"seh_savereg", obj_coff_seh_save, 0}, \ |
| {"seh_savemm", obj_coff_seh_save, 1}, \ |
| {"seh_savexmm", obj_coff_seh_save, 2}, \ |
| {"seh_pushframe", obj_coff_seh_push, 1}, \ |
| {"seh_endprologue", obj_coff_seh_endprologue, 0}, \ |
| {"seh_setframe", obj_coff_seh_setframe, 0}, \ |
| {"seh_stackalloc", obj_coff_seh_stack_alloc, 0}, \ |
| {"seh_handler", obj_coff_seh_handler, 0}, \ |
| {"seh_eh", obj_coff_seh_eh, 0}, \ |
| {"seh_32", obj_coff_seh_32, 1}, \ |
| {"seh_no32", obj_coff_seh_32, 0}, \ |
| {"seh_scope", obj_coff_seh_scope, 0}, |
| |
| /* Type definitions. */ |
| |
| typedef struct seh_prologue_element |
| { |
| symbolS *pc_addr; |
| char *pc_symbol; |
| int kind; |
| int reg; |
| bfd_vma offset; |
| } seh_prologue_element; |
| |
| typedef struct seh_scope_elem { |
| char *begin_addr; |
| char *end_addr; |
| char *handler_addr; |
| char *jump_addr; |
| } seh_scope_elem; |
| |
| typedef struct seh_context |
| { |
| struct seh_context *next; |
| /* Was record alread processed. */ |
| int done; |
| /* Function name. */ |
| char *func_name; |
| /* BeginAddress. */ |
| char *start_symbol; |
| symbolS *start_addr; |
| bfd_vma start_offset; |
| /* EndAddress. */ |
| char *end_symbol; |
| symbolS *end_addr; |
| bfd_vma end_offset; |
| /* PrologueEnd. */ |
| char *endprologue_symbol; |
| symbolS *endprologue_addr; |
| bfd_vma endprologue_offset; |
| /* ExceptionHandler. */ |
| char *handler_name; |
| /* ExceptionHandlerData. */ |
| char *handler_data_name; |
| int handler_written; |
| /* WinCE specific data. */ |
| int use_instruction_32; |
| |
| /* the bfd to store data within. */ |
| bfd *abfd; |
| /* the current section to generate data within. */ |
| asection *section; |
| /* Relocations for section. */ |
| unsigned int count_reloc; |
| /* Symbols within section. */ |
| unsigned int count_syms; |
| /* Iterator for text lable generation. */ |
| unsigned int tlbl_count; |
| /* Iterator for xdata lable generation. */ |
| unsigned int xlbl_count; |
| /* The name of the first xdata label. */ |
| char *xdata_first; |
| /* FIelds used for x64 generation of chained information. */ |
| char **xdata_names; |
| char **xdata_pcsyms; |
| int *xdata_elm_start; |
| /* Size and offset within current generated xdata section. */ |
| size_t xdata_sz; |
| size_t xdata_offset; |
| /* x64 framereg and frame offset information. */ |
| int framereg; |
| bfd_vma frameoff; |
| /* Information about x64 specific unwind data fields. */ |
| size_t elems_count; |
| size_t elems_max; |
| seh_prologue_element *elems; |
| size_t scope_max; |
| size_t scope_count; |
| seh_scope_elem *scopes; |
| } seh_context; |
| |
| typedef enum seh_kind { |
| seh_kind_unknown = 0, |
| seh_kind_mips = 1, /* Used for MIPS and x86 pdata generation. */ |
| seh_kind_arm = 2, /* Used for ARM, PPC, SH3, and SH4 pdata (PDATA_EH) generation. */ |
| seh_kind_x64 = 3 /* Used for IA64 and x64 pdata/xdata generation. */ |
| } seh_kind; |
| |
| /* Forward declarations. */ |
| static void obj_coff_seh_stack_alloc (int); |
| static void obj_coff_seh_setframe (int); |
| static void obj_coff_seh_endprologue (int); |
| static void obj_coff_seh_save (int); |
| static void obj_coff_seh_push (int); |
| static void obj_coff_seh_endproc (int); |
| static void obj_coff_seh_eh (int); |
| static void obj_coff_seh_32 (int); |
| static void obj_coff_seh_proc (int); |
| static void obj_coff_seh_handler (int); |
| static void obj_coff_seh_scope (int); |
| static int seh_read_offset (const char *, bfd_vma *); |
| static int seh_x64_read_reg (const char *, int, int *); |
| static void seh_x64_make_prologue_element (int, int, bfd_vma); |
| static void make_function_entry_pdata (seh_context *c); |
| |
| #define UNDSEC (asection *) &bfd_und_section |
| |
| /* Check if x64 UNW_... macros are already defined. */ |
| #ifndef PEX64_FLAG_NHANDLER |
| /* We can't include here coff/pe.h header. So we have to copy macros |
| from coff/pe.h here. */ |
| #define PEX64_UNWCODE_CODE(VAL) ((VAL) & 0xf) |
| #define PEX64_UNWCODE_INFO(VAL) (((VAL) >> 4) & 0xf) |
| |
| /* The unwind info. */ |
| #define UNW_FLAG_NHANDLER 0 |
| #define UNW_FLAG_EHANDLER 1 |
| #define UNW_FLAG_UHANDLER 2 |
| #define UNW_FLAG_FHANDLER 3 |
| #define UNW_FLAG_CHAININFO 4 |
| |
| #define UNW_FLAG_MASK 0x1f |
| |
| /* The unwind codes. */ |
| #define UWOP_PUSH_NONVOL 0 |
| #define UWOP_ALLOC_LARGE 1 |
| #define UWOP_ALLOC_SMALL 2 |
| #define UWOP_SET_FPREG 3 |
| #define UWOP_SAVE_NONVOL 4 |
| #define UWOP_SAVE_NONVOL_FAR 5 |
| #define UWOP_SAVE_XMM 6 |
| #define UWOP_SAVE_XMM_FAR 7 |
| #define UWOP_SAVE_XMM128 8 |
| #define UWOP_SAVE_XMM128_FAR 9 |
| #define UWOP_PUSH_MACHFRAME 10 |
| |
| #define PEX64_UWI_VERSION(VAL) ((VAL) & 7) |
| #define PEX64_UWI_FLAGS(VAL) (((VAL) >> 3) & 0x1f) |
| #define PEX64_UWI_FRAMEREG(VAL) ((VAL) & 0xf) |
| #define PEX64_UWI_FRAMEOFF(VAL) (((VAL) >> 4) & 0xf) |
| #define PEX64_UWI_SIZEOF_UWCODE_ARRAY(VAL) \ |
| ((((VAL) + 1) & ~1) * 2) |
| |
| #define PEX64_OFFSET_TO_UNWIND_CODE 0x4 |
| |
| #define PEX64_OFFSET_TO_HANDLER_RVA (COUNTOFUNWINDCODES) \ |
| (PEX64_OFFSET_TO_UNWIND_CODE + \ |
| PEX64_UWI_SIZEOF_UWCODE_ARRAY(COUNTOFUNWINDCODES)) |
| |
| #define PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) \ |
| (PEX64_OFFSET_TO_HANDLER_RVA(COUNTOFUNWINDCODES) + 4) |
| |
| #define PEX64_SCOPE_ENTRY(COUNTOFUNWINDCODES, IDX) \ |
| (PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \ |
| PEX64_SCOPE_ENTRY_SIZE * (IDX)) |
| |
| #endif |
| |