| 1 | /* seh pdata/xdata coff object file format |
| 2 | Copyright (C) 2009-2019 Free Software Foundation, Inc. |
| 3 | |
| 4 | This file is part of GAS. |
| 5 | |
| 6 | GAS is free software; you can redistribute it and/or modify |
| 7 | it under the terms of the GNU General Public License as published by |
| 8 | the Free Software Foundation; either version 3, or (at your option) |
| 9 | any later version. |
| 10 | |
| 11 | GAS is distributed in the hope that it will be useful, |
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | GNU General Public License for more details. |
| 15 | |
| 16 | You should have received a copy of the GNU General Public License |
| 17 | along with GAS; see the file COPYING. If not, write to the Free |
| 18 | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
| 19 | 02110-1301, USA. */ |
| 20 | |
| 21 | /* Short overview: |
| 22 | There are at the moment three different function entry formats preset. |
| 23 | The first is the MIPS one. The second version |
| 24 | is for ARM, PPC, SH3, and SH4 mainly for Windows CE. |
| 25 | The third is the IA64 and x64 version. Note, the IA64 isn't implemented yet, |
| 26 | but to find information about it, please see specification about IA64 on |
| 27 | http://download.intel.com/design/Itanium/Downloads/245358.pdf file. |
| 28 | |
| 29 | The first version has just entries in the pdata section: BeginAddress, |
| 30 | EndAddress, ExceptionHandler, HandlerData, and PrologueEndAddress. Each |
| 31 | value is a pointer to the corresponding data and has size of 4 bytes. |
| 32 | |
| 33 | The second variant has the following entries in the pdata section. |
| 34 | BeginAddress, PrologueLength (8 bits), EndAddress (22 bits), |
| 35 | Use-32-bit-instruction (1 bit), and Exception-Handler-Exists (1 bit). |
| 36 | If the FunctionLength is zero, or the Exception-Handler-Exists bit |
| 37 | is true, a PDATA_EH block is placed directly before function entry. |
| 38 | |
| 39 | The third version has a function entry block of BeginAddress (RVA), |
| 40 | EndAddress (RVA), and UnwindData (RVA). The description of the |
| 41 | prologue, exception-handler, and additional SEH data is stored |
| 42 | within the UNWIND_DATA field in the xdata section. |
| 43 | |
| 44 | The pseudos: |
| 45 | .seh_proc <fct_name> |
| 46 | .seh_endprologue |
| 47 | .seh_handler <handler>[,@unwind][,@except] (x64) |
| 48 | .seh_handler <handler>[,<handler_data>] (others) |
| 49 | .seh_handlerdata |
| 50 | .seh_eh |
| 51 | .seh_32/.seh_no32 |
| 52 | .seh_endproc |
| 53 | .seh_setframe <reg>,<offset> |
| 54 | .seh_stackalloc |
| 55 | .seh_pushreg |
| 56 | .seh_savereg |
| 57 | .seh_savexmm |
| 58 | .seh_pushframe |
| 59 | .seh_code |
| 60 | */ |
| 61 | |
| 62 | /* architecture specific pdata/xdata handling. */ |
| 63 | #define SEH_CMDS \ |
| 64 | {"seh_proc", obj_coff_seh_proc, 0}, \ |
| 65 | {"seh_endproc", obj_coff_seh_endproc, 0}, \ |
| 66 | {"seh_pushreg", obj_coff_seh_pushreg, 0}, \ |
| 67 | {"seh_savereg", obj_coff_seh_save, 1}, \ |
| 68 | {"seh_savexmm", obj_coff_seh_save, 2}, \ |
| 69 | {"seh_pushframe", obj_coff_seh_pushframe, 0}, \ |
| 70 | {"seh_endprologue", obj_coff_seh_endprologue, 0}, \ |
| 71 | {"seh_setframe", obj_coff_seh_setframe, 0}, \ |
| 72 | {"seh_stackalloc", obj_coff_seh_stackalloc, 0}, \ |
| 73 | {"seh_eh", obj_coff_seh_eh, 0}, \ |
| 74 | {"seh_32", obj_coff_seh_32, 1}, \ |
| 75 | {"seh_no32", obj_coff_seh_32, 0}, \ |
| 76 | {"seh_handler", obj_coff_seh_handler, 0}, \ |
| 77 | {"seh_code", obj_coff_seh_code, 0}, \ |
| 78 | {"seh_handlerdata", obj_coff_seh_handlerdata, 0}, |
| 79 | |
| 80 | /* Type definitions. */ |
| 81 | |
| 82 | typedef struct seh_prologue_element |
| 83 | { |
| 84 | int code; |
| 85 | int info; |
| 86 | offsetT off; |
| 87 | symbolS *pc_addr; |
| 88 | } seh_prologue_element; |
| 89 | |
| 90 | typedef struct seh_context |
| 91 | { |
| 92 | struct seh_context *next; |
| 93 | |
| 94 | /* Initial code-segment. */ |
| 95 | segT code_seg; |
| 96 | /* Function name. */ |
| 97 | char *func_name; |
| 98 | /* BeginAddress. */ |
| 99 | symbolS *start_addr; |
| 100 | /* EndAddress. */ |
| 101 | symbolS *end_addr; |
| 102 | /* Unwind data. */ |
| 103 | symbolS *xdata_addr; |
| 104 | /* PrologueEnd. */ |
| 105 | symbolS *endprologue_addr; |
| 106 | /* ExceptionHandler. */ |
| 107 | expressionS handler; |
| 108 | /* ExceptionHandlerData. (arm, mips) */ |
| 109 | expressionS handler_data; |
| 110 | |
| 111 | /* ARM .seh_eh directive seen. */ |
| 112 | int handler_written; |
| 113 | |
| 114 | /* WinCE specific data. */ |
| 115 | int use_instruction_32; |
| 116 | /* Was record already processed. */ |
| 117 | int done; |
| 118 | |
| 119 | /* x64 flags for the xdata header. */ |
| 120 | int handler_flags; |
| 121 | int subsection; |
| 122 | |
| 123 | /* x64 framereg and frame offset information. */ |
| 124 | int framereg; |
| 125 | int frameoff; |
| 126 | |
| 127 | /* Information about x64 specific unwind data fields. */ |
| 128 | int elems_count; |
| 129 | int elems_max; |
| 130 | seh_prologue_element *elems; |
| 131 | } seh_context; |
| 132 | |
| 133 | typedef enum seh_kind { |
| 134 | seh_kind_unknown = 0, |
| 135 | seh_kind_mips = 1, /* Used for MIPS and x86 pdata generation. */ |
| 136 | seh_kind_arm = 2, /* Used for ARM, PPC, SH3, and SH4 pdata (PDATA_EH) generation. */ |
| 137 | seh_kind_x64 = 3 /* Used for IA64 and x64 pdata/xdata generation. */ |
| 138 | } seh_kind; |
| 139 | |
| 140 | /* Forward declarations. */ |
| 141 | static void obj_coff_seh_stackalloc (int); |
| 142 | static void obj_coff_seh_setframe (int); |
| 143 | static void obj_coff_seh_endprologue (int); |
| 144 | static void obj_coff_seh_save (int); |
| 145 | static void obj_coff_seh_pushreg (int); |
| 146 | static void obj_coff_seh_pushframe (int); |
| 147 | static void obj_coff_seh_endproc (int); |
| 148 | static void obj_coff_seh_eh (int); |
| 149 | static void obj_coff_seh_32 (int); |
| 150 | static void obj_coff_seh_proc (int); |
| 151 | static void obj_coff_seh_handler (int); |
| 152 | static void obj_coff_seh_handlerdata (int); |
| 153 | static void obj_coff_seh_code (int); |
| 154 | |
| 155 | #define UNDSEC bfd_und_section_ptr |
| 156 | |
| 157 | /* Check if x64 UNW_... macros are already defined. */ |
| 158 | #ifndef PEX64_FLAG_NHANDLER |
| 159 | /* We can't include here coff/pe.h header. So we have to copy macros |
| 160 | from coff/pe.h here. */ |
| 161 | #define PEX64_UNWCODE_CODE(VAL) ((VAL) & 0xf) |
| 162 | #define PEX64_UNWCODE_INFO(VAL) (((VAL) >> 4) & 0xf) |
| 163 | |
| 164 | /* The unwind info. */ |
| 165 | #define UNW_FLAG_NHANDLER 0 |
| 166 | #define UNW_FLAG_EHANDLER 1 |
| 167 | #define UNW_FLAG_UHANDLER 2 |
| 168 | #define UNW_FLAG_FHANDLER 3 |
| 169 | #define UNW_FLAG_CHAININFO 4 |
| 170 | |
| 171 | #define UNW_FLAG_MASK 0x1f |
| 172 | |
| 173 | /* The unwind codes. */ |
| 174 | #define UWOP_PUSH_NONVOL 0 |
| 175 | #define UWOP_ALLOC_LARGE 1 |
| 176 | #define UWOP_ALLOC_SMALL 2 |
| 177 | #define UWOP_SET_FPREG 3 |
| 178 | #define UWOP_SAVE_NONVOL 4 |
| 179 | #define UWOP_SAVE_NONVOL_FAR 5 |
| 180 | #define UWOP_SAVE_XMM 6 |
| 181 | #define UWOP_SAVE_XMM_FAR 7 |
| 182 | #define UWOP_SAVE_XMM128 8 |
| 183 | #define UWOP_SAVE_XMM128_FAR 9 |
| 184 | #define UWOP_PUSH_MACHFRAME 10 |
| 185 | |
| 186 | #define PEX64_UWI_VERSION(VAL) ((VAL) & 7) |
| 187 | #define PEX64_UWI_FLAGS(VAL) (((VAL) >> 3) & 0x1f) |
| 188 | #define PEX64_UWI_FRAMEREG(VAL) ((VAL) & 0xf) |
| 189 | #define PEX64_UWI_FRAMEOFF(VAL) (((VAL) >> 4) & 0xf) |
| 190 | #define PEX64_UWI_SIZEOF_UWCODE_ARRAY(VAL) \ |
| 191 | ((((VAL) + 1) & ~1) * 2) |
| 192 | |
| 193 | #define PEX64_OFFSET_TO_UNWIND_CODE 0x4 |
| 194 | |
| 195 | #define PEX64_OFFSET_TO_HANDLER_RVA (COUNTOFUNWINDCODES) \ |
| 196 | (PEX64_OFFSET_TO_UNWIND_CODE + \ |
| 197 | PEX64_UWI_SIZEOF_UWCODE_ARRAY(COUNTOFUNWINDCODES)) |
| 198 | |
| 199 | #define PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) \ |
| 200 | (PEX64_OFFSET_TO_HANDLER_RVA(COUNTOFUNWINDCODES) + 4) |
| 201 | |
| 202 | #define PEX64_SCOPE_ENTRY(COUNTOFUNWINDCODES, IDX) \ |
| 203 | (PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \ |
| 204 | PEX64_SCOPE_ENTRY_SIZE * (IDX)) |
| 205 | |
| 206 | #endif |