1 1.1 christos /* codeview.c - CodeView debug support 2 1.1.1.2 christos Copyright (C) 2022-2025 Free Software Foundation, Inc. 3 1.1 christos 4 1.1 christos This file is part of GAS, the GNU Assembler. 5 1.1 christos 6 1.1 christos GAS is free software; you can redistribute it and/or modify 7 1.1 christos it under the terms of the GNU General Public License as published by 8 1.1 christos the Free Software Foundation; either version 3, or (at your option) 9 1.1 christos any later version. 10 1.1 christos 11 1.1 christos GAS is distributed in the hope that it will be useful, 12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 christos GNU General Public License for more details. 15 1.1 christos 16 1.1 christos You should have received a copy of the GNU General Public License 17 1.1 christos along with GAS; see the file COPYING. If not, write to the Free 18 1.1 christos Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 19 1.1 christos 02110-1301, USA. */ 20 1.1 christos 21 1.1 christos #include "as.h" 22 1.1 christos #include "codeview.h" 23 1.1 christos #include "subsegs.h" 24 1.1 christos #include "filenames.h" 25 1.1 christos #include "md5.h" 26 1.1 christos 27 1.1 christos #if defined (TE_PE) && defined (O_secrel) 28 1.1 christos 29 1.1 christos #define NUM_MD5_BYTES 16 30 1.1 christos 31 1.1 christos #define FILE_ENTRY_PADDING 2 32 1.1 christos #define FILE_ENTRY_LENGTH (sizeof (struct file_checksum) + NUM_MD5_BYTES \ 33 1.1 christos + FILE_ENTRY_PADDING) 34 1.1 christos 35 1.1 christos struct line 36 1.1 christos { 37 1.1 christos struct line *next; 38 1.1 christos unsigned int lineno; 39 1.1 christos addressT frag_offset; 40 1.1 christos }; 41 1.1 christos 42 1.1 christos struct line_file 43 1.1 christos { 44 1.1 christos struct line_file *next; 45 1.1 christos unsigned int fileno; 46 1.1 christos struct line *lines_head, *lines_tail; 47 1.1 christos unsigned int num_lines; 48 1.1 christos }; 49 1.1 christos 50 1.1 christos struct line_block 51 1.1 christos { 52 1.1 christos struct line_block *next; 53 1.1 christos segT seg; 54 1.1 christos unsigned int subseg; 55 1.1 christos fragS *frag; 56 1.1 christos symbolS *sym; 57 1.1 christos struct line_file *files_head, *files_tail; 58 1.1 christos }; 59 1.1 christos 60 1.1 christos struct source_file 61 1.1 christos { 62 1.1 christos struct source_file *next; 63 1.1 christos unsigned int num; 64 1.1 christos char *filename; 65 1.1 christos uint32_t string_pos; 66 1.1 christos uint8_t md5[NUM_MD5_BYTES]; 67 1.1 christos }; 68 1.1 christos 69 1.1 christos static struct line_block *blocks_head = NULL, *blocks_tail = NULL; 70 1.1 christos static struct source_file *files_head = NULL, *files_tail = NULL; 71 1.1 christos static unsigned int num_source_files = 0; 72 1.1 christos 73 1.1 christos /* Return the size of the current fragment (taken from dwarf2dbg.c). */ 74 1.1 christos static offsetT 75 1.1 christos get_frag_fix (fragS *frag, segT seg) 76 1.1 christos { 77 1.1 christos frchainS *fr; 78 1.1 christos 79 1.1 christos if (frag->fr_next) 80 1.1 christos return frag->fr_fix; 81 1.1 christos 82 1.1 christos for (fr = seg_info (seg)->frchainP; fr; fr = fr->frch_next) 83 1.1 christos if (fr->frch_last == frag) 84 1.1 christos return (char *) obstack_next_free (&fr->frch_obstack) - frag->fr_literal; 85 1.1 christos 86 1.1 christos abort (); 87 1.1 christos } 88 1.1 christos 89 1.1 christos /* Emit a .secrel32 relocation. */ 90 1.1 christos static void 91 1.1 christos emit_secrel32_reloc (symbolS *sym) 92 1.1 christos { 93 1.1 christos expressionS exp; 94 1.1 christos 95 1.1 christos memset (&exp, 0, sizeof (exp)); 96 1.1 christos exp.X_op = O_secrel; 97 1.1 christos exp.X_add_symbol = sym; 98 1.1 christos exp.X_add_number = 0; 99 1.1 christos emit_expr (&exp, sizeof (uint32_t)); 100 1.1 christos } 101 1.1 christos 102 1.1 christos /* Emit a .secidx relocation. */ 103 1.1 christos static void 104 1.1 christos emit_secidx_reloc (symbolS *sym) 105 1.1 christos { 106 1.1 christos expressionS exp; 107 1.1 christos 108 1.1 christos memset (&exp, 0, sizeof (exp)); 109 1.1 christos exp.X_op = O_secidx; 110 1.1 christos exp.X_add_symbol = sym; 111 1.1 christos exp.X_add_number = 0; 112 1.1 christos emit_expr (&exp, sizeof (uint16_t)); 113 1.1 christos } 114 1.1 christos 115 1.1 christos /* Write the DEBUG_S_STRINGTABLE subsection. */ 116 1.1 christos static void 117 1.1 christos write_string_table (void) 118 1.1 christos { 119 1.1 christos uint32_t len; 120 1.1 christos unsigned int padding; 121 1.1 christos char *ptr, *start; 122 1.1 christos 123 1.1 christos len = 1; 124 1.1 christos 125 1.1 christos for (struct source_file *sf = files_head; sf; sf = sf->next) 126 1.1 christos { 127 1.1 christos len += strlen (sf->filename) + 1; 128 1.1 christos } 129 1.1 christos 130 1.1 christos if (len % 4) 131 1.1 christos padding = 4 - (len % 4); 132 1.1 christos else 133 1.1 christos padding = 0; 134 1.1 christos 135 1.1 christos ptr = frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len + padding); 136 1.1 christos 137 1.1 christos bfd_putl32 (DEBUG_S_STRINGTABLE, ptr); 138 1.1 christos ptr += sizeof (uint32_t); 139 1.1 christos bfd_putl32 (len, ptr); 140 1.1 christos ptr += sizeof (uint32_t); 141 1.1 christos 142 1.1 christos start = ptr; 143 1.1 christos 144 1.1 christos *ptr = 0; 145 1.1 christos ptr++; 146 1.1 christos 147 1.1 christos for (struct source_file *sf = files_head; sf; sf = sf->next) 148 1.1 christos { 149 1.1 christos size_t fn_len = strlen (sf->filename); 150 1.1 christos 151 1.1 christos sf->string_pos = ptr - start; 152 1.1 christos 153 1.1 christos memcpy(ptr, sf->filename, fn_len + 1); 154 1.1 christos ptr += fn_len + 1; 155 1.1 christos } 156 1.1 christos 157 1.1 christos memset (ptr, 0, padding); 158 1.1 christos } 159 1.1 christos 160 1.1 christos /* Write the DEBUG_S_FILECHKSMS subsection. */ 161 1.1 christos static void 162 1.1 christos write_checksums (void) 163 1.1 christos { 164 1.1 christos uint32_t len; 165 1.1 christos char *ptr; 166 1.1 christos 167 1.1 christos len = FILE_ENTRY_LENGTH * num_source_files; 168 1.1 christos 169 1.1 christos ptr = frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len); 170 1.1 christos 171 1.1 christos bfd_putl32 (DEBUG_S_FILECHKSMS, ptr); 172 1.1 christos ptr += sizeof (uint32_t); 173 1.1 christos bfd_putl32 (len, ptr); 174 1.1 christos ptr += sizeof (uint32_t); 175 1.1 christos 176 1.1 christos for (struct source_file *sf = files_head; sf; sf = sf->next) 177 1.1 christos { 178 1.1 christos struct file_checksum fc; 179 1.1 christos 180 1.1 christos fc.file_id = sf->string_pos; 181 1.1 christos fc.checksum_length = NUM_MD5_BYTES; 182 1.1 christos fc.checksum_type = CHKSUM_TYPE_MD5; 183 1.1 christos 184 1.1 christos memcpy (ptr, &fc, sizeof (struct file_checksum)); 185 1.1 christos ptr += sizeof (struct file_checksum); 186 1.1 christos 187 1.1 christos memcpy (ptr, sf->md5, NUM_MD5_BYTES); 188 1.1 christos ptr += NUM_MD5_BYTES; 189 1.1 christos 190 1.1 christos memset (ptr, 0, FILE_ENTRY_PADDING); 191 1.1 christos ptr += FILE_ENTRY_PADDING; 192 1.1 christos } 193 1.1 christos } 194 1.1 christos 195 1.1 christos /* Write the DEBUG_S_LINES subsection. */ 196 1.1 christos static void 197 1.1 christos write_lines_info (void) 198 1.1 christos { 199 1.1 christos while (blocks_head) 200 1.1 christos { 201 1.1 christos struct line_block *lb; 202 1.1 christos struct line_file *lf; 203 1.1 christos uint32_t len; 204 1.1 christos uint32_t off; 205 1.1 christos char *ptr; 206 1.1 christos 207 1.1 christos lb = blocks_head; 208 1.1 christos 209 1.1 christos bfd_putl32 (DEBUG_S_LINES, frag_more (sizeof (uint32_t))); 210 1.1 christos 211 1.1 christos len = sizeof (struct cv_lines_header); 212 1.1 christos 213 1.1 christos for (lf = lb->files_head; lf; lf = lf->next) 214 1.1 christos { 215 1.1 christos len += sizeof (struct cv_lines_block); 216 1.1 christos len += sizeof (struct cv_line) * lf->num_lines; 217 1.1 christos } 218 1.1 christos 219 1.1 christos bfd_putl32 (len, frag_more (sizeof (uint32_t))); 220 1.1 christos 221 1.1 christos /* Write the header (struct cv_lines_header). We can't use a struct 222 1.1 christos for this as we're also emitting relocations. */ 223 1.1 christos 224 1.1 christos emit_secrel32_reloc (lb->sym); 225 1.1 christos emit_secidx_reloc (lb->sym); 226 1.1 christos 227 1.1 christos ptr = frag_more (len - sizeof (uint32_t) - sizeof (uint16_t)); 228 1.1 christos 229 1.1 christos /* Flags */ 230 1.1 christos bfd_putl16 (0, ptr); 231 1.1 christos ptr += sizeof (uint16_t); 232 1.1 christos 233 1.1 christos off = lb->files_head->lines_head->frag_offset; 234 1.1 christos 235 1.1 christos /* Length of region */ 236 1.1 christos bfd_putl32 (get_frag_fix (lb->frag, lb->seg) - off, ptr); 237 1.1 christos ptr += sizeof (uint32_t); 238 1.1 christos 239 1.1 christos while (lb->files_head) 240 1.1 christos { 241 1.1 christos struct cv_lines_block *block = (struct cv_lines_block *) ptr; 242 1.1 christos 243 1.1 christos lf = lb->files_head; 244 1.1 christos 245 1.1 christos bfd_putl32(lf->fileno * FILE_ENTRY_LENGTH, &block->file_id); 246 1.1 christos bfd_putl32(lf->num_lines, &block->num_lines); 247 1.1 christos bfd_putl32(sizeof (struct cv_lines_block) 248 1.1 christos + (sizeof (struct cv_line) * lf->num_lines), 249 1.1 christos &block->length); 250 1.1 christos 251 1.1 christos ptr += sizeof (struct cv_lines_block); 252 1.1 christos 253 1.1 christos while (lf->lines_head) 254 1.1 christos { 255 1.1 christos struct line *l; 256 1.1 christos struct cv_line *l2 = (struct cv_line *) ptr; 257 1.1 christos 258 1.1 christos l = lf->lines_head; 259 1.1 christos 260 1.1 christos /* Only the bottom 24 bits of line_no actually encode the 261 1.1 christos line number. The top bit is a flag meaning "is 262 1.1 christos a statement". */ 263 1.1 christos 264 1.1 christos bfd_putl32 (l->frag_offset - off, &l2->offset); 265 1.1 christos bfd_putl32 (0x80000000 | (l->lineno & 0xffffff), 266 1.1 christos &l2->line_no); 267 1.1 christos 268 1.1 christos lf->lines_head = l->next; 269 1.1 christos 270 1.1 christos free(l); 271 1.1 christos 272 1.1 christos ptr += sizeof (struct cv_line); 273 1.1 christos } 274 1.1 christos 275 1.1 christos lb->files_head = lf->next; 276 1.1 christos free (lf); 277 1.1 christos } 278 1.1 christos 279 1.1 christos blocks_head = lb->next; 280 1.1 christos 281 1.1 christos free (lb); 282 1.1 christos } 283 1.1 christos } 284 1.1 christos 285 1.1 christos /* Return the CodeView constant for the selected architecture. */ 286 1.1 christos static uint16_t 287 1.1 christos target_processor (void) 288 1.1 christos { 289 1.1 christos switch (stdoutput->arch_info->arch) 290 1.1 christos { 291 1.1 christos case bfd_arch_i386: 292 1.1 christos if (stdoutput->arch_info->mach & bfd_mach_x86_64) 293 1.1 christos return CV_CFL_X64; 294 1.1 christos else 295 1.1 christos return CV_CFL_80386; 296 1.1 christos 297 1.1 christos case bfd_arch_aarch64: 298 1.1 christos return CV_CFL_ARM64; 299 1.1 christos 300 1.1 christos default: 301 1.1 christos return 0; 302 1.1 christos } 303 1.1 christos } 304 1.1 christos 305 1.1 christos /* Write the CodeView symbols, describing the object name and 306 1.1 christos assembler version. */ 307 1.1 christos static void 308 1.1 christos write_symbols_info (void) 309 1.1 christos { 310 1.1 christos static const char assembler[] = "GNU AS " VERSION; 311 1.1 christos 312 1.1 christos char *path = lrealpath (out_file_name); 313 1.1 christos char *path2 = remap_debug_filename (path); 314 1.1 christos size_t path_len, padding; 315 1.1 christos uint32_t len; 316 1.1 christos struct OBJNAMESYM objname; 317 1.1 christos struct COMPILESYM3 compile3; 318 1.1 christos char *ptr; 319 1.1 christos 320 1.1 christos free (path); 321 1.1 christos path = path2; 322 1.1 christos 323 1.1 christos path_len = strlen (path); 324 1.1 christos 325 1.1 christos len = sizeof (struct OBJNAMESYM) + path_len + 1; 326 1.1 christos len += sizeof (struct COMPILESYM3) + sizeof (assembler); 327 1.1 christos 328 1.1 christos if (len % 4) 329 1.1 christos padding = 4 - (len % 4); 330 1.1 christos else 331 1.1 christos padding = 0; 332 1.1 christos 333 1.1 christos len += padding; 334 1.1 christos 335 1.1 christos ptr = frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len); 336 1.1 christos 337 1.1 christos bfd_putl32 (DEBUG_S_SYMBOLS, ptr); 338 1.1 christos ptr += sizeof (uint32_t); 339 1.1 christos bfd_putl32 (len, ptr); 340 1.1 christos ptr += sizeof (uint32_t); 341 1.1 christos 342 1.1 christos /* Write S_OBJNAME entry. */ 343 1.1 christos 344 1.1 christos bfd_putl16 (sizeof (struct OBJNAMESYM) - sizeof (uint16_t) + path_len + 1, 345 1.1 christos &objname.length); 346 1.1 christos bfd_putl16 (S_OBJNAME, &objname.type); 347 1.1 christos bfd_putl32 (0, &objname.signature); 348 1.1 christos 349 1.1 christos memcpy (ptr, &objname, sizeof (struct OBJNAMESYM)); 350 1.1 christos ptr += sizeof (struct OBJNAMESYM); 351 1.1 christos memcpy (ptr, path, path_len + 1); 352 1.1 christos ptr += path_len + 1; 353 1.1 christos 354 1.1 christos free (path); 355 1.1 christos 356 1.1 christos /* Write S_COMPILE3 entry. */ 357 1.1 christos 358 1.1 christos bfd_putl16 (sizeof (struct COMPILESYM3) - sizeof (uint16_t) 359 1.1 christos + sizeof (assembler) + padding, &compile3.length); 360 1.1 christos bfd_putl16 (S_COMPILE3, &compile3.type); 361 1.1 christos bfd_putl32 (CV_CFL_MASM, &compile3.flags); 362 1.1 christos bfd_putl16 (target_processor (), &compile3.machine); 363 1.1 christos bfd_putl16 (0, &compile3.frontend_major); 364 1.1 christos bfd_putl16 (0, &compile3.frontend_minor); 365 1.1 christos bfd_putl16 (0, &compile3.frontend_build); 366 1.1 christos bfd_putl16 (0, &compile3.frontend_qfe); 367 1.1 christos bfd_putl16 (0, &compile3.backend_major); 368 1.1 christos bfd_putl16 (0, &compile3.backend_minor); 369 1.1 christos bfd_putl16 (0, &compile3.backend_build); 370 1.1 christos bfd_putl16 (0, &compile3.backend_qfe); 371 1.1 christos 372 1.1 christos memcpy (ptr, &compile3, sizeof (struct COMPILESYM3)); 373 1.1 christos ptr += sizeof (struct COMPILESYM3); 374 1.1 christos memcpy (ptr, assembler, sizeof (assembler)); 375 1.1 christos ptr += sizeof (assembler); 376 1.1 christos 377 1.1 christos memset (ptr, 0, padding); 378 1.1 christos } 379 1.1 christos 380 1.1 christos /* Processing of the file has finished, emit the .debug$S section. */ 381 1.1 christos void 382 1.1 christos codeview_finish (void) 383 1.1 christos { 384 1.1 christos segT seg; 385 1.1 christos 386 1.1 christos if (!blocks_head) 387 1.1 christos return; 388 1.1 christos 389 1.1 christos seg = subseg_new (".debug$S", 0); 390 1.1 christos 391 1.1 christos bfd_set_section_flags (seg, SEC_READONLY | SEC_NEVER_LOAD); 392 1.1 christos 393 1.1 christos bfd_putl32 (CV_SIGNATURE_C13, frag_more (sizeof (uint32_t))); 394 1.1 christos 395 1.1 christos write_string_table (); 396 1.1 christos write_checksums (); 397 1.1 christos write_lines_info (); 398 1.1 christos write_symbols_info (); 399 1.1 christos } 400 1.1 christos 401 1.1 christos /* Assign a new index number for the given file, or return the existing 402 1.1 christos one if already assigned. */ 403 1.1 christos static unsigned int 404 1.1 christos get_fileno (const char *file) 405 1.1 christos { 406 1.1 christos struct source_file *sf; 407 1.1 christos char *path = lrealpath (file); 408 1.1 christos char *path2 = remap_debug_filename (path); 409 1.1 christos size_t path_len; 410 1.1 christos FILE *f; 411 1.1 christos 412 1.1 christos free (path); 413 1.1 christos path = path2; 414 1.1 christos 415 1.1 christos path_len = strlen (path); 416 1.1 christos 417 1.1 christos for (sf = files_head; sf; sf = sf->next) 418 1.1 christos { 419 1.1 christos if (path_len == strlen (sf->filename) 420 1.1 christos && !filename_ncmp (sf->filename, path, path_len)) 421 1.1 christos { 422 1.1 christos free (path); 423 1.1 christos return sf->num; 424 1.1 christos } 425 1.1 christos } 426 1.1 christos 427 1.1 christos sf = xmalloc (sizeof (struct source_file)); 428 1.1 christos 429 1.1 christos sf->next = NULL; 430 1.1 christos sf->num = num_source_files; 431 1.1 christos sf->filename = path; 432 1.1 christos 433 1.1 christos f = fopen (file, "r"); 434 1.1 christos if (!f) 435 1.1 christos as_fatal (_("could not open %s for reading"), file); 436 1.1 christos 437 1.1 christos if (md5_stream (f, sf->md5)) 438 1.1 christos { 439 1.1 christos fclose(f); 440 1.1 christos as_fatal (_("md5_stream failed")); 441 1.1 christos } 442 1.1 christos 443 1.1 christos fclose(f); 444 1.1 christos 445 1.1 christos if (!files_head) 446 1.1 christos files_head = sf; 447 1.1 christos else 448 1.1 christos files_tail->next = sf; 449 1.1 christos 450 1.1 christos files_tail = sf; 451 1.1 christos 452 1.1 christos num_source_files++; 453 1.1 christos 454 1.1 christos return num_source_files - 1; 455 1.1 christos } 456 1.1 christos 457 1.1 christos /* Called for each new line in asm file. */ 458 1.1 christos void 459 1.1 christos codeview_generate_asm_lineno (void) 460 1.1 christos { 461 1.1 christos const char *file; 462 1.1 christos unsigned int filenr; 463 1.1 christos unsigned int lineno; 464 1.1 christos struct line *l; 465 1.1 christos symbolS *sym = NULL; 466 1.1 christos struct line_block *lb; 467 1.1 christos struct line_file *lf; 468 1.1 christos 469 1.1 christos file = as_where (&lineno); 470 1.1 christos 471 1.1 christos filenr = get_fileno (file); 472 1.1 christos 473 1.1 christos if (!blocks_tail || blocks_tail->frag != frag_now) 474 1.1 christos { 475 1.1 christos static int label_num = 0; 476 1.1 christos char name[32]; 477 1.1 christos 478 1.1 christos sprintf (name, ".Loc.%u", label_num); 479 1.1 christos label_num++; 480 1.1 christos sym = symbol_new (name, now_seg, frag_now, frag_now_fix ()); 481 1.1 christos 482 1.1 christos lb = xmalloc (sizeof (struct line_block)); 483 1.1 christos lb->next = NULL; 484 1.1 christos lb->seg = now_seg; 485 1.1 christos lb->subseg = now_subseg; 486 1.1 christos lb->frag = frag_now; 487 1.1 christos lb->sym = sym; 488 1.1 christos lb->files_head = lb->files_tail = NULL; 489 1.1 christos 490 1.1 christos if (!blocks_head) 491 1.1 christos blocks_head = lb; 492 1.1 christos else 493 1.1 christos blocks_tail->next = lb; 494 1.1 christos 495 1.1 christos blocks_tail = lb; 496 1.1 christos } 497 1.1 christos else 498 1.1 christos { 499 1.1 christos lb = blocks_tail; 500 1.1 christos } 501 1.1 christos 502 1.1 christos if (!lb->files_tail || lb->files_tail->fileno != filenr) 503 1.1 christos { 504 1.1 christos lf = xmalloc (sizeof (struct line_file)); 505 1.1 christos lf->next = NULL; 506 1.1 christos lf->fileno = filenr; 507 1.1 christos lf->lines_head = lf->lines_tail = NULL; 508 1.1 christos lf->num_lines = 0; 509 1.1 christos 510 1.1 christos if (!lb->files_head) 511 1.1 christos lb->files_head = lf; 512 1.1 christos else 513 1.1 christos lb->files_tail->next = lf; 514 1.1 christos 515 1.1 christos lb->files_tail = lf; 516 1.1 christos } 517 1.1 christos else 518 1.1 christos { 519 1.1 christos lf = lb->files_tail; 520 1.1 christos } 521 1.1 christos 522 1.1 christos l = xmalloc (sizeof (struct line)); 523 1.1 christos l->next = NULL; 524 1.1 christos l->lineno = lineno; 525 1.1 christos l->frag_offset = frag_now_fix (); 526 1.1 christos 527 1.1 christos if (!lf->lines_head) 528 1.1 christos lf->lines_head = l; 529 1.1 christos else 530 1.1 christos lf->lines_tail->next = l; 531 1.1 christos 532 1.1 christos lf->lines_tail = l; 533 1.1 christos lf->num_lines++; 534 1.1 christos } 535 1.1 christos 536 1.1.1.2 christos /* Output a compressed CodeView integer. The return value is the number of 537 1.1.1.2 christos bytes used. */ 538 1.1.1.2 christos 539 1.1.1.2 christos unsigned int 540 1.1.1.2 christos output_cv_comp (char *p, offsetT value, int sign) 541 1.1.1.2 christos { 542 1.1.1.2 christos char *orig = p; 543 1.1.1.2 christos 544 1.1.1.2 christos if (sign) 545 1.1.1.2 christos { 546 1.1.1.2 christos if (value < -0xfffffff || value > 0xfffffff) 547 1.1.1.2 christos { 548 1.1.1.2 christos as_bad (_("value cannot be expressed as a .cv_scomp")); 549 1.1.1.2 christos return 0; 550 1.1.1.2 christos } 551 1.1.1.2 christos } 552 1.1.1.2 christos else 553 1.1.1.2 christos { 554 1.1.1.2 christos if (value < 0 || value > 0x1fffffff) 555 1.1.1.2 christos { 556 1.1.1.2 christos as_bad (_("value cannot be expressed as a .cv_ucomp")); 557 1.1.1.2 christos return 0; 558 1.1.1.2 christos } 559 1.1.1.2 christos } 560 1.1.1.2 christos 561 1.1.1.2 christos if (sign) 562 1.1.1.2 christos { 563 1.1.1.2 christos if (value >= 0) 564 1.1.1.2 christos value <<= 1; 565 1.1.1.2 christos else 566 1.1.1.2 christos value = (-value << 1) | 1; 567 1.1.1.2 christos } 568 1.1.1.2 christos 569 1.1.1.2 christos if (value <= 0x7f) 570 1.1.1.2 christos { 571 1.1.1.2 christos *p++ = value; 572 1.1.1.2 christos } 573 1.1.1.2 christos else if (value <= 0x3fff) 574 1.1.1.2 christos { 575 1.1.1.2 christos *p++ = 0x80 | (value >> 8); 576 1.1.1.2 christos *p++ = value & 0xff; 577 1.1.1.2 christos } 578 1.1.1.2 christos else 579 1.1.1.2 christos { 580 1.1.1.2 christos *p++ = 0xc0 | (value >> 24); 581 1.1.1.2 christos *p++ = (value >> 16) & 0xff; 582 1.1.1.2 christos *p++ = (value >> 8) & 0xff; 583 1.1.1.2 christos *p++ = value & 0xff; 584 1.1.1.2 christos } 585 1.1.1.2 christos 586 1.1.1.2 christos return p - orig; 587 1.1.1.2 christos } 588 1.1.1.2 christos 589 1.1.1.2 christos /* Return the size needed to output a compressed CodeView integer. */ 590 1.1.1.2 christos 591 1.1.1.2 christos unsigned int 592 1.1.1.2 christos sizeof_cv_comp (offsetT value, int sign) 593 1.1.1.2 christos { 594 1.1.1.2 christos if (sign) 595 1.1.1.2 christos { 596 1.1.1.2 christos if (value < -0xfffffff || value > 0xfffffff) 597 1.1.1.2 christos return 0; 598 1.1.1.2 christos 599 1.1.1.2 christos if (value >= 0) 600 1.1.1.2 christos value <<= 1; 601 1.1.1.2 christos else 602 1.1.1.2 christos value = (-value << 1) | 1; 603 1.1.1.2 christos } 604 1.1.1.2 christos else 605 1.1.1.2 christos { 606 1.1.1.2 christos if (value > 0x1fffffff) 607 1.1.1.2 christos return 0; 608 1.1.1.2 christos } 609 1.1.1.2 christos 610 1.1.1.2 christos if (value <= 0x7f) 611 1.1.1.2 christos return 1; 612 1.1.1.2 christos else if (value <= 0x3fff) 613 1.1.1.2 christos return 2; 614 1.1.1.2 christos else if (value <= 0x1fffffff) 615 1.1.1.2 christos return 4; 616 1.1.1.2 christos else 617 1.1.1.2 christos return 0; 618 1.1.1.2 christos } 619 1.1.1.2 christos 620 1.1 christos #else 621 1.1 christos 622 1.1 christos void 623 1.1 christos codeview_finish (void) 624 1.1 christos { 625 1.1 christos } 626 1.1 christos 627 1.1 christos void 628 1.1 christos codeview_generate_asm_lineno (void) 629 1.1 christos { 630 1.1 christos } 631 1.1 christos 632 1.1 christos #endif /* TE_PE && O_secrel */ 633