154359Sroberto// incremental.cc -- incremental linking test/debug tool 254359Sroberto 354359Sroberto// Copyright (C) 2009-2020 Free Software Foundation, Inc. 454359Sroberto// Written by Rafael Avila de Espindola <rafael.espindola@gmail.com> 554359Sroberto 654359Sroberto// This file is part of gold. 754359Sroberto 854359Sroberto// This program is free software; you can redistribute it and/or modify 954359Sroberto// it under the terms of the GNU General Public License as published by 1054359Sroberto// the Free Software Foundation; either version 3 of the License, or 1154359Sroberto// (at your option) any later version. 1254359Sroberto 1354359Sroberto// This program is distributed in the hope that it will be useful, 1454359Sroberto// but WITHOUT ANY WARRANTY; without even the implied warranty of 1554359Sroberto// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1682498Sroberto// GNU General Public License for more details. 1782498Sroberto 1882498Sroberto// You should have received a copy of the GNU General Public License 1954359Sroberto// along with this program; if not, write to the Free Software 2054359Sroberto// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 2154359Sroberto// MA 02110-1301, USA. 2254359Sroberto 2354359Sroberto 2454359Sroberto// This file is a (still incomplete) test/debug tool that should display 2554359Sroberto// all information available in the incremental linking sections in a 2654359Sroberto// format that is easy to read. 2754359Sroberto// Once the format is a bit more stable, this should probably be moved to 2854359Sroberto// readelf. Because of that, the use of gold's data structures and functions 2954359Sroberto// is just a short term convenience and not a design decision. 3054359Sroberto 3154359Sroberto#include "gold.h" 3254359Sroberto 3354359Sroberto#include <stdio.h> 3454359Sroberto#include <errno.h> 3554359Sroberto#include <time.h> 3654359Sroberto 3754359Sroberto#include "incremental.h" 3854359Sroberto 3954359Srobertonamespace gold 4054359Sroberto{ 4154359Sroberto class Output_file; 4254359Sroberto} 4354359Sroberto 4454359Srobertousing namespace gold; 4554359Sroberto 4654359Srobertotemplate<int size, bool big_endian> 4754359Srobertostatic typename Incremental_inputs_reader<size, big_endian>:: 4854359Sroberto Incremental_input_entry_reader 4954359Srobertofind_input_containing_global( 5054359Sroberto Incremental_inputs_reader<size, big_endian>& incremental_inputs, 5154359Sroberto unsigned int offset, 5254359Sroberto unsigned int* symndx) 5354359Sroberto{ 5454359Sroberto typedef Incremental_inputs_reader<size, big_endian> Inputs_reader; 5554359Sroberto static const unsigned int global_sym_entry_size = 5654359Sroberto Incremental_inputs_reader<size, big_endian>::global_sym_entry_size; 5754359Sroberto 5854359Sroberto for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 5954359Sroberto { 6054359Sroberto typename Inputs_reader::Incremental_input_entry_reader input_file = 6154359Sroberto incremental_inputs.input_file(i); 6254359Sroberto if (input_file.type() != INCREMENTAL_INPUT_OBJECT 6354359Sroberto && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER) 6454359Sroberto continue; 6554359Sroberto unsigned int nsyms = input_file.get_global_symbol_count(); 6654359Sroberto if (offset >= input_file.get_symbol_offset(0) 6754359Sroberto && offset < input_file.get_symbol_offset(nsyms)) 6854359Sroberto { 6954359Sroberto *symndx = ((offset - input_file.get_symbol_offset(0)) 7054359Sroberto / global_sym_entry_size); 7154359Sroberto return input_file; 7254359Sroberto } 7354359Sroberto } 74132451Sroberto gold_unreachable(); 7554359Sroberto} 7654359Sroberto 7754359Srobertotemplate<int size, bool big_endian> 7854359Srobertostatic void 7954359Srobertodump_incremental_inputs(const char* argv0, const char* filename, 8054359Sroberto Sized_incremental_binary<size, big_endian>* inc) 8154359Sroberto{ 8254359Sroberto typedef Incremental_binary::Location Location; 8354359Sroberto typedef Incremental_binary::View View; 8454359Sroberto typedef Incremental_inputs_reader<size, big_endian> Inputs_reader; 8554359Sroberto typedef typename Inputs_reader::Incremental_input_entry_reader Entry_reader; 8654359Sroberto 87132451Sroberto if (!inc->has_incremental_info()) 8854359Sroberto { 8954359Sroberto fprintf(stderr, "%s: %s: no .gnu_incremental_inputs section\n", argv0, 9054359Sroberto filename); 9154359Sroberto exit(1); 9254359Sroberto } 9354359Sroberto 94285612Sdelphij // Create a reader object for the .gnu_incremental_inputs section. 95285612Sdelphij 96285612Sdelphij Incremental_inputs_reader<size, big_endian> 97285612Sdelphij incremental_inputs(inc->inputs_reader()); 9854359Sroberto 9954359Sroberto if (incremental_inputs.version() != 2) 10054359Sroberto { 10154359Sroberto fprintf(stderr, "%s: %s: unknown incremental version %d\n", argv0, 10254359Sroberto filename, incremental_inputs.version()); 10354359Sroberto exit(1); 10454359Sroberto } 10554359Sroberto 10654359Sroberto const char* command_line = incremental_inputs.command_line(); 10754359Sroberto if (command_line == NULL) 10854359Sroberto { 10954359Sroberto fprintf(stderr, 11054359Sroberto "%s: %s: failed to get link command line\n", 11154359Sroberto argv0, filename); 11254359Sroberto exit(1); 11354359Sroberto } 11454359Sroberto printf("Link command line: %s\n", command_line); 11554359Sroberto 11654359Sroberto printf("\nInput files:\n"); 11754359Sroberto for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 11854359Sroberto { 11954359Sroberto Entry_reader input_file = incremental_inputs.input_file(i); 12054359Sroberto 12154359Sroberto const char* objname = input_file.filename(); 12254359Sroberto if (objname == NULL) 12354359Sroberto { 12454359Sroberto fprintf(stderr,"%s: %s: failed to get file name for object %u\n", 12554359Sroberto argv0, filename, i); 12654359Sroberto exit(1); 12754359Sroberto } 12854359Sroberto printf("[%d] %s\n", i, objname); 12954359Sroberto 130285612Sdelphij Timespec mtime = input_file.get_mtime(); 131285612Sdelphij printf(" Timestamp: %llu.%09d %s", 132285612Sdelphij static_cast<unsigned long long>(mtime.seconds), 13354359Sroberto mtime.nanoseconds, 13454359Sroberto ctime(&mtime.seconds)); 13554359Sroberto 13654359Sroberto printf(" Serial Number: %d\n", input_file.arg_serial()); 13754359Sroberto printf(" In System Directory: %s\n", 138285612Sdelphij input_file.is_in_system_directory() ? "true" : "false"); 13954359Sroberto 14054359Sroberto Incremental_input_type input_type = input_file.type(); 141285612Sdelphij printf(" Type: "); 14254359Sroberto switch (input_type) 14354359Sroberto { 14454359Sroberto case INCREMENTAL_INPUT_OBJECT: 145285612Sdelphij case INCREMENTAL_INPUT_ARCHIVE_MEMBER: 146285612Sdelphij printf("%s\n", (input_type == INCREMENTAL_INPUT_OBJECT 14754359Sroberto ? "Object" : "Archive member")); 14854359Sroberto printf(" Input section count: %d\n", 14954359Sroberto input_file.get_input_section_count()); 150285612Sdelphij printf(" Global symbol count: %d\n", 15154359Sroberto input_file.get_global_symbol_count()); 15254359Sroberto printf(" Local symbol offset: %d\n", 15354359Sroberto input_file.get_local_symbol_offset()); 15454359Sroberto printf(" Local symbol count: %d\n", 15554359Sroberto input_file.get_local_symbol_count()); 15654359Sroberto printf(" First dynamic reloc: %d\n", 15754359Sroberto input_file.get_first_dyn_reloc()); 15854359Sroberto printf(" Dynamic reloc count: %d\n", 15954359Sroberto input_file.get_dyn_reloc_count()); 16054359Sroberto printf(" COMDAT group count: %d\n", 16154359Sroberto input_file.get_comdat_group_count()); 16254359Sroberto break; 16354359Sroberto case INCREMENTAL_INPUT_ARCHIVE: 16454359Sroberto printf("Archive\n"); 16554359Sroberto printf(" Member count: %d\n", input_file.get_member_count()); 16654359Sroberto printf(" Unused symbol count: %d\n", 16754359Sroberto input_file.get_unused_symbol_count()); 16854359Sroberto break; 16954359Sroberto case INCREMENTAL_INPUT_SHARED_LIBRARY: 17054359Sroberto printf("Shared library\n"); 17154359Sroberto printf(" As needed: %s\n", 17254359Sroberto input_file.as_needed() ? "true" : "false"); 17354359Sroberto printf(" soname: %s\n", 17454359Sroberto input_file.get_soname()); 175285612Sdelphij printf(" Symbol count: %d\n", 176285612Sdelphij input_file.get_global_symbol_count()); 177285612Sdelphij break; 178285612Sdelphij case INCREMENTAL_INPUT_SCRIPT: 179285612Sdelphij printf("Linker script\n"); 18054359Sroberto printf(" Object count: %d\n", input_file.get_object_count()); 18154359Sroberto break; 18254359Sroberto default: 18354359Sroberto fprintf(stderr, "%s: invalid file type for object %u: %d\n", 18454359Sroberto argv0, i, input_type); 18554359Sroberto exit(1); 18654359Sroberto } 18754359Sroberto } 18854359Sroberto 18954359Sroberto printf("\nInput sections:\n"); 19054359Sroberto for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 19154359Sroberto { 19254359Sroberto Entry_reader input_file(incremental_inputs.input_file(i)); 19354359Sroberto 19454359Sroberto if (input_file.type() != INCREMENTAL_INPUT_OBJECT 19554359Sroberto && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER) 19654359Sroberto continue; 19754359Sroberto 19854359Sroberto const char* objname = input_file.filename(); 19954359Sroberto if (objname == NULL) 20054359Sroberto { 20154359Sroberto fprintf(stderr,"%s: %s: failed to get file name for object %u\n", 20254359Sroberto argv0, filename, i); 20354359Sroberto exit(1); 204285612Sdelphij } 20554359Sroberto 206285612Sdelphij printf("[%d] %s\n", i, objname); 20754359Sroberto 20854359Sroberto printf(" %3s %6s %8s %8s %s\n", 20954359Sroberto "n", "outndx", "offset", "size", "name"); 21054359Sroberto unsigned int nsections = input_file.get_input_section_count(); 21154359Sroberto for (unsigned int shndx = 0; shndx < nsections; ++shndx) 21254359Sroberto { 21354359Sroberto typename Entry_reader::Input_section_info info( 21454359Sroberto input_file.get_input_section(shndx)); 21554359Sroberto printf(" %3d %6d %8lld %8lld %s\n", shndx + 1, 216132451Sroberto info.output_shndx, 21754359Sroberto static_cast<long long>(info.sh_offset), 21854359Sroberto static_cast<long long>(info.sh_size), 21954359Sroberto info.name); 22054359Sroberto } 22154359Sroberto 22254359Sroberto unsigned int ncomdat = input_file.get_comdat_group_count(); 22354359Sroberto for (unsigned int i = 0; i < ncomdat; ++i) 22454359Sroberto printf(" Comdat group: %s\n", 22554359Sroberto input_file.get_comdat_group_signature(i)); 22654359Sroberto } 22754359Sroberto 22854359Sroberto // Get a view of the .symtab section. 22954359Sroberto 23054359Sroberto elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file(inc); 23154359Sroberto 23254359Sroberto unsigned int symtab_shndx = elf_file.find_section_by_type(elfcpp::SHT_SYMTAB); 23354359Sroberto if (symtab_shndx == elfcpp::SHN_UNDEF) // Not found. 23454359Sroberto { 23554359Sroberto fprintf(stderr, "%s: %s: no symbol table section\n", argv0, filename); 23654359Sroberto exit(1); 237132451Sroberto } 238132451Sroberto Location symtab_location(elf_file.section_contents(symtab_shndx)); 239132451Sroberto View symtab_view(inc->view(symtab_location)); 240132451Sroberto 24154359Sroberto // Get a view of the .strtab section. 24254359Sroberto 24354359Sroberto unsigned int strtab_shndx = elf_file.section_link(symtab_shndx); 244132451Sroberto if (strtab_shndx == elfcpp::SHN_UNDEF 24554359Sroberto || strtab_shndx > elf_file.shnum() 24654359Sroberto || elf_file.section_type(strtab_shndx) != elfcpp::SHT_STRTAB) 24754359Sroberto { 24854359Sroberto fprintf(stderr, "%s: %s: no string table section\n", argv0, filename); 24954359Sroberto exit(1); 25054359Sroberto } 25154359Sroberto Location strtab_location(elf_file.section_contents(strtab_shndx)); 25254359Sroberto View strtab_view(inc->view(strtab_location)); 25354359Sroberto elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size); 25454359Sroberto 25554359Sroberto // The .gnu_incremental_symtab section contains entries that parallel 25654359Sroberto // the global symbols of the main symbol table. The sh_info field 25754359Sroberto // of the main symbol table's section header tells us how many global 25854359Sroberto // symbols there are, but that count does not include any global 25954359Sroberto // symbols that were forced local during the link. Therefore, we 26054359Sroberto // use the size of the .gnu_incremental_symtab section to deduce 261132451Sroberto // the number of global symbols + forced-local symbols there are 262132451Sroberto // in the symbol table. 263132451Sroberto Incremental_symtab_reader<big_endian> isymtab(inc->symtab_reader()); 26454359Sroberto Incremental_relocs_reader<size, big_endian> irelocs(inc->relocs_reader()); 26554359Sroberto unsigned int sym_size = elfcpp::Elf_sizes<size>::sym_size; 26654359Sroberto unsigned int nsyms = symtab_location.data_size / sym_size; 26754359Sroberto unsigned int nglobals = isymtab.symbol_count(); 26854359Sroberto unsigned int first_global = nsyms - nglobals; 26954359Sroberto unsigned const char* sym_p; 27054359Sroberto 271182007Sroberto printf("\nGlobal symbols per input file:\n"); 272182007Sroberto for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 27354359Sroberto { 27454359Sroberto Entry_reader input_file(incremental_inputs.input_file(i)); 27554359Sroberto 27654359Sroberto if (input_file.type() != INCREMENTAL_INPUT_OBJECT 27754359Sroberto && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER 27854359Sroberto && input_file.type() != INCREMENTAL_INPUT_SHARED_LIBRARY) 27954359Sroberto continue; 28054359Sroberto 28154359Sroberto const char* objname = input_file.filename(); 28254359Sroberto if (objname == NULL) 28354359Sroberto { 28454359Sroberto fprintf(stderr,"%s: %s: failed to get file name for object %u\n", 28554359Sroberto argv0, filename, i); 28654359Sroberto exit(1); 28754359Sroberto } 28854359Sroberto 28954359Sroberto printf("[%d] %s\n", i, objname); 29054359Sroberto 291132451Sroberto unsigned int nsyms = input_file.get_global_symbol_count(); 292132451Sroberto if (nsyms > 0) 293132451Sroberto printf(" %6s %6s %8s %8s %8s %8s\n", 294132451Sroberto "outndx", "shndx", "offset", "chain", "#relocs", "rbase"); 29554359Sroberto if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY) 29654359Sroberto { 297285612Sdelphij for (unsigned int symndx = 0; symndx < nsyms; ++symndx) 29854359Sroberto { 29954359Sroberto bool is_def; 30054359Sroberto bool is_copy; 30154359Sroberto unsigned int output_symndx = 30254359Sroberto input_file.get_output_symbol_index(symndx, &is_def, &is_copy); 30354359Sroberto sym_p = symtab_view.data() + output_symndx * sym_size; 30454359Sroberto elfcpp::Sym<size, big_endian> sym(sym_p); 30554359Sroberto const char* symname; 306132451Sroberto if (!strtab.get_c_string(sym.get_st_name(), &symname)) 30754359Sroberto symname = "<unknown>"; 308132451Sroberto printf(" %6d %6s %8s %8s %8s %8s %-5s %s\n", 309132451Sroberto output_symndx, 310132451Sroberto "", "", "", "", "", 311132451Sroberto is_copy ? "COPY" : (is_def ? "DEF" : "UNDEF"), 312132451Sroberto symname); 313132451Sroberto } 31454359Sroberto } 31554359Sroberto else 31654359Sroberto { 31754359Sroberto for (unsigned int symndx = 0; symndx < nsyms; ++symndx) 31854359Sroberto { 319 Incremental_global_symbol_reader<big_endian> info( 320 input_file.get_global_symbol_reader(symndx)); 321 unsigned int output_symndx = info.output_symndx(); 322 sym_p = symtab_view.data() + output_symndx * sym_size; 323 elfcpp::Sym<size, big_endian> sym(sym_p); 324 const char* symname; 325 if (!strtab.get_c_string(sym.get_st_name(), &symname)) 326 symname = "<unknown>"; 327 printf(" %6d %6d %8d %8d %8d %8d %-5s %s\n", 328 output_symndx, 329 info.shndx() == -1U ? -1 : info.shndx(), 330 input_file.get_symbol_offset(symndx), 331 info.next_offset(), 332 info.reloc_count(), 333 info.reloc_offset(), 334 (info.shndx() == -1U 335 ? "BASE" 336 : info.shndx() == 0 ? "UNDEF" : "DEF"), 337 symname); 338 } 339 } 340 } 341 342 sym_p = symtab_view.data() + first_global * sym_size; 343 printf("\nGlobal symbol table:\n"); 344 for (unsigned int i = 0; i < nglobals; i++) 345 { 346 elfcpp::Sym<size, big_endian> sym(sym_p); 347 const char* symname; 348 if (!strtab.get_c_string(sym.get_st_name(), &symname)) 349 symname = "<unknown>"; 350 printf("[%d] %s\n", first_global + i, symname); 351 unsigned int offset = isymtab.get_list_head(i); 352 while (offset > 0) 353 { 354 unsigned int sym_ndx; 355 Entry_reader input_file = 356 find_input_containing_global<size, big_endian>(incremental_inputs, 357 offset, &sym_ndx); 358 Incremental_global_symbol_reader<big_endian> sym_info( 359 input_file.get_global_symbol_reader(sym_ndx)); 360 printf(" %s (first reloc: %d, reloc count: %d)", 361 input_file.filename(), sym_info.reloc_offset(), 362 sym_info.reloc_count()); 363 if (sym_info.output_symndx() != first_global + i) 364 printf(" ** wrong output symndx (%d) **", sym_info.output_symndx()); 365 printf("\n"); 366 // Dump the relocations from this input file for this symbol. 367 unsigned int r_off = sym_info.reloc_offset(); 368 for (unsigned int j = 0; j < sym_info.reloc_count(); j++) 369 { 370 printf(" %4d relocation type %3d shndx %2d" 371 " offset %016llx addend %016llx %s\n", 372 r_off, 373 irelocs.get_r_type(r_off), 374 irelocs.get_r_shndx(r_off), 375 static_cast<long long>(irelocs.get_r_offset(r_off)), 376 static_cast<long long>(irelocs.get_r_addend(r_off)), 377 symname); 378 r_off += irelocs.reloc_size; 379 } 380 offset = sym_info.next_offset(); 381 } 382 sym_p += sym_size; 383 } 384 385 Incremental_got_plt_reader<big_endian> igot_plt(inc->got_plt_reader()); 386 unsigned int ngot = igot_plt.get_got_entry_count(); 387 unsigned int nplt = igot_plt.get_plt_entry_count(); 388 389 printf("\nGOT entries:\n"); 390 for (unsigned int i = 0; i < ngot; ++i) 391 { 392 unsigned int got_type = igot_plt.get_got_type(i); 393 unsigned int got_symndx = igot_plt.get_got_symndx(i); 394 unsigned int got_input_index = igot_plt.get_got_input_index(i); 395 printf("[%d] type %02x, ", i, got_type & 0x7f); 396 if ((got_type & 0x7f) == 0x7f) 397 printf("reserved"); 398 else if (got_type & 0x80) 399 { 400 Entry_reader input_file = 401 incremental_inputs.input_file(got_input_index); 402 const char* objname = input_file.filename(); 403 printf("local: %s (%d)", objname, got_symndx); 404 } 405 else 406 { 407 sym_p = symtab_view.data() + got_symndx * sym_size; 408 elfcpp::Sym<size, big_endian> sym(sym_p); 409 const char* symname; 410 if (!strtab.get_c_string(sym.get_st_name(), &symname)) 411 symname = "<unknown>"; 412 printf("global %s (%d)", symname, got_symndx); 413 } 414 printf("\n"); 415 } 416 417 printf("\nPLT entries:\n"); 418 for (unsigned int i = 0; i < nplt; ++i) 419 { 420 unsigned int plt_desc = igot_plt.get_plt_desc(i); 421 printf("[%d] ", i); 422 sym_p = symtab_view.data() + plt_desc * sym_size; 423 elfcpp::Sym<size, big_endian> sym(sym_p); 424 const char* symname; 425 if (!strtab.get_c_string(sym.get_st_name(), &symname)) 426 symname = "<unknown>"; 427 printf("%s (%d)\n", symname, plt_desc); 428 } 429 430 printf("\nUnused archive symbols:\n"); 431 for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 432 { 433 Entry_reader input_file(incremental_inputs.input_file(i)); 434 435 if (input_file.type() != INCREMENTAL_INPUT_ARCHIVE) 436 continue; 437 438 const char* objname = input_file.filename(); 439 if (objname == NULL) 440 { 441 fprintf(stderr,"%s: %s: failed to get file name for object %u\n", 442 argv0, filename, i); 443 exit(1); 444 } 445 446 printf("[%d] %s\n", i, objname); 447 unsigned int nsyms = input_file.get_unused_symbol_count(); 448 for (unsigned int symndx = 0; symndx < nsyms; ++symndx) 449 printf(" %s\n", input_file.get_unused_symbol(symndx)); 450 } 451 452} 453 454int 455main(int argc, char** argv) 456{ 457 if (argc != 2) 458 { 459 fprintf(stderr, "Usage: %s <file>\n", argv[0]); 460 return 1; 461 } 462 const char* filename = argv[1]; 463 464 Output_file* file = new Output_file(filename); 465 466 bool t = file->open_base_file(NULL, false); 467 if (!t) 468 { 469 fprintf(stderr, "%s: open_base_file(%s): %s\n", argv[0], filename, 470 strerror(errno)); 471 return 1; 472 } 473 474 Incremental_binary* inc = open_incremental_binary(file); 475 476 if (inc == NULL) 477 { 478 fprintf(stderr, "%s: open_incremental_binary(%s): %s\n", argv[0], 479 filename, strerror(errno)); 480 return 1; 481 } 482 483 switch (parameters->size_and_endianness()) 484 { 485#ifdef HAVE_TARGET_32_LITTLE 486 case Parameters::TARGET_32_LITTLE: 487 dump_incremental_inputs<32, false>( 488 argv[0], filename, 489 static_cast<Sized_incremental_binary<32, false>*>(inc)); 490 break; 491#endif 492#ifdef HAVE_TARGET_32_BIG 493 case Parameters::TARGET_32_BIG: 494 dump_incremental_inputs<32, true>( 495 argv[0], filename, 496 static_cast<Sized_incremental_binary<32, true>*>(inc)); 497 break; 498#endif 499#ifdef HAVE_TARGET_64_LITTLE 500 case Parameters::TARGET_64_LITTLE: 501 dump_incremental_inputs<64, false>( 502 argv[0], filename, 503 static_cast<Sized_incremental_binary<64, false>*>(inc)); 504 break; 505#endif 506#ifdef HAVE_TARGET_64_BIG 507 case Parameters::TARGET_64_BIG: 508 dump_incremental_inputs<64, true>( 509 argv[0], filename, 510 static_cast<Sized_incremental_binary<64, true>*>(inc)); 511 break; 512#endif 513 default: 514 gold_unreachable(); 515 } 516 517 return 0; 518} 519