1 /* a.out object file format 2 Copyright (C) 1989-2024 Free Software Foundation, Inc. 3 4 This file is part of GAS, the GNU Assembler. 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 8 published by the Free Software Foundation; either version 3, 9 or (at your option) any later version. 10 11 GAS is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 14 the 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 #define OBJ_HEADER "obj-aout.h" 22 23 #include "as.h" 24 #undef NO_RELOC 25 #include "aout/aout64.h" 26 27 void 28 obj_aout_frob_symbol (symbolS *sym, int *punt ATTRIBUTE_UNUSED) 29 { 30 flagword flags; 31 asection *sec; 32 int type; 33 34 flags = symbol_get_bfdsym (sym)->flags; 35 type = aout_symbol (symbol_get_bfdsym (sym))->type; 36 sec = S_GET_SEGMENT (sym); 37 38 /* Only frob simple symbols this way right now. */ 39 if (! (type & ~ (N_TYPE | N_EXT))) 40 { 41 if (type == (N_UNDF | N_EXT) 42 && sec == bfd_abs_section_ptr) 43 { 44 sec = bfd_und_section_ptr; 45 S_SET_SEGMENT (sym, sec); 46 } 47 48 if ((type & N_TYPE) != N_INDR 49 && (type & N_TYPE) != N_SETA 50 && (type & N_TYPE) != N_SETT 51 && (type & N_TYPE) != N_SETD 52 && (type & N_TYPE) != N_SETB 53 && type != N_WARNING 54 && (sec == bfd_abs_section_ptr 55 || sec == bfd_und_section_ptr)) 56 return; 57 if (flags & BSF_EXPORT) 58 type |= N_EXT; 59 60 switch (type & N_TYPE) 61 { 62 case N_SETA: 63 case N_SETT: 64 case N_SETD: 65 case N_SETB: 66 /* Set the debugging flag for constructor symbols so that 67 BFD leaves them alone. */ 68 symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 69 70 /* You can't put a common symbol in a set. The way a set 71 element works is that the symbol has a definition and a 72 name, and the linker adds the definition to the set of 73 that name. That does not work for a common symbol, 74 because the linker can't tell which common symbol the 75 user means. FIXME: Using as_bad here may be 76 inappropriate, since the user may want to force a 77 particular type without regard to the semantics of sets; 78 on the other hand, we certainly don't want anybody to be 79 mislead into thinking that their code will work. */ 80 if (S_IS_COMMON (sym)) 81 as_bad (_("Attempt to put a common symbol into set %s"), 82 S_GET_NAME (sym)); 83 /* Similarly, you can't put an undefined symbol in a set. */ 84 else if (! S_IS_DEFINED (sym)) 85 as_bad (_("Attempt to put an undefined symbol into set %s"), 86 S_GET_NAME (sym)); 87 88 break; 89 case N_INDR: 90 /* Put indirect symbols in the indirect section. */ 91 S_SET_SEGMENT (sym, bfd_ind_section_ptr); 92 symbol_get_bfdsym (sym)->flags |= BSF_INDIRECT; 93 if (type & N_EXT) 94 { 95 symbol_get_bfdsym (sym)->flags |= BSF_EXPORT; 96 symbol_get_bfdsym (sym)->flags &=~ BSF_LOCAL; 97 } 98 break; 99 case N_WARNING: 100 /* Mark warning symbols. */ 101 symbol_get_bfdsym (sym)->flags |= BSF_WARNING; 102 break; 103 } 104 } 105 else 106 symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; 107 108 aout_symbol (symbol_get_bfdsym (sym))->type = type; 109 110 /* Double check weak symbols. */ 111 if (S_IS_WEAK (sym) && S_IS_COMMON (sym)) 112 as_bad (_("Symbol `%s' can not be both weak and common"), 113 S_GET_NAME (sym)); 114 } 115 116 /* Relocation processing may require knowing the VMAs of the sections. 117 Writing to a section will cause the BFD back end to compute the 118 VMAs. This function also ensures that file size is large enough 119 to cover a_text and a_data should text or data be the last section 120 in the file. */ 121 122 void 123 obj_aout_frob_file_before_fix (void) 124 { 125 asection *sec; 126 bfd_vma *sizep = NULL; 127 if ((sec = data_section)->size != 0) 128 sizep = &exec_hdr (stdoutput)->a_data; 129 else if ((sec = text_section)->size != 0) 130 sizep = &exec_hdr (stdoutput)->a_text; 131 if (sizep) 132 { 133 bfd_size_type size = sec->size; 134 bfd_byte b = 0; 135 136 gas_assert (bfd_set_section_contents (stdoutput, sec, &b, size - 1, 1)); 137 138 /* We don't know the aligned size until after VMAs and sizes are 139 set on the bfd_set_section_contents call. If that size is 140 larger than the section then write again to ensure the file 141 contents extend to cover the aligned size. */ 142 if (*sizep > size) 143 { 144 file_ptr pos = sec->filepos + *sizep; 145 146 gas_assert (bfd_seek (stdoutput, pos - 1, SEEK_SET) == 0 147 && bfd_write (&b, 1, stdoutput) == 1); 148 } 149 } 150 } 151 152 static void 153 obj_aout_line (int ignore ATTRIBUTE_UNUSED) 154 { 155 /* Assume delimiter is part of expression. 156 BSD4.2 as fails with delightful bug, so we 157 are not being incompatible here. */ 158 new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); 159 demand_empty_rest_of_line (); 160 } 161 162 /* Handle .weak. This is a GNU extension. */ 163 164 static void 165 obj_aout_weak (int ignore ATTRIBUTE_UNUSED) 166 { 167 char *name; 168 int c; 169 symbolS *symbolP; 170 171 do 172 { 173 c = get_symbol_name (&name); 174 symbolP = symbol_find_or_make (name); 175 (void) restore_line_pointer (c); 176 SKIP_WHITESPACE (); 177 S_SET_WEAK (symbolP); 178 if (c == ',') 179 { 180 input_line_pointer++; 181 SKIP_WHITESPACE (); 182 if (*input_line_pointer == '\n') 183 c = '\n'; 184 } 185 } 186 while (c == ','); 187 demand_empty_rest_of_line (); 188 } 189 190 /* Handle .type. On {Net,Open}BSD, this is used to set the n_other field, 191 which is then apparently used when doing dynamic linking. Older 192 versions of gas ignored the .type pseudo-op, so we also ignore it if 193 we can't parse it. */ 194 195 static void 196 obj_aout_type (int ignore ATTRIBUTE_UNUSED) 197 { 198 char *name; 199 int c; 200 symbolS *sym; 201 202 c = get_symbol_name (&name); 203 sym = symbol_find_or_make (name); 204 (void) restore_line_pointer (c); 205 SKIP_WHITESPACE (); 206 if (*input_line_pointer == ',') 207 { 208 ++input_line_pointer; 209 SKIP_WHITESPACE (); 210 if (*input_line_pointer == '@') 211 { 212 ++input_line_pointer; 213 if (startswith (input_line_pointer, "object")) 214 S_SET_OTHER (sym, 1); 215 else if (startswith (input_line_pointer, "function")) 216 S_SET_OTHER (sym, 2); 217 } 218 } 219 220 /* Ignore everything else on the line. */ 221 s_ignore (0); 222 } 223 224 /* Support for an AOUT emulation. */ 225 226 static void 227 aout_pop_insert (void) 228 { 229 pop_insert (aout_pseudo_table); 230 } 231 232 static int 233 obj_aout_s_get_other (symbolS *sym) 234 { 235 return aout_symbol (symbol_get_bfdsym (sym))->other; 236 } 237 238 static void 239 obj_aout_s_set_other (symbolS *sym, int o) 240 { 241 aout_symbol (symbol_get_bfdsym (sym))->other = o; 242 } 243 244 static int 245 obj_aout_sec_sym_ok_for_reloc (asection *sec ATTRIBUTE_UNUSED) 246 { 247 return obj_sec_sym_ok_for_reloc (sec); 248 } 249 250 static void 251 obj_aout_process_stab (int w, 252 const char *s, 253 int t, 254 int o, 255 int d) 256 { 257 aout_process_stab (w, s, t, o, d); 258 } 259 260 static int 261 obj_aout_s_get_desc (symbolS *sym) 262 { 263 return aout_symbol (symbol_get_bfdsym (sym))->desc; 264 } 265 266 static void 267 obj_aout_s_set_desc (symbolS *sym, int d) 268 { 269 aout_symbol (symbol_get_bfdsym (sym))->desc = d; 270 } 271 272 static int 273 obj_aout_s_get_type (symbolS *sym) 274 { 275 return aout_symbol (symbol_get_bfdsym (sym))->type; 276 } 277 278 static void 279 obj_aout_s_set_type (symbolS *sym, int t) 280 { 281 aout_symbol (symbol_get_bfdsym (sym))->type = t; 282 } 283 284 static int 285 obj_aout_separate_stab_sections (void) 286 { 287 return 0; 288 } 289 290 /* When changed, make sure these table entries match the single-format 291 definitions in obj-aout.h. */ 292 293 const struct format_ops aout_format_ops = 294 { 295 bfd_target_aout_flavour, 296 1, /* dfl_leading_underscore. */ 297 0, /* emit_section_symbols. */ 298 0, /* begin. */ 299 0, /* end. */ 300 0, /* app_file. */ 301 obj_aout_frob_symbol, 302 0, /* frob_file. */ 303 0, /* frob_file_before_adjust. */ 304 obj_aout_frob_file_before_fix, 305 0, /* frob_file_after_relocs. */ 306 0, /* s_get_size. */ 307 0, /* s_set_size. */ 308 0, /* s_get_align. */ 309 0, /* s_set_align. */ 310 obj_aout_s_get_other, 311 obj_aout_s_set_other, 312 obj_aout_s_get_desc, 313 obj_aout_s_set_desc, 314 obj_aout_s_get_type, 315 obj_aout_s_set_type, 316 0, /* copy_symbol_attributes. */ 317 0, /* generate_asm_lineno. */ 318 obj_aout_process_stab, 319 obj_aout_separate_stab_sections, 320 0, /* init_stab_section. */ 321 obj_aout_sec_sym_ok_for_reloc, 322 aout_pop_insert, 323 0, /* ecoff_set_ext. */ 324 0, /* read_begin_hook. */ 325 0, /* symbol_new_hook. */ 326 0, /* symbol_clone_hook. */ 327 0 /* adjust_symtab. */ 328 }; 329 330 const pseudo_typeS aout_pseudo_table[] = 331 { 332 {"line", obj_aout_line, 0}, /* Source code line number. */ 333 {"ln", obj_aout_line, 0}, /* COFF line number that we use anyway. */ 334 335 {"weak", obj_aout_weak, 0}, /* Mark symbol as weak. */ 336 337 {"type", obj_aout_type, 0}, 338 339 /* coff debug pseudos (ignored) */ 340 {"def", s_ignore, 0}, 341 {"dim", s_ignore, 0}, 342 {"endef", s_ignore, 0}, 343 {"ident", s_ignore, 0}, 344 {"line", s_ignore, 0}, 345 {"ln", s_ignore, 0}, 346 {"scl", s_ignore, 0}, 347 {"size", s_ignore, 0}, 348 {"tag", s_ignore, 0}, 349 {"val", s_ignore, 0}, 350 {"version", s_ignore, 0}, 351 352 {"optim", s_ignore, 0}, /* For sun386i cc (?). */ 353 354 /* other stuff */ 355 {"ABORT", s_abort, 0}, 356 357 {NULL, NULL, 0} 358 }; 359