[gold patch] Incremental 8/18: Initial support for incremental update

Cary Coutant ccoutant@google.com
Wed Mar 30 00:46:00 GMT 2011


This patch adds the initial support for incremental update. Each input
argument is assigned an "argument serial number", which is stored in
the incremental info, and allows us to later associate an input file
with the corresponding input argument (for the purpose of checking the
--incremental-changed/-unchanged flag). I've created a new
Sized_incr_relobj class to represent an unchanged input file, and
introduced a new base class, Sized_relobj_base, that both it and
Sized_relobj derive from. The output sections that we aren't
rebuilding get a fixed layout, and a free list from which new
contributions are allocated.

Sorry this is so huge -- the rest of the patches are more manageable.

-cary


2011-03-28 Cary Coutant  <ccoutant@google.com>

	* gold/archive.cc (Archive::include_member): Adjust call to
	report_object.
	(Add_archive_symbols::run): Track argument serial numbers.
	(Lib_group::include_member): Likewise.
	(Add_lib_group_symbols::run): Adjust call to report_archive_begin.
	* gold/archive.h (Incremental_archive_entry::Archive_member):
	Initialize arg_serial_.
	(Archive_member::arg_serial_): New data member.
	* gold/dynobj.cc (Dynobj::Dynobj): Allow input_file_ to be NULL.
	(Sized_dynobj::do_add_symbols): Track symbols when doing an
	incremental link.
	(Sized_dynobj::do_for_all_local_got_entries): New function.
	* gold/dynobj.h: (Sized_dynobj::do_for_all_local_got_entries): New
	function.
	* gold/fileread.cc (get_mtime): New function.
	* gold/fileread.h (get_mtime): New function.
	* gold/gold.cc (queue_initial_tasks): Check for incremental update.
	(process_incremental_input): New function.
	(queue_middle_tasks): Don't force valid target for incremental
	update.
	* gold/incremental-dump.cc (find_input_containing_global): Adjust
	size of symbol info entry.
	(dump_incremental_inputs): Dump argument serial number and
	in_system_directory flag; bias shndx by 1; print symbol names
	when dumping per-file symbol lists; use new symbol info readers.
	* gold/incremental.cc
	(Output_section_incremental_inputs:update_data_size): New function.
	(Sized_incremental_binary::setup_readers): Setup input readers
	for each input file; build maps for files added from libraries
	and scripts.
	(Sized_incremental_binary::check_input_args): New function.
	(Sized_incremental_binary::do_check_inputs): Build map of argument
	serial numbers to input arguments.
	(Sized_incremental_binary::do_file_has_changed): Rename
	do_file_is_unchanged to this; compare file modification times.
	(Sized_incremental_binary::do_init_layout): New function.
	(Sized_incremental_binary::do_reserve_layout): New function.
	(Sized_incremental_binary::do_get_input_reader): Remove.
	(Sized_incremental_binary::get_symtab_view): New function.
	(Incremental_checker::can_incrementally_link_output_file): Remove.
	(Incremental_inputs::report_command_line): Exclude --debug options.
	(Incremental_inputs::report_archive_begin): Add parameter; track
	argument serial numbers; don't put input file entry for archive
	before archive members.
	(Incremental_inputs::report_archive_end): Put input file entry
	for archive after archive members.
	(Incremental_inputs::report_object): Add parameter; track argument
	serial numbers and in_system_directory flag.
	(Incremental_inputs::report_script): Add parameter; track argument
	serial numbers.
	(Output_section_incremental_inputs::set_final_data_size): Adjust
	size of symbol info entry; check for forwarding symbols.
	(Output_section_incremental_inputs::write_input_files): Write
	in_system_directory flag and argument serial number.
	(Output_section_incremental_inputs::write_info_blocks): Map section
	indices between incremental info and original input file; store
	input section index for each symbol.
	(class Local_got_offset_visitor): Derive from Got_offset_list::Visitor;
	change operator() to visit().
	(class Global_got_offset_visitor): Likewise.
	(class Global_symbol_visitor_got_plt):
	(Output_section_incremental_inputs::write_got_plt): Use new visitor
	classes.
	(Sized_incr_relobj::Sized_incr_relobj): New constructor.
	(Sized_incr_relobj::do_read_symbols): New function.
	(Sized_incr_relobj::do_layout): New function.
	(Sized_incr_relobj::do_layout_deferred_sections): New function.
	(Sized_incr_relobj::do_add_symbols): New function.
	(Sized_incr_relobj::do_should_include_member): New function.
	(Sized_incr_relobj::do_for_all_global_symbols): New function.
	(Sized_incr_relobj::do_for_all_local_got_entries): New function.
	(Sized_incr_relobj::do_section_size): New function.
	(Sized_incr_relobj::do_section_name): New function.
	(Sized_incr_relobj::do_section_contents): New function.
	(Sized_incr_relobj::do_section_flags): New function.
	(Sized_incr_relobj::do_section_entsize): New function.
	(Sized_incr_relobj::do_section_address): New function.
	(Sized_incr_relobj::do_section_type): New function.
	(Sized_incr_relobj::do_section_link): New function.
	(Sized_incr_relobj::do_section_info): New function.
	(Sized_incr_relobj::do_section_addralign): New function.
	(Sized_incr_relobj::do_initialize_xindex): New function.
	(Sized_incr_relobj::do_get_global_symbol_counts): New function.
	(Sized_incr_relobj::do_read_relocs): New function.
	(Sized_incr_relobj::do_gc_process_relocs): New function.
	(Sized_incr_relobj::do_scan_relocs): New function.
	(Sized_incr_relobj::do_count_local_symbols): New function.
	(Sized_incr_relobj::do_finalize_local_symbols): New function.
	(Sized_incr_relobj::do_set_local_dynsym_indexes): New function.
	(Sized_incr_relobj::do_set_local_dynsym_offset): New function.
	(Sized_incr_relobj::do_relocate): New function.
	(Sized_incr_relobj::do_set_section_offset): New function.
	(Sized_incr_dynobj::Sized_incr_dynobj): New function.
	(Sized_incr_dynobj::do_read_symbols): New function.
	(Sized_incr_dynobj::do_layout): New function.
	(Sized_incr_dynobj::do_add_symbols): New function.
	(Sized_incr_dynobj::do_should_include_member): New function.
	(Sized_incr_dynobj::do_for_all_global_symbols): New function.
	(Sized_incr_dynobj::do_for_all_local_got_entries): New function.
	(Sized_incr_dynobj::do_section_size): New function.
	(Sized_incr_dynobj::do_section_name): New function.
	(Sized_incr_dynobj::do_section_contents): New function.
	(Sized_incr_dynobj::do_section_flags): New function.
	(Sized_incr_dynobj::do_section_entsize): New function.
	(Sized_incr_dynobj::do_section_address): New function.
	(Sized_incr_dynobj::do_section_type): New function.
	(Sized_incr_dynobj::do_section_link): New function.
	(Sized_incr_dynobj::do_section_info): New function.
	(Sized_incr_dynobj::do_section_addralign): New function.
	(Sized_incr_dynobj::do_initialize_xindex): New function.
	(Sized_incr_dynobj::do_get_global_symbol_counts): New function.
	(make_sized_incremental_object): New function.
	(Incremental_library::copy_unused_symbols): New function.
	(Incremental_library::do_for_all_unused_symbols): New function.
	* gold/incremental.h (enum Incremental_input_flags): New type.
	(class Incremental_checker): Remove.
	(Incremental_input_entry::Incremental_input_entry): Add argument
	serial number.
	(Incremental_input_entry::arg_serial): New function.
	(Incremental_input_entry::set_is_in_system_directory): New function.
	(Incremental_input_entry::is_in_system_directory): New function.
	(Incremental_input_entry::arg_serial_): New data member.
	(Incremental_input_entry::is_in_system_directory_): New data member.
	(class Script_info): Move here from script.h.
	(Script_info::Script_info): Add filename parameter.
	(Script_info::filename): New function.
	(Script_info::filename_): New data member.
	(Incremental_script_entry::Incremental_script_entry): Add argument
	serial number.
	(Incremental_object_entry::Incremental_object_entry): Likewise.
	(Incremental_object_entry::add_input_section): Build list of input
	sections with map to original shndx.
	(Incremental_object_entry::get_input_section_index): New function.
	(Incremental_object_entry::shndx_): New data member.
	(Incremental_object_entry::name_key_): Rename; adjust all refs.
	(Incremental_object_entry::sh_size_): Rename; adjust all refs.
	(Incremental_archive_entry::Incremental_archive_entry): Add argument
	serial number.
	(Incremental_inputs::report_archive_begin): Likewise.
	(Incremental_inputs::report_object): Likewise.
	(Incremental_inputs::report_script): Likewise.
	(class Incremental_global_symbol_reader): New class.
	(Incremental_input_entry_reader::Incremental_input_entry_reader): Read
	and store flags and input file type.
	(Incremental_input_entry_reader::arg_serial): New function.
	(Incremental_input_entry_reader::type): Extract type from flags.
	(Incremental_input_entry_reader::is_in_system_directory): New function.
	(Incremental_input_entry_reader::get_input_section_count): Call
	accessor function for type.
	(Incremental_input_entry_reader::get_symbol_offset): Call accessor
	function for type; adjust size of global symbol entry.
	(Incremental_input_entry_reader::get_global_symbol_count): Call
	accessor function for type.
	(Incremental_input_entry_reader::get_object_count): Likewise.
	(Incremental_input_entry_reader::get_object_offset): Likewise.
	(Incremental_input_entry_reader::get_member_count): Likewise.
	(Incremental_input_entry_reader::get_unused_symbol_count): Likewise.
	(Incremental_input_entry_reader::get_member_offset): Likewise.
	(Incremental_input_entry_reader::get_unused_symbol): Likewise.
	(Incremental_input_entry_reader::Global_symbol_info): Remove.
	(Incremental_input_entry_reader::get_global_symbol_info): Remove.
	(Incremental_input_entry_reader::get_global_symbol_reader): New
	function.
	(Incremental_input_entry_reader::get_output_symbol_index): New
	function.
	(Incremental_input_entry_reader::type_): Remove.
	(Incremental_input_entry_reader::flags_): New data member.
	(Incremental_inputs_reader::input_file_offset): New function.
	(Incremental_inputs_reader::input_file_index): New function.
	(Incremental_inputs_reader::input_file): Call input_file_offset.
	(Incremental_inputs_reader::input_file_at_offset): New function.
	(Incremental_relocs_reader::get_r_type): Reformat.
	(Incremental_relocs_reader::get_r_shndx): Reformat.
	(Incremental_relocs_reader::get_r_offset): Reformat.
	(Incremental_relocs_reader::data): New function.
	(Incremental_binary::Incremental_binary): Initialize new data members.
	(Incremental_binary::check_inputs): Add cmdline parameter.
	(Incremental_binary::file_is_unchanged): Remove.
	(Input_reader::arg_serial): New function.
	(Input_reader::get_unused_symbol_count): New function.
	(Input_reader::get_unused_symbol): New function.
	(Input_reader::do_arg_serial): New function.
	(Input_reader::do_get_unused_symbol_count): New function.
	(Input_reader::do_get_unused_symbol): New function.
	(Incremental_binary::input_file_count): New function.
	(Incremental_binary::get_input_reader): Change signature to use
	index instead of filename.
	(Incremental_binary::file_has_changed): New function.
	(Incremental_binary::get_input_argument): New function.
	(Incremental_binary::get_library): New function.
	(Incremental_binary::get_script_info): New function.
	(Incremental_binary::init_layout): New function.
	(Incremental_binary::reserve_layout): New function.
	(Incremental_binary::output_file): New function.
	(Incremental_binary::do_check_inputs): New function.
	(Incremental_binary::do_file_is_unchanged): Remove.
	(Incremental_binary::do_file_has_changed): New function.
	(Incremental_binary::do_init_layout): New function.
	(Incremental_binary::do_reserve_layout): New function.
	(Incremental_binary::do_input_file_count): New function.
	(Incremental_binary::do_get_input_reader): Change signature.
	(Incremental_binary::input_args_map_): New data member.
	(Incremental_binary::library_map_): New data member.
	(Incremental_binary::script_map_): New data member.
	(Sized_incremental_binary::Sized_incremental_binary): Initialize
	new data members.
	(Sized_incremental_binary::output_section): New function.
	(Sized_incremental_binary::inputs_reader): Add const.
	(Sized_incremental_binary::symtab_reader): Add const.
	(Sized_incremental_binary::relocs_reader): Add const.
	(Sized_incremental_binary::got_plt_reader): Add const.
	(Sized_incremental_binary::get_symtab_view): New function.
	(Sized_incremental_binary::Inputs_reader): New typedef.
	(Sized_incremental_binary::Input_entry_reader): New typedef.
	(Sized_incremental_binary::do_check_inputs): Add cmdline parameter.
	(Sized_incremental_binary::do_file_is_unchanged): Remove.
	(Sized_incremental_binary::do_file_has_changed): New function.
	(Sized_incremental_binary::do_init_layout): New function.
	(Sized_incremental_binary::do_reserve_layout): New function.
	(Sized_input_reader::Inputs_reader): Remove.
	(Sized_input_reader::Input_entry_reader): Remove.
	(Sized_input_reader::do_arg_serial): New function.
	(Sized_input_reader::do_get_unused_symbol_count): New function.
	(Sized_input_reader::do_get_unused_symbol): New function.
	(Sized_incremental_binary::do_input_file_count): New function.
	(Sized_incremental_binary::do_get_input_reader): Change signature;
	use index instead of filename.
	(Sized_incremental_binary::section_map_): New data member.
	(Sized_incremental_binary::input_entry_readers_): New data member.
	(class Sized_incr_relobj): New class.
	(class Sized_incr_dynobj): New class.
	(make_sized_incremental_object): New function.
	(class Incremental_library): New class.
	* gold/layout.cc (Free_list::num_lists): New static data member.
	(Free_list::num_nodes): New static data member.
	(Free_list::num_removes): New static data member.
	(Free_list::num_remove_visits): New static data member.
	(Free_list::num_allocates): New static data member.
	(Free_list::num_allocate_visits): New static data member.
	(Free_list::init): New function.
	(Free_list::remove): New function.
	(Free_list::allocate): New function.
	(Free_list::dump): New function.
	(Free_list::print_stats): New function.
	(Layout_task_runner::run): Resize output file for incremental updates.
	(Layout::Layout): Initialize new data members.
	(Layout::set_incremental_base): New function.
	(Layout::init_fixed_output_section): New function.
	(Layout::layout_eh_frame): Do not build .eh_frame_hdr section for
	incremental updates.
	(Layout::create_gold_note): Do not create gold note section for
	incremental updates.
	(Layout::set_segment_offsets): Do not recalculate RELRO alignment
	for incremental updates.
	(Layout::set_section_offsets): For incremental updates, allocate space
	from free list.
	(Layout::create_symtab_sections): Layout with offsets relative to
	start of section; for incremental updates, allocate space from free
	list.
	(Layout::create_shdrs): For incremental updates, allocate space from
	free list.
	(Layout::finish_dynamic_section): For incremental updates, do not
	check --as-needed (fixed in subsequent patch).
	* gold/layout.h (class Free_list): New class.
	(Layout::set_incremental_base): New function.
	(Layout::incremental_base): New function.
	(Layout::init_fixed_output_section): New function.
	(Layout::allocate): New function.
	(Layout::incremental_base_): New data member.
	(Layout::free_list_): New data member.
	* gold/main.cc (main): Print Free_list statistics.
	* gold/object.cc (Relobj::finalize_incremental_relocs): Add
	clear_counts parameter; clear counts only when clear_counts is set.
	(Sized_relobj::Sized_relobj): Initialize new base class.
	(Sized_relobj::do_layout): Don't report special sections.
	(Sized_relobj::do_for_all_local_got_entries): New function.
	(Sized_relobj::write_local_symbols): Add symtab_off parameter; add
	symtab_off to all symbol table offsets.
	(Sized_relobj::do_get_global_symbol_counts): Add typename keyword.
	* gold/object.h (class Got_offset_list): Move to top of file.
	(Object::Object): Allow case where input_file == NULL.
	(Object::~Object): Likewise.
	(Object::input_file): Assert that input_file != NULL.
	(Object::lock): Allow case where input_file == NULL.
	(Object::unlock): Likewise.
	(Object::is_locked): Likewise.
	(Object::token): Likewise.
	(Object::release): Likewise.
	(Object::is_incremental): New function.
	(Object::get_mtime): New function.
	(Object::for_all_local_got_entries): New function.
	(Object::clear_view_cache_marks): Allow case where input_file == NULL.
	(Object::set_is_in_system_directory): New function.
	(Object::is_in_system_directory): New function.
	(Object::do_is_incremental): New function.
	(Object::do_get_mtime): New function.
	(Object::do_for_all_local_got_entries): New function.
	(Object::is_in_system_directory_): New data member.
	(Relobj::finalize_incremental_relocs): Add clear_counts parameter.
	(class Sized_relobj_base): New class.
	(class Sized_relobj): Derive from Sized_relobj_base.
	(class Sized_relobj::Symbols): Redeclare from base class.
	(class Sized_relobj::local_got_offset_list): Remove.
	(class Sized_relobj::Output_sections): Redeclare from base class.
	(class Sized_relobj::do_for_all_local_got_entries): New function.
	(class Sized_relobj::write_local_symbols): Add offset parameter.
	(class Sized_relobj::local_symbol_offset_): Update comment.
	(class Sized_relobj::local_dynsym_offset_): Update comment.
	* gold/options.cc (Input_arguments::add_file): Remove const.
	* gold/options.h (Input_file_argument::Input_file_argument):
	Initialize arg_serial_ (all constructors).
	(Input_file_argument::set_arg_serial): New function.
	(Input_file_argument::arg_serial): New function.
	(Input_file_argument::arg_serial_): New data member.
	(Input_arguments::Input_arguments): Initialize file_count_.
	(Input_arguments::add_file): Remove const.
	(Input_arguments::number_of_input_files): New function.
	(Input_arguments::file_count_): New data member.
	(Command_line::number_of_input_files): Call
	Input_arguments::number_of_input_files.
	* gold/output.cc (Output_segment_headers::Output_segment_headers):
	Set current size.
	(Output_section::Input_section::current_data_size): New function.
	(Output_section::Output_section): Initialize new data members.
	(Output_section::add_input_section): Don't do merge sections for
	an incremental link; allocate space from free list for an
	incremental update.
	(Output_section::add_output_section_data): Allocate space from
	free list for an incremental update.
	(Output_section::update_data_size): New function.
	(Output_section::set_fixed_layout): New function.
	(Output_section::reserve): New function.
	(Output_segment::set_section_addresses): Remove const.
	(Output_segment::set_section_list_addresses): Remove const; allocate
	space from free list for an incremental update.
	(Output_segment::set_offset): Adjust size of RELRO segment for an
	incremental update.
	* gold/output.h (Output_data::current_data_size): Move here from
	child classes.
	(Output_data::pre_finalize_data_size): New function.
	(Output_data::update_data_size): New function.
	(Output_section_headers::update_data_size): new function.
	(Output_section_data_build::current_data_size): Move to Output_data.
	(Output_data_strtab::update_data_size): New function.
	(Output_section::current_data_size): Move to Output_data.
	(Output_section::set_fixed_layout): New function.
	(Output_section::has_fixed_layout): New function.
	(Output_section::reserve): New function.
	(Output_section::update_data_size): New function.
	(Output_section::has_fixed_layout_): New data member.
	(Output_section::free_list_): New data member.
	(Output_segment::set_section_addresses): Remove const.
	(Output_segment::set_section_list_addresses): Remove const.
	* gold/plugin.cc (Sized_pluginobj::do_for_all_local_got_entries):
	New function.
	* gold/plugin.h (Sized_pluginobj::do_for_all_local_got_entries):
	New function.
	* gold/readsyms.cc (Read_symbols::do_read_symbols): Add library
	parameter when calling Add_symbols constructor; store argument
	serial number for members of a lib group.
	(Add_symbols::locks): Allow case where token == NULL.
	(Add_symbols::run): Report libraries denoted by --start-lib/--end-lib.
	(Read_member::~Read_member): New function.
	(Read_member::is_runnable): New function.
	(Read_member::locks): New function.
	(Read_member::run): New function.
	(Check_script::~Check_script): New function.
	(Check_script::is_runnable): New function.
	(Check_script::locks): New function.
	(Check_script::run): New function.
	(Check_library::~Check_library): New function.
	(Check_library::is_runnable): New function.
	(Check_library::locks): New function.
	(Check_library::run): New function.
	* gold/readsyms.h (Add_symbols::Add_symbols): Add library parameter.
	(Add_symbols::library_): New data member.
	(class Read_member): New class.
	(class Check_script): New class.
	(class Check_library): New class.
	* gold/reloc.cc (Read_relocs::is_runnable): Allow case where
	token == NULL.
	(Read_relocs::locks): Likewise.
	(Scan_relocs::locks): Likewise.
	(Relocate_task::locks): Likewise.
	(Sized_relobj::do_scan_relocs): Tell finalize_incremental_relocs
	to clear counters.
	(Sized_relobj::incremental_relocs_scan): Fix comment.
	(Sized_relobj::do_relocate): Pass output file offset to
	write_local_symbols.
	(Sized_relobj::incremental_relocs_write_reltype): Use reloc_size
	from class declaration.
	* gold/script.cc (read_input_script): Allocate Script_info; pass
	argument serial number to report_script.
	* gold/script.h (class Script_info): Move to incremental.h.
	* gold/symtab.cc (Symbol_table::add_from_incrobj): New function.
	* gold/symtab.h (Symbol_table::add_from_incrobj): New function.
	(Symbol_table::set_file_offset): New function.
-------------- next part --------------
Initial support for incremental update.


2011-03-28 Cary Coutant  <ccoutant@google.com>

	* gold/archive.cc (Archive::include_member): Adjust call to
	report_object.
	(Add_archive_symbols::run): Track argument serial numbers.
	(Lib_group::include_member): Likewise.
	(Add_lib_group_symbols::run): Adjust call to report_archive_begin.
	* gold/archive.h (Incremental_archive_entry::Archive_member):
	Initialize arg_serial_.
	(Archive_member::arg_serial_): New data member.
	* gold/dynobj.cc (Dynobj::Dynobj): Allow input_file_ to be NULL.
	(Sized_dynobj::do_add_symbols): Track symbols when doing an
	incremental link.
	(Sized_dynobj::do_for_all_local_got_entries): New function.
	* gold/dynobj.h: (Sized_dynobj::do_for_all_local_got_entries): New
	function.
	* gold/fileread.cc (get_mtime): New function.
	* gold/fileread.h (get_mtime): New function.
	* gold/gold.cc (queue_initial_tasks): Check for incremental update.
	(process_incremental_input): New function.
	(queue_middle_tasks): Don't force valid target for incremental
	update.
	* gold/incremental-dump.cc (find_input_containing_global): Adjust
	size of symbol info entry.
	(dump_incremental_inputs): Dump argument serial number and
	in_system_directory flag; bias shndx by 1; print symbol names
	when dumping per-file symbol lists; use new symbol info readers.
	* gold/incremental.cc
	(Output_section_incremental_inputs:update_data_size): New function.
	(Sized_incremental_binary::setup_readers): Setup input readers
	for each input file; build maps for files added from libraries
	and scripts.
	(Sized_incremental_binary::check_input_args): New function.
	(Sized_incremental_binary::do_check_inputs): Build map of argument
	serial numbers to input arguments.
	(Sized_incremental_binary::do_file_has_changed): Rename
	do_file_is_unchanged to this; compare file modification times.
	(Sized_incremental_binary::do_init_layout): New function.
	(Sized_incremental_binary::do_reserve_layout): New function.
	(Sized_incremental_binary::do_get_input_reader): Remove.
	(Sized_incremental_binary::get_symtab_view): New function.
	(Incremental_checker::can_incrementally_link_output_file): Remove.
	(Incremental_inputs::report_command_line): Exclude --debug options.
	(Incremental_inputs::report_archive_begin): Add parameter; track
	argument serial numbers; don't put input file entry for archive
	before archive members.
	(Incremental_inputs::report_archive_end): Put input file entry
	for archive after archive members.
	(Incremental_inputs::report_object): Add parameter; track argument
	serial numbers and in_system_directory flag.
	(Incremental_inputs::report_script): Add parameter; track argument
	serial numbers.
	(Output_section_incremental_inputs::set_final_data_size): Adjust
	size of symbol info entry; check for forwarding symbols.
	(Output_section_incremental_inputs::write_input_files): Write
	in_system_directory flag and argument serial number.
	(Output_section_incremental_inputs::write_info_blocks): Map section
	indices between incremental info and original input file; store
	input section index for each symbol.
	(class Local_got_offset_visitor): Derive from Got_offset_list::Visitor;
	change operator() to visit().
	(class Global_got_offset_visitor): Likewise.
	(class Global_symbol_visitor_got_plt):
	(Output_section_incremental_inputs::write_got_plt): Use new visitor
	classes.
	(Sized_incr_relobj::Sized_incr_relobj): New constructor.
	(Sized_incr_relobj::do_read_symbols): New function.
	(Sized_incr_relobj::do_layout): New function.
	(Sized_incr_relobj::do_layout_deferred_sections): New function.
	(Sized_incr_relobj::do_add_symbols): New function.
	(Sized_incr_relobj::do_should_include_member): New function.
	(Sized_incr_relobj::do_for_all_global_symbols): New function.
	(Sized_incr_relobj::do_for_all_local_got_entries): New function.
	(Sized_incr_relobj::do_section_size): New function.
	(Sized_incr_relobj::do_section_name): New function.
	(Sized_incr_relobj::do_section_contents): New function.
	(Sized_incr_relobj::do_section_flags): New function.
	(Sized_incr_relobj::do_section_entsize): New function.
	(Sized_incr_relobj::do_section_address): New function.
	(Sized_incr_relobj::do_section_type): New function.
	(Sized_incr_relobj::do_section_link): New function.
	(Sized_incr_relobj::do_section_info): New function.
	(Sized_incr_relobj::do_section_addralign): New function.
	(Sized_incr_relobj::do_initialize_xindex): New function.
	(Sized_incr_relobj::do_get_global_symbol_counts): New function.
	(Sized_incr_relobj::do_read_relocs): New function.
	(Sized_incr_relobj::do_gc_process_relocs): New function.
	(Sized_incr_relobj::do_scan_relocs): New function.
	(Sized_incr_relobj::do_count_local_symbols): New function.
	(Sized_incr_relobj::do_finalize_local_symbols): New function.
	(Sized_incr_relobj::do_set_local_dynsym_indexes): New function.
	(Sized_incr_relobj::do_set_local_dynsym_offset): New function.
	(Sized_incr_relobj::do_relocate): New function.
	(Sized_incr_relobj::do_set_section_offset): New function.
	(Sized_incr_dynobj::Sized_incr_dynobj): New function.
	(Sized_incr_dynobj::do_read_symbols): New function.
	(Sized_incr_dynobj::do_layout): New function.
	(Sized_incr_dynobj::do_add_symbols): New function.
	(Sized_incr_dynobj::do_should_include_member): New function.
	(Sized_incr_dynobj::do_for_all_global_symbols): New function.
	(Sized_incr_dynobj::do_for_all_local_got_entries): New function.
	(Sized_incr_dynobj::do_section_size): New function.
	(Sized_incr_dynobj::do_section_name): New function.
	(Sized_incr_dynobj::do_section_contents): New function.
	(Sized_incr_dynobj::do_section_flags): New function.
	(Sized_incr_dynobj::do_section_entsize): New function.
	(Sized_incr_dynobj::do_section_address): New function.
	(Sized_incr_dynobj::do_section_type): New function.
	(Sized_incr_dynobj::do_section_link): New function.
	(Sized_incr_dynobj::do_section_info): New function.
	(Sized_incr_dynobj::do_section_addralign): New function.
	(Sized_incr_dynobj::do_initialize_xindex): New function.
	(Sized_incr_dynobj::do_get_global_symbol_counts): New function.
	(make_sized_incremental_object): New function.
	(Incremental_library::copy_unused_symbols): New function.
	(Incremental_library::do_for_all_unused_symbols): New function.
	* gold/incremental.h (enum Incremental_input_flags): New type.
	(class Incremental_checker): Remove.
	(Incremental_input_entry::Incremental_input_entry): Add argument
	serial number.
	(Incremental_input_entry::arg_serial): New function.
	(Incremental_input_entry::set_is_in_system_directory): New function.
	(Incremental_input_entry::is_in_system_directory): New function.
	(Incremental_input_entry::arg_serial_): New data member.
	(Incremental_input_entry::is_in_system_directory_): New data member.
	(class Script_info): Move here from script.h.
	(Script_info::Script_info): Add filename parameter.
	(Script_info::filename): New function.
	(Script_info::filename_): New data member.
	(Incremental_script_entry::Incremental_script_entry): Add argument
	serial number.
	(Incremental_object_entry::Incremental_object_entry): Likewise.
	(Incremental_object_entry::add_input_section): Build list of input
	sections with map to original shndx.
	(Incremental_object_entry::get_input_section_index): New function.
	(Incremental_object_entry::shndx_): New data member.
	(Incremental_object_entry::name_key_): Rename; adjust all refs.
	(Incremental_object_entry::sh_size_): Rename; adjust all refs.
	(Incremental_archive_entry::Incremental_archive_entry): Add argument
	serial number.
	(Incremental_inputs::report_archive_begin): Likewise.
	(Incremental_inputs::report_object): Likewise.
	(Incremental_inputs::report_script): Likewise.
	(class Incremental_global_symbol_reader): New class.
	(Incremental_input_entry_reader::Incremental_input_entry_reader): Read
	and store flags and input file type.
	(Incremental_input_entry_reader::arg_serial): New function.
	(Incremental_input_entry_reader::type): Extract type from flags.
	(Incremental_input_entry_reader::is_in_system_directory): New function.
	(Incremental_input_entry_reader::get_input_section_count): Call
	accessor function for type.
	(Incremental_input_entry_reader::get_symbol_offset): Call accessor
	function for type; adjust size of global symbol entry.
	(Incremental_input_entry_reader::get_global_symbol_count): Call
	accessor function for type.
	(Incremental_input_entry_reader::get_object_count): Likewise.
	(Incremental_input_entry_reader::get_object_offset): Likewise.
	(Incremental_input_entry_reader::get_member_count): Likewise.
	(Incremental_input_entry_reader::get_unused_symbol_count): Likewise.
	(Incremental_input_entry_reader::get_member_offset): Likewise.
	(Incremental_input_entry_reader::get_unused_symbol): Likewise.
	(Incremental_input_entry_reader::Global_symbol_info): Remove.
	(Incremental_input_entry_reader::get_global_symbol_info): Remove.
	(Incremental_input_entry_reader::get_global_symbol_reader): New
	function.
	(Incremental_input_entry_reader::get_output_symbol_index): New
	function.
	(Incremental_input_entry_reader::type_): Remove.
	(Incremental_input_entry_reader::flags_): New data member.
	(Incremental_inputs_reader::input_file_offset): New function.
	(Incremental_inputs_reader::input_file_index): New function.
	(Incremental_inputs_reader::input_file): Call input_file_offset.
	(Incremental_inputs_reader::input_file_at_offset): New function.
	(Incremental_relocs_reader::get_r_type): Reformat.
	(Incremental_relocs_reader::get_r_shndx): Reformat.
	(Incremental_relocs_reader::get_r_offset): Reformat.
	(Incremental_relocs_reader::data): New function.
	(Incremental_binary::Incremental_binary): Initialize new data members.
	(Incremental_binary::check_inputs): Add cmdline parameter.
	(Incremental_binary::file_is_unchanged): Remove.
	(Input_reader::arg_serial): New function.
	(Input_reader::get_unused_symbol_count): New function.
	(Input_reader::get_unused_symbol): New function.
	(Input_reader::do_arg_serial): New function.
	(Input_reader::do_get_unused_symbol_count): New function.
	(Input_reader::do_get_unused_symbol): New function.
	(Incremental_binary::input_file_count): New function.
	(Incremental_binary::get_input_reader): Change signature to use
	index instead of filename.
	(Incremental_binary::file_has_changed): New function.
	(Incremental_binary::get_input_argument): New function.
	(Incremental_binary::get_library): New function.
	(Incremental_binary::get_script_info): New function.
	(Incremental_binary::init_layout): New function.
	(Incremental_binary::reserve_layout): New function.
	(Incremental_binary::output_file): New function.
	(Incremental_binary::do_check_inputs): New function.
	(Incremental_binary::do_file_is_unchanged): Remove.
	(Incremental_binary::do_file_has_changed): New function.
	(Incremental_binary::do_init_layout): New function.
	(Incremental_binary::do_reserve_layout): New function.
	(Incremental_binary::do_input_file_count): New function.
	(Incremental_binary::do_get_input_reader): Change signature.
	(Incremental_binary::input_args_map_): New data member.
	(Incremental_binary::library_map_): New data member.
	(Incremental_binary::script_map_): New data member.
	(Sized_incremental_binary::Sized_incremental_binary): Initialize
	new data members.
	(Sized_incremental_binary::output_section): New function.
	(Sized_incremental_binary::inputs_reader): Add const.
	(Sized_incremental_binary::symtab_reader): Add const.
	(Sized_incremental_binary::relocs_reader): Add const.
	(Sized_incremental_binary::got_plt_reader): Add const.
	(Sized_incremental_binary::get_symtab_view): New function.
	(Sized_incremental_binary::Inputs_reader): New typedef.
	(Sized_incremental_binary::Input_entry_reader): New typedef.
	(Sized_incremental_binary::do_check_inputs): Add cmdline parameter.
	(Sized_incremental_binary::do_file_is_unchanged): Remove.
	(Sized_incremental_binary::do_file_has_changed): New function.
	(Sized_incremental_binary::do_init_layout): New function.
	(Sized_incremental_binary::do_reserve_layout): New function.
	(Sized_input_reader::Inputs_reader): Remove.
	(Sized_input_reader::Input_entry_reader): Remove.
	(Sized_input_reader::do_arg_serial): New function.
	(Sized_input_reader::do_get_unused_symbol_count): New function.
	(Sized_input_reader::do_get_unused_symbol): New function.
	(Sized_incremental_binary::do_input_file_count): New function.
	(Sized_incremental_binary::do_get_input_reader): Change signature;
	use index instead of filename.
	(Sized_incremental_binary::section_map_): New data member.
	(Sized_incremental_binary::input_entry_readers_): New data member.
	(class Sized_incr_relobj): New class.
	(class Sized_incr_dynobj): New class.
	(make_sized_incremental_object): New function.
	(class Incremental_library): New class.
	* gold/layout.cc (Free_list::num_lists): New static data member.
	(Free_list::num_nodes): New static data member.
	(Free_list::num_removes): New static data member.
	(Free_list::num_remove_visits): New static data member.
	(Free_list::num_allocates): New static data member.
	(Free_list::num_allocate_visits): New static data member.
	(Free_list::init): New function.
	(Free_list::remove): New function.
	(Free_list::allocate): New function.
	(Free_list::dump): New function.
	(Free_list::print_stats): New function.
	(Layout_task_runner::run): Resize output file for incremental updates.
	(Layout::Layout): Initialize new data members.
	(Layout::set_incremental_base): New function.
	(Layout::init_fixed_output_section): New function.
	(Layout::layout_eh_frame): Do not build .eh_frame_hdr section for
	incremental updates.
	(Layout::create_gold_note): Do not create gold note section for
	incremental updates.
	(Layout::set_segment_offsets): Do not recalculate RELRO alignment
	for incremental updates.
	(Layout::set_section_offsets): For incremental updates, allocate space
	from free list.
	(Layout::create_symtab_sections): Layout with offsets relative to
	start of section; for incremental updates, allocate space from free
	list.
	(Layout::create_shdrs): For incremental updates, allocate space from
	free list.
	(Layout::finish_dynamic_section): For incremental updates, do not
	check --as-needed (fixed in subsequent patch).
	* gold/layout.h (class Free_list): New class.
	(Layout::set_incremental_base): New function.
	(Layout::incremental_base): New function.
	(Layout::init_fixed_output_section): New function.
	(Layout::allocate): New function.
	(Layout::incremental_base_): New data member.
	(Layout::free_list_): New data member.
	* gold/main.cc (main): Print Free_list statistics.
	* gold/object.cc (Relobj::finalize_incremental_relocs): Add
	clear_counts parameter; clear counts only when clear_counts is set.
	(Sized_relobj::Sized_relobj): Initialize new base class.
	(Sized_relobj::do_layout): Don't report special sections.
	(Sized_relobj::do_for_all_local_got_entries): New function.
	(Sized_relobj::write_local_symbols): Add symtab_off parameter; add
	symtab_off to all symbol table offsets.
	(Sized_relobj::do_get_global_symbol_counts): Add typename keyword.
	* gold/object.h (class Got_offset_list): Move to top of file.
	(Object::Object): Allow case where input_file == NULL.
	(Object::~Object): Likewise.
	(Object::input_file): Assert that input_file != NULL.
	(Object::lock): Allow case where input_file == NULL.
	(Object::unlock): Likewise.
	(Object::is_locked): Likewise.
	(Object::token): Likewise.
	(Object::release): Likewise.
	(Object::is_incremental): New function.
	(Object::get_mtime): New function.
	(Object::for_all_local_got_entries): New function.
	(Object::clear_view_cache_marks): Allow case where input_file == NULL.
	(Object::set_is_in_system_directory): New function.
	(Object::is_in_system_directory): New function.
	(Object::do_is_incremental): New function.
	(Object::do_get_mtime): New function.
	(Object::do_for_all_local_got_entries): New function.
	(Object::is_in_system_directory_): New data member.
	(Relobj::finalize_incremental_relocs): Add clear_counts parameter.
	(class Sized_relobj_base): New class.
	(class Sized_relobj): Derive from Sized_relobj_base.
	(class Sized_relobj::Symbols): Redeclare from base class.
	(class Sized_relobj::local_got_offset_list): Remove.
	(class Sized_relobj::Output_sections): Redeclare from base class.
	(class Sized_relobj::do_for_all_local_got_entries): New function.
	(class Sized_relobj::write_local_symbols): Add offset parameter.
	(class Sized_relobj::local_symbol_offset_): Update comment.
	(class Sized_relobj::local_dynsym_offset_): Update comment.
	* gold/options.cc (Input_arguments::add_file): Remove const.
	* gold/options.h (Input_file_argument::Input_file_argument):
	Initialize arg_serial_ (all constructors).
	(Input_file_argument::set_arg_serial): New function.
	(Input_file_argument::arg_serial): New function.
	(Input_file_argument::arg_serial_): New data member.
	(Input_arguments::Input_arguments): Initialize file_count_.
	(Input_arguments::add_file): Remove const.
	(Input_arguments::number_of_input_files): New function.
	(Input_arguments::file_count_): New data member.
	(Command_line::number_of_input_files): Call
	Input_arguments::number_of_input_files.
	* gold/output.cc (Output_segment_headers::Output_segment_headers):
	Set current size.
	(Output_section::Input_section::current_data_size): New function.
	(Output_section::Output_section): Initialize new data members.
	(Output_section::add_input_section): Don't do merge sections for
	an incremental link; allocate space from free list for an
	incremental update.
	(Output_section::add_output_section_data): Allocate space from
	free list for an incremental update.
	(Output_section::update_data_size): New function.
	(Output_section::set_fixed_layout): New function.
	(Output_section::reserve): New function.
	(Output_segment::set_section_addresses): Remove const.
	(Output_segment::set_section_list_addresses): Remove const; allocate
	space from free list for an incremental update.
	(Output_segment::set_offset): Adjust size of RELRO segment for an
	incremental update.
	* gold/output.h (Output_data::current_data_size): Move here from
	child classes.
	(Output_data::pre_finalize_data_size): New function.
	(Output_data::update_data_size): New function.
	(Output_section_headers::update_data_size): new function.
	(Output_section_data_build::current_data_size): Move to Output_data.
	(Output_data_strtab::update_data_size): New function.
	(Output_section::current_data_size): Move to Output_data.
	(Output_section::set_fixed_layout): New function.
	(Output_section::has_fixed_layout): New function.
	(Output_section::reserve): New function.
	(Output_section::update_data_size): New function.
	(Output_section::has_fixed_layout_): New data member.
	(Output_section::free_list_): New data member.
	(Output_segment::set_section_addresses): Remove const.
	(Output_segment::set_section_list_addresses): Remove const.
	* gold/plugin.cc (Sized_pluginobj::do_for_all_local_got_entries):
	New function.
	* gold/plugin.h (Sized_pluginobj::do_for_all_local_got_entries):
	New function.
	* gold/readsyms.cc (Read_symbols::do_read_symbols): Add library
	parameter when calling Add_symbols constructor; store argument
	serial number for members of a lib group.
	(Add_symbols::locks): Allow case where token == NULL.
	(Add_symbols::run): Report libraries denoted by --start-lib/--end-lib.
	(Read_member::~Read_member): New function.
	(Read_member::is_runnable): New function.
	(Read_member::locks): New function.
	(Read_member::run): New function.
	(Check_script::~Check_script): New function.
	(Check_script::is_runnable): New function.
	(Check_script::locks): New function.
	(Check_script::run): New function.
	(Check_library::~Check_library): New function.
	(Check_library::is_runnable): New function.
	(Check_library::locks): New function.
	(Check_library::run): New function.
	* gold/readsyms.h (Add_symbols::Add_symbols): Add library parameter.
	(Add_symbols::library_): New data member.
	(class Read_member): New class.
	(class Check_script): New class.
	(class Check_library): New class.
	* gold/reloc.cc (Read_relocs::is_runnable): Allow case where
	token == NULL.
	(Read_relocs::locks): Likewise.
	(Scan_relocs::locks): Likewise.
	(Relocate_task::locks): Likewise.
	(Sized_relobj::do_scan_relocs): Tell finalize_incremental_relocs
	to clear counters.
	(Sized_relobj::incremental_relocs_scan): Fix comment.
	(Sized_relobj::do_relocate): Pass output file offset to
	write_local_symbols.
	(Sized_relobj::incremental_relocs_write_reltype): Use reloc_size
	from class declaration.
	* gold/script.cc (read_input_script): Allocate Script_info; pass
	argument serial number to report_script.
	* gold/script.h (class Script_info): Move to incremental.h.
	* gold/symtab.cc (Symbol_table::add_from_incrobj): New function.
	* gold/symtab.h (Symbol_table::add_from_incrobj): New function.
	(Symbol_table::set_file_offset): New function.


diff --git a/gold/archive.cc b/gold/archive.cc
index 140d020..dffb3c1 100644
--- a/gold/archive.cc
+++ b/gold/archive.cc
@@ -946,7 +946,7 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
     {
       {
 	if (layout->incremental_inputs() != NULL)
-	  layout->incremental_inputs()->report_object(obj, this, NULL);
+	  layout->incremental_inputs()->report_object(obj, 0, this, NULL);
 	Read_symbols_data sd;
 	obj->read_symbols(&sd);
 	obj->layout(symtab, layout, &sd);
@@ -1026,8 +1026,12 @@ Add_archive_symbols::run(Workqueue* workqueue)
   // For an incremental link, begin recording layout information.
   Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
   if (incremental_inputs != NULL)
-    incremental_inputs->report_archive_begin(this->archive_,
-					this->input_argument_->script_info());
+    {
+      unsigned int arg_serial = this->input_argument_->file().arg_serial();
+      Script_info* script_info = this->input_argument_->script_info();
+      incremental_inputs->report_archive_begin(this->archive_, arg_serial,
+					       script_info);
+    }
 
   bool added = this->archive_->add_symbols(this->symtab_, this->layout_,
 					   this->input_objects_,
@@ -1183,7 +1187,8 @@ Lib_group::include_member(Symbol_table* symtab, Layout* layout,
   if (input_objects->add_object(obj))
     {
       if (layout->incremental_inputs() != NULL)
-	layout->incremental_inputs()->report_object(obj, this, NULL);
+	layout->incremental_inputs()->report_object(obj, member.arg_serial_,
+						    this, NULL);
       obj->layout(symtab, layout, sd);
       obj->add_symbols(symtab, sd, layout);
     }
@@ -1243,7 +1248,7 @@ Add_lib_group_symbols::run(Workqueue*)
   // For an incremental link, begin recording layout information.
   Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
   if (incremental_inputs != NULL)
-    incremental_inputs->report_archive_begin(this->lib_, NULL);
+    incremental_inputs->report_archive_begin(this->lib_, 0, NULL);
 
   this->lib_->add_symbols(this->symtab_, this->layout_, this->input_objects_);
 
diff --git a/gold/archive.h b/gold/archive.h
index 2e57076..bef1c2e 100644
--- a/gold/archive.h
+++ b/gold/archive.h
@@ -48,7 +48,7 @@ class Incremental_archive_entry;
 struct Archive_member
 {
   Archive_member()
-      : obj_(NULL), sd_(NULL)
+      : obj_(NULL), sd_(NULL), arg_serial_(0)
   { }
   Archive_member(Object* obj, Read_symbols_data* sd)
       : obj_(obj), sd_(sd)
@@ -57,6 +57,8 @@ struct Archive_member
   Object* obj_;
   // The data to pass from read_symbols() to add_symbols().
   Read_symbols_data* sd_;
+  // The serial number of the file in the argument list.
+  unsigned int arg_serial_;
 };
 
 // This class serves as a base class for Archive and Lib_group objects.
diff --git a/gold/dynobj.cc b/gold/dynobj.cc
index face503..4fe9b58 100644
--- a/gold/dynobj.cc
+++ b/gold/dynobj.cc
@@ -49,16 +49,23 @@ Dynobj::Dynobj(const std::string& name, Input_file* input_file, off_t offset)
   // object's filename.  The only exception is when the dynamic object
   // is part of an archive (so the filename is the archive's
   // filename).  In that case, we use just the dynobj's name-in-archive.
-  this->soname_ = this->input_file()->found_name();
-  if (this->offset() != 0)
+  if (input_file == NULL)
+    this->soname_ = name;
+  else
     {
-      std::string::size_type open_paren = this->name().find('(');
-      std::string::size_type close_paren = this->name().find(')');
-      if (open_paren != std::string::npos && close_paren != std::string::npos)
+      this->soname_ = input_file->found_name();
+      if (this->offset() != 0)
 	{
-	  // It's an archive, and name() is of the form 'foo.a(bar.so)'.
-	  this->soname_ = this->name().substr(open_paren + 1,
-					      close_paren - (open_paren + 1));
+	  std::string::size_type open_paren = this->name().find('(');
+	  std::string::size_type close_paren = this->name().find(')');
+	  if (open_paren != std::string::npos
+	      && close_paren != std::string::npos)
+	    {
+	      // It's an archive, and name() is of the form 'foo.a(bar.so)'.
+	      open_paren += 1;
+	      this->soname_ = this->name().substr(open_paren,
+						  close_paren - open_paren);
+	    }
 	}
     }
 }
@@ -705,10 +712,11 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
   Version_map version_map;
   this->make_version_map(sd, &version_map);
 
-  // If printing symbol counts or a cross reference table, we want to
-  // track symbols.
+  // If printing symbol counts or a cross reference table or
+  // preparing for an incremental link, we want to track symbols.
   if (parameters->options().user_set_print_symbol_counts()
-      || parameters->options().cref())
+      || parameters->options().cref()
+      || parameters->incremental())
     {
       this->symbols_ = new Symbols();
       this->symbols_->resize(symcount);
@@ -787,6 +795,16 @@ Sized_dynobj<size, big_endian>::do_for_all_global_symbols(
     }
 }
 
+// Iterate over local symbols, calling a visitor class V for each GOT offset
+// associated with a local symbol.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::do_for_all_local_got_entries(
+    Got_offset_list::Visitor&) const
+{
+}
+
 // Get symbol counts.
 
 template<int size, bool big_endian>
diff --git a/gold/dynobj.h b/gold/dynobj.h
index 637081c..8eb76b2 100644
--- a/gold/dynobj.h
+++ b/gold/dynobj.h
@@ -186,6 +186,11 @@ class Sized_dynobj : public Dynobj
   do_for_all_global_symbols(Read_symbols_data* sd,
 			    Library_base::Symbol_visitor_base& v);
 
+  // Iterate over local symbols, calling a visitor class V for each GOT offset
+  // associated with a local symbol.
+  void
+  do_for_all_local_got_entries(Got_offset_list::Visitor& v) const;
+
   // Get the size of a section.
   uint64_t
   do_section_size(unsigned int shndx)
diff --git a/gold/fileread.cc b/gold/fileread.cc
index 36485a9..553630a 100644
--- a/gold/fileread.cc
+++ b/gold/fileread.cc
@@ -58,6 +58,25 @@ readv(int, const iovec*, int)
 namespace gold
 {
 
+// Get the last modified time of an unopened file.
+
+bool
+get_mtime(const char* filename, Timespec* mtime)
+{
+  struct stat file_stat;
+  
+  if (stat(filename, &file_stat) < 0)
+    return false;
+#ifdef HAVE_STAT_ST_MTIM
+  mtime->seconds = file_stat.st_mtim.tv_sec;
+  mtime->nanoseconds = file_stat.st_mtim.tv_nsec;
+#else
+  mtime->seconds = file_stat.st_mtime;
+  mtime->nanoseconds = 0;
+#endif
+  return true;
+}
+
 // Class File_read.
 
 // A lock for the File_read static variables.
diff --git a/gold/fileread.h b/gold/fileread.h
index d2ac927..02c7a64 100644
--- a/gold/fileread.h
+++ b/gold/fileread.h
@@ -52,6 +52,12 @@ struct Timespec
   int nanoseconds;
 };
 
+// Get the last modified time of an unopened file.  Returns false if the
+// file does not exist.
+
+bool
+get_mtime(const char* filename, Timespec* mtime);
+
 class Position_dependent_options;
 class Input_file_argument;
 class Dirsearch;
diff --git a/gold/gold.cc b/gold/gold.cc
index 564ca39..7d17d3f 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -48,8 +48,15 @@
 namespace gold
 {
 
+class Object;
+
 const char* program_name;
 
+Task*
+process_incremental_input(Incremental_binary*, unsigned int, Input_objects*,
+			  Symbol_table*, Layout*, Dirsearch*, Mapfile*,
+			  Task_token*, Task_token*);
+
 void
 gold_exit(bool status)
 {
@@ -178,19 +185,50 @@ queue_initial_tasks(const General_options& options,
     thread_count = cmdline.number_of_input_files();
   workqueue->set_thread_count(thread_count);
 
+  // For incremental links, the base output file.
+  Incremental_binary* ibase = NULL;
+
   if (parameters->incremental())
     {
-      Incremental_checker incremental_checker(
-          parameters->options().output_file_name(),
-          layout->incremental_inputs());
-      if (incremental_checker.can_incrementally_link_output_file())
-        {
-          // TODO: remove when incremental linking implemented.
-          printf("Incremental linking might be possible "
-              "(not implemented yet)\n");
-        }
-      // TODO: If we decide on an incremental build, fewer tasks
-      // should be scheduled.
+      if (options.relocatable())
+	gold_error(_("incremental linking is incompatible with -r"));
+      if (options.emit_relocs())
+	gold_error(_("incremental linking is incompatible with --emit-relocs"));
+      if (options.gc_sections())
+	gold_error(_("incremental linking is incompatible with --gc-sections"));
+      if (options.icf_enabled())
+	gold_error(_("incremental linking is incompatible with --icf"));
+      if (options.has_plugins())
+	gold_error(_("incremental linking is incompatible with --plugin"));
+
+      if (parameters->incremental_update())
+	{
+	  Output_file* of = new Output_file(options.output_file_name());
+	  if (!of->open_for_modification())
+	    gold_info(_("incremental update not possible: "
+			"cannot open %s"),
+		      options.output_file_name());
+	  else
+	    {
+	      ibase = open_incremental_binary(of);
+	      if (ibase != NULL
+		  && ibase->check_inputs(cmdline, layout->incremental_inputs()))
+		ibase->init_layout(layout);
+	      else
+		{
+		  delete ibase;
+		  ibase = NULL;
+		  of->close();
+		}
+	    }
+	  if (ibase == NULL)
+	    {
+	      if (set_parameters_incremental_full())
+		gold_info(_("linking with --incremental-full"));
+	      else
+		gold_fatal(_("restart link with --incremental-full"));
+	    }
+	}
     }
 
   // Read the input files.  We have to add the symbols to the symbol
@@ -198,16 +236,47 @@ queue_initial_tasks(const General_options& options,
   // each input file.  We associate the blocker with the following
   // input file, to give us a convenient place to delete it.
   Task_token* this_blocker = NULL;
-  for (Command_line::const_iterator p = cmdline.begin();
-       p != cmdline.end();
-       ++p)
+  if (ibase == NULL)
     {
-      Task_token* next_blocker = new Task_token(true);
-      next_blocker->add_blocker();
-      workqueue->queue(new Read_symbols(input_objects, symtab, layout,
-					&search_path, 0, mapfile, &*p, NULL,
-					NULL, this_blocker, next_blocker));
-      this_blocker = next_blocker;
+      // Normal link.  Queue a Read_symbols task for each input file
+      // on the command line.
+      for (Command_line::const_iterator p = cmdline.begin();
+	   p != cmdline.end();
+	   ++p)
+	{
+	  Task_token* next_blocker = new Task_token(true);
+	  next_blocker->add_blocker();
+	  workqueue->queue(new Read_symbols(input_objects, symtab, layout,
+					    &search_path, 0, mapfile, &*p, NULL,
+					    NULL, this_blocker, next_blocker));
+	  this_blocker = next_blocker;
+	}
+    }
+  else
+    {
+      // Incremental update link.  Process the list of input files
+      // stored in the base file, and queue a task for each file:
+      // a Read_symbols task for a changed file, and an Add_symbols task
+      // for an unchanged file.  We need to mark all the space used by
+      // unchanged files before we can start any tasks running.
+      std::list<Task*> tasks;
+      unsigned int input_file_count = ibase->input_file_count();
+      for (unsigned int i = 0; i < input_file_count; ++i)
+	{
+	  Task_token* next_blocker = new Task_token(true);
+	  next_blocker->add_blocker();
+	  Task* t = process_incremental_input(ibase, i, input_objects, symtab,
+					      layout, &search_path, mapfile,
+					      this_blocker, next_blocker);
+	  tasks.push_back(t);
+	  this_blocker = next_blocker;
+	}
+      // Now we can queue the tasks.
+      while (!tasks.empty())
+        {
+	  workqueue->queue(tasks.front());
+	  tasks.pop_front();
+	}
     }
 
   if (options.has_plugins())
@@ -220,13 +289,11 @@ queue_initial_tasks(const General_options& options,
       this_blocker = next_blocker;
     }
 
-  if (parameters->options().relocatable()
-      && (parameters->options().gc_sections()
-	  || parameters->options().icf_enabled()))
+  if (options.relocatable()
+      && (options.gc_sections() || options.icf_enabled()))
     gold_error(_("cannot mix -r with --gc-sections or --icf"));
 
-  if (parameters->options().gc_sections()
-      || parameters->options().icf_enabled())
+  if (options.gc_sections() || options.icf_enabled())
     {
       workqueue->queue(new Task_function(new Gc_runner(options,
 						       input_objects,
@@ -248,6 +315,129 @@ queue_initial_tasks(const General_options& options,
     }
 }
 
+// Process an incremental input file: if it is unchanged from the previous
+// link, return a task to add its symbols from the base file's incremental
+// info; if it has changed, return a normal Read_symbols task.  We create a
+// task for every input file, if only to report the file for rebuilding the
+// incremental info.
+
+Task*
+process_incremental_input(Incremental_binary* ibase,
+			  unsigned int input_file_index,
+			  Input_objects* input_objects,
+			  Symbol_table* symtab,
+			  Layout* layout,
+			  Dirsearch* search_path,
+			  Mapfile* mapfile,
+			  Task_token* this_blocker,
+			  Task_token* next_blocker)
+{
+  const Incremental_binary::Input_reader* input_reader =
+      ibase->get_input_reader(input_file_index);
+  Incremental_input_type input_type = input_reader->type();
+
+  // Get the input argument corresponding to this input file, matching on
+  // the argument serial number.  If the input file cannot be matched
+  // to an existing input argument, synthesize a new one.
+  const Input_argument* input_argument =
+      ibase->get_input_argument(input_file_index);
+  if (input_argument == NULL)
+    {
+      Input_file_argument file(input_reader->filename(),
+			       Input_file_argument::INPUT_FILE_TYPE_FILE,
+			       "", false, parameters->options());
+      Input_argument* arg = new Input_argument(file);
+      arg->set_script_info(ibase->get_script_info(input_file_index));
+      input_argument = arg;
+    }
+
+  gold_debug(DEBUG_INCREMENTAL,   "Incremental object: %s, type %d",
+	     input_reader->filename(), input_type);
+
+  if (input_type == INCREMENTAL_INPUT_SCRIPT)
+    {
+      // Incremental_binary::check_inputs should have cancelled the
+      // incremental update if the script has changed.
+      gold_assert(!ibase->file_has_changed(input_file_index));
+      return new Check_script(layout, ibase, input_file_index, input_reader,
+			      this_blocker, next_blocker);
+    }
+
+  if (input_type == INCREMENTAL_INPUT_ARCHIVE)
+    {
+      Incremental_library* lib = ibase->get_library(input_file_index);
+      gold_assert(lib != NULL);
+      if (lib->filename() == "<group>"
+	  || !ibase->file_has_changed(input_file_index))
+	{
+	  // Queue a task to check that no references have been added to any
+	  // of the library's unused symbols.
+	  return new Check_library(symtab, layout, ibase, input_file_index,
+				   input_reader, this_blocker, next_blocker);
+	}
+      else
+	{
+	  // Queue a Read_symbols task to process the archive normally.
+	  return new Read_symbols(input_objects, symtab, layout, search_path,
+				  0, mapfile, input_argument, NULL, NULL,
+				  this_blocker, next_blocker);
+	}
+    }
+
+  if (input_type == INCREMENTAL_INPUT_ARCHIVE_MEMBER)
+    {
+      // For archive members, check the timestamp of the containing archive.
+      Incremental_library* lib = ibase->get_library(input_file_index);
+      gold_assert(lib != NULL);
+      // Process members of a --start-lib/--end-lib group as normal objects.
+      if (lib->filename() != "<group>")
+	{
+	  if (ibase->file_has_changed(lib->input_file_index()))
+	    {
+	      return new Read_member(input_objects, symtab, layout, mapfile,
+				     input_reader, this_blocker, next_blocker);
+	    }
+	  else
+	    {
+	      // The previous contributions from this file will be kept.
+	      // Mark the pieces of output sections contributed by this
+	      // object.
+	      ibase->reserve_layout(input_file_index);
+	      Object* obj = make_sized_incremental_object(ibase,
+							  input_file_index,
+							  input_type,
+							  input_reader);
+	      return new Add_symbols(input_objects, symtab, layout,
+				     search_path, 0, mapfile, input_argument,
+				     obj, lib, NULL, this_blocker,
+				     next_blocker);
+	    }
+	}
+    }
+
+  // Normal object file or shared library.  Check if the file has changed
+  // since the last incremental link.
+  if (ibase->file_has_changed(input_file_index))
+    {
+      return new Read_symbols(input_objects, symtab, layout, search_path, 0,
+			      mapfile, input_argument, NULL, NULL,
+			      this_blocker, next_blocker);
+    }
+  else
+    {
+      // The previous contributions from this file will be kept.
+      // Mark the pieces of output sections contributed by this object.
+      ibase->reserve_layout(input_file_index);
+      Object* obj = make_sized_incremental_object(ibase,
+						  input_file_index,
+						  input_type,
+						  input_reader);
+      return new Add_symbols(input_objects, symtab, layout, search_path, 0,
+			     mapfile, input_argument, obj, NULL, NULL,
+			     this_blocker, next_blocker);
+    }
+}
+
 // Queue up a set of tasks to be done before queueing the middle set
 // of tasks.  This is only necessary when garbage collection
 // (--gc-sections) of unused sections is desired.  The relocs are read
@@ -396,7 +586,8 @@ queue_middle_tasks(const General_options& options,
   // generate an empty file.  Existing builds depend on being able to
   // pass an empty archive to the linker and get an empty object file
   // out.  In order to do this we need to use a default target.
-  if (input_objects->number_of_input_objects() == 0)
+  if (input_objects->number_of_input_objects() == 0
+      && layout->incremental_base() == NULL)
     parameters_force_valid_target();
 
   int thread_count = options.thread_count_middle();
diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc
index 6f79f4d..3a77ee8 100644
--- a/gold/incremental-dump.cc
+++ b/gold/incremental-dump.cc
@@ -63,7 +63,7 @@ find_input_containing_global(
       if (offset >= input_file.get_symbol_offset(0)
           && offset < input_file.get_symbol_offset(nsyms))
 	{
-	  *symndx = (offset - input_file.get_symbol_offset(0)) / 16;
+	  *symndx = (offset - input_file.get_symbol_offset(0)) / 20;
 	  return input_file;
 	}
     }
@@ -129,6 +129,10 @@ dump_incremental_inputs(const char* argv0, const char* filename,
 	     mtime.nanoseconds,
 	     ctime(&mtime.seconds));
 
+      printf("    Serial Number: %d\n", input_file.arg_serial());
+      printf("    In System Directory: %s\n",
+	     input_file.is_in_system_directory() ? "true" : "false");
+
       Incremental_input_type input_type = input_file.type();
       printf("    Type: ");
       switch (input_type)
@@ -195,7 +199,7 @@ dump_incremental_inputs(const char* argv0, const char* filename,
 	{
 	  typename Entry_reader::Input_section_info info(
 	      input_file.get_input_section(shndx));
-	  printf("    %3d  %6d  %8lld  %8lld  %s\n", shndx,
+	  printf("    %3d  %6d  %8lld  %8lld  %s\n", shndx + 1,
 		 info.output_shndx,
 		 static_cast<long long>(info.sh_offset),
 		 static_cast<long long>(info.sh_size),
@@ -203,42 +207,6 @@ dump_incremental_inputs(const char* argv0, const char* filename,
 	}
     }
 
-  printf("\nGlobal symbols per input file:\n");
-  for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
-    {
-      Entry_reader input_file(incremental_inputs.input_file(i));
-
-      if (input_file.type() != INCREMENTAL_INPUT_OBJECT
-	  && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER)
-	continue;
-
-      const char* objname = input_file.filename();
-      if (objname == NULL)
-	{
-	  fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
-		  argv0, filename, i);
-	  exit(1);
-	}
-
-      printf("[%d] %s\n", i, objname);
-
-      unsigned int nsyms = input_file.get_global_symbol_count();
-      if (nsyms > 0)
-	printf("    %6s  %8s  %8s  %8s  %8s\n",
-	       "outndx", "offset", "chain", "#relocs", "rbase");
-      for (unsigned int symndx = 0; symndx < nsyms; ++symndx)
-	{
-	  typename Entry_reader::Global_symbol_info info(
-	      input_file.get_global_symbol_info(symndx));
-	  printf("    %6d  %8d  %8d  %8d  %8d\n",
-		 info.output_symndx,
-		 input_file.get_symbol_offset(symndx),
-		 info.next_offset,
-		 info.reloc_count,
-		 info.reloc_offset);
-	}
-    }
-
   // Get a view of the .symtab section.
 
   elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file(inc);
@@ -280,8 +248,77 @@ dump_incremental_inputs(const char* argv0, const char* filename,
   unsigned int nsyms = symtab_location.data_size / sym_size;
   unsigned int nglobals = isymtab.symbol_count();
   unsigned int first_global = nsyms - nglobals;
-  unsigned const char* sym_p = symtab_view.data() + first_global * sym_size;
+  unsigned const char* sym_p;
+
+  printf("\nGlobal symbols per input file:\n");
+  for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
+    {
+      Entry_reader input_file(incremental_inputs.input_file(i));
+
+      if (input_file.type() != INCREMENTAL_INPUT_OBJECT
+	  && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER
+	  && input_file.type() != INCREMENTAL_INPUT_SHARED_LIBRARY)
+	continue;
+
+      const char* objname = input_file.filename();
+      if (objname == NULL)
+	{
+	  fprintf(stderr,"%s: %s: failed to get file name for object %u\n",
+		  argv0, filename, i);
+	  exit(1);
+	}
+
+      printf("[%d] %s\n", i, objname);
+
+      unsigned int nsyms = input_file.get_global_symbol_count();
+      if (nsyms > 0)
+	printf("    %6s  %6s  %8s  %8s  %8s  %8s\n",
+	       "outndx", "shndx", "offset", "chain", "#relocs", "rbase");
+      if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY)
+	{
+	  for (unsigned int symndx = 0; symndx < nsyms; ++symndx)
+	    {
+	      bool is_def;
+	      unsigned int output_symndx =
+		  input_file.get_output_symbol_index(symndx, &is_def);
+	      sym_p = symtab_view.data() + output_symndx * sym_size;
+	      elfcpp::Sym<size, big_endian> sym(sym_p);
+	      const char* symname;
+	      if (!strtab.get_c_string(sym.get_st_name(), &symname))
+		symname = "<unknown>";
+	      printf("    %6d  %6s  %8s  %8s  %8s  %8s  %-5s  %s\n",
+		     output_symndx,
+		     "", "", "", "", "",
+		     is_def ? "DEF" : "UNDEF",
+		     symname);
+	    }
+	}
+      else
+	{
+	  for (unsigned int symndx = 0; symndx < nsyms; ++symndx)
+	    {
+	      Incremental_global_symbol_reader<big_endian> info(
+		  input_file.get_global_symbol_reader(symndx));
+	      unsigned int output_symndx = info.output_symndx();
+	      sym_p = symtab_view.data() + output_symndx * sym_size;
+	      elfcpp::Sym<size, big_endian> sym(sym_p);
+	      const char* symname;
+	      if (!strtab.get_c_string(sym.get_st_name(), &symname))
+		symname = "<unknown>";
+	      printf("    %6d  %6d  %8d  %8d  %8d  %8d  %-5s  %s\n",
+		     output_symndx,
+		     info.shndx(),
+		     input_file.get_symbol_offset(symndx),
+		     info.next_offset(),
+		     info.reloc_count(),
+		     info.reloc_offset(),
+		     info.shndx() != elfcpp::SHN_UNDEF ? "DEF" : "UNDEF",
+		     symname);
+	    }
+	}
+    }
 
+  sym_p = symtab_view.data() + first_global * sym_size;
   printf("\nGlobal symbol table:\n");
   for (unsigned int i = 0; i < nglobals; i++)
     {
@@ -297,19 +334,19 @@ dump_incremental_inputs(const char* argv0, const char* filename,
 	  Entry_reader input_file =
 	      find_input_containing_global<size, big_endian>(incremental_inputs,
 							     offset, &sym_ndx);
-	  typename Entry_reader::Global_symbol_info sym_info(
-	      input_file.get_global_symbol_info(sym_ndx));
+	  Incremental_global_symbol_reader<big_endian> sym_info(
+	      input_file.get_global_symbol_reader(sym_ndx));
 	  printf("    %s (first reloc: %d, reloc count: %d)",
-		 input_file.filename(), sym_info.reloc_offset,
-		 sym_info.reloc_count);
-	  if (sym_info.output_symndx != first_global + i)
-	    printf(" ** wrong output symndx (%d) **", sym_info.output_symndx);
+		 input_file.filename(), sym_info.reloc_offset(),
+		 sym_info.reloc_count());
+	  if (sym_info.output_symndx() != first_global + i)
+	    printf(" ** wrong output symndx (%d) **", sym_info.output_symndx());
 	  printf("\n");
 	  // Dump the relocations from this input file for this symbol.
-	  unsigned int r_off = sym_info.reloc_offset;
-	  for (unsigned int j = 0; j < sym_info.reloc_count; j++)
+	  unsigned int r_off = sym_info.reloc_offset();
+	  for (unsigned int j = 0; j < sym_info.reloc_count(); j++)
 	    {
-	      printf("      %4d  relocation type %3d  shndx %d"
+	      printf("      %4d  relocation type %3d  shndx %2d"
 		     "  offset %016llx  addend %016llx  %s\n",
 		     r_off,
 		     irelocs.get_r_type(r_off),
@@ -319,7 +356,7 @@ dump_incremental_inputs(const char* argv0, const char* filename,
 		     symname);
 	      r_off += irelocs.reloc_size;
 	    }
-	  offset = sym_info.next_offset;
+	  offset = sym_info.next_offset();
 	}
       sym_p += sym_size;
     }
diff --git a/gold/incremental.cc b/gold/incremental.cc
index 800cf49..4663569 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -26,13 +26,17 @@
 #include "libiberty.h"
 
 #include "elfcpp.h"
+#include "options.h"
 #include "output.h"
 #include "symtab.h"
 #include "incremental.h"
 #include "archive.h"
+#include "object.h"
 #include "output.h"
 #include "target-select.h"
 #include "target.h"
+#include "fileread.h"
+#include "script.h"
 
 namespace gold {
 
@@ -54,6 +58,12 @@ class Output_section_incremental_inputs : public Output_section_data
   { }
 
  protected:
+  // This is called to update the section size prior to assigning
+  // the address and file offset.
+  void
+  update_data_size()
+  { this->set_final_data_size(); }
+
   // Set the final data size.
   void
   set_final_data_size();
@@ -247,65 +257,291 @@ Sized_incremental_binary<size, big_endian>::setup_readers()
 						  relocs_location.data_size);
   this->got_plt_reader_ =
       Incremental_got_plt_reader<big_endian>(got_plt_view.data());
+
+  // Walk the list of input files (a) to setup an Input_reader for each
+  // input file, and (b) to record maps of files added from archive
+  // libraries and scripts.
+  Incremental_inputs_reader<size, big_endian>& inputs = this->inputs_reader_;
+  unsigned int count = inputs.input_file_count();
+  this->input_entry_readers_.reserve(count);
+  this->library_map_.resize(count);
+  this->script_map_.resize(count);
+  for (unsigned int i = 0; i < count; i++)
+    {
+      Input_entry_reader input_file = inputs.input_file(i);
+      this->input_entry_readers_.push_back(Sized_input_reader(input_file));
+      switch (input_file.type())
+	{
+	case INCREMENTAL_INPUT_OBJECT:
+	case INCREMENTAL_INPUT_ARCHIVE_MEMBER:
+	case INCREMENTAL_INPUT_SHARED_LIBRARY:
+	  // No special treatment necessary.
+	  break;
+	case INCREMENTAL_INPUT_ARCHIVE:
+	  {
+	    Incremental_library* lib =
+	        new Incremental_library(input_file.filename(), i,
+					&this->input_entry_readers_[i]);
+	    this->library_map_[i] = lib;
+	    unsigned int member_count = input_file.get_member_count();
+	    for (unsigned int j = 0; j < member_count; j++)
+	      {
+		int member_offset = input_file.get_member_offset(j);
+		int member_index = inputs.input_file_index(member_offset);
+		this->library_map_[member_index] = lib;
+	      }
+	  }
+	  break;
+	case INCREMENTAL_INPUT_SCRIPT:
+	  {
+	    Script_info* script = new Script_info(input_file.filename());
+	    this->script_map_[i] = script;
+	    unsigned int object_count = input_file.get_object_count();
+	    for (unsigned int j = 0; j < object_count; j++)
+	      {
+		int object_offset = input_file.get_object_offset(j);
+		int object_index = inputs.input_file_index(object_offset);
+		this->script_map_[object_index] = script;
+	      }
+	  }
+	  break;
+	default:
+	  gold_unreachable();
+	}
+    }
+
   this->has_incremental_info_ = true;
 }
 
+// Walk the list of input files given on the command line, and build
+// a direct map of file index to the corresponding input argument.
+
+void
+check_input_args(std::vector<const Input_argument*>& input_args_map,
+		 Input_arguments::const_iterator begin,
+		 Input_arguments::const_iterator end)
+{
+  for (Input_arguments::const_iterator p = begin;
+       p != end;
+       ++p)
+    {
+      if (p->is_group())
+	{
+	  const Input_file_group* group = p->group();
+	  check_input_args(input_args_map, group->begin(), group->end());
+	}
+      else if (p->is_lib())
+	{
+	  const Input_file_lib* lib = p->lib();
+	  check_input_args(input_args_map, lib->begin(), lib->end());
+	}
+      else
+        {
+          gold_assert(p->is_file());
+          unsigned int arg_serial = p->file().arg_serial();
+          if (arg_serial > 0)
+	    {
+	      gold_assert(arg_serial <= input_args_map.size());
+	      gold_assert(input_args_map[arg_serial - 1] == 0);
+	      input_args_map[arg_serial - 1] = &*p;
+	    }
+        }
+    }
+}
+
 // Determine whether an incremental link based on the existing output file
 // can be done.
 
 template<int size, bool big_endian>
 bool
 Sized_incremental_binary<size, big_endian>::do_check_inputs(
+    const Command_line& cmdline,
     Incremental_inputs* incremental_inputs)
 {
+  Incremental_inputs_reader<size, big_endian>& inputs = this->inputs_reader_;
+
   if (!this->has_incremental_info_)
     {
       explain_no_incremental(_("no incremental data from previous build"));
       return false;
     }
 
-  if (this->inputs_reader_.version() != INCREMENTAL_LINK_VERSION)
+  if (inputs.version() != INCREMENTAL_LINK_VERSION)
     {
       explain_no_incremental(_("different version of incremental build data"));
       return false;
     }
 
-  if (incremental_inputs->command_line() != this->inputs_reader_.command_line())
+  if (incremental_inputs->command_line() != inputs.command_line())
     {
       explain_no_incremental(_("command line changed"));
       return false;
     }
 
+  // Walk the list of input files given on the command line, and build
+  // a direct map of argument serial numbers to the corresponding input
+  // arguments.
+  this->input_args_map_.resize(cmdline.number_of_input_files());
+  check_input_args(this->input_args_map_, cmdline.begin(), cmdline.end());
+
+  // Walk the list of input files to check for conditions that prevent
+  // an incremental update link.
+  unsigned int count = inputs.input_file_count();
+  for (unsigned int i = 0; i < count; i++)
+    {
+      Input_entry_reader input_file = inputs.input_file(i);
+      switch (input_file.type())
+	{
+	case INCREMENTAL_INPUT_OBJECT:
+	case INCREMENTAL_INPUT_ARCHIVE_MEMBER:
+	case INCREMENTAL_INPUT_SHARED_LIBRARY:
+	case INCREMENTAL_INPUT_ARCHIVE:
+	  // No special treatment necessary.
+	  break;
+	case INCREMENTAL_INPUT_SCRIPT:
+	  if (this->do_file_has_changed(i))
+	    {
+	      explain_no_incremental(_("%s: script file changed"),
+				     input_file.filename());
+	      return false;
+	    }
+	  break;
+	default:
+	  gold_unreachable();
+	}
+    }
+
   return true;
 }
 
-// Return TRUE if the file specified by INPUT_ARGUMENT is unchanged
-// with respect to the base file.
+// Return TRUE if input file N has changed since the last incremental link.
 
 template<int size, bool big_endian>
 bool
-Sized_incremental_binary<size, big_endian>::do_file_is_unchanged(
-    const Input_argument* input_argument) const
+Sized_incremental_binary<size, big_endian>::do_file_has_changed(
+    unsigned int n) const
 {
-  Incremental_disposition disp =
-      input_argument->file().options().incremental_disposition();
+  Input_entry_reader input_file = this->inputs_reader_.input_file(n);
+  Incremental_disposition disp = INCREMENTAL_CHECK;
+  const Input_argument* input_argument = this->get_input_argument(n);
+  if (input_argument != NULL)
+    disp = input_argument->file().options().incremental_disposition();
 
   if (disp != INCREMENTAL_CHECK)
-    return disp == INCREMENTAL_UNCHANGED;
+    return disp == INCREMENTAL_CHANGED;
 
-  // FIXME: Handle INCREMENTAL_CHECK.
+  const char* filename = input_file.filename();
+  Timespec old_mtime = input_file.get_mtime();
+  Timespec new_mtime;
+  if (!get_mtime(filename, &new_mtime))
+    {
+      // If we can't open get the current modification time, assume it has
+      // changed.  If the file doesn't exist, we'll issue an error when we
+      // try to open it later.
+      return true;
+    }
+
+  if (new_mtime.seconds > old_mtime.seconds)
+    return true;
+  if (new_mtime.seconds == old_mtime.seconds
+      && new_mtime.nanoseconds > old_mtime.nanoseconds)
+    return true;
   return false;
 }
 
+// Initialize the layout of the output file based on the existing
+// output file.
+
+template<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_init_layout(Layout* layout)
+{
+  typedef elfcpp::Shdr<size, big_endian> Shdr;
+  const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+
+  // Get views of the section headers and the section string table.
+  const off_t shoff = this->elf_file_.shoff();
+  const unsigned int shnum = this->elf_file_.shnum();
+  const unsigned int shstrndx = this->elf_file_.shstrndx();
+  Location shdrs_location(shoff, shnum * shdr_size);
+  Location shstrndx_location(this->elf_file_.section_contents(shstrndx));
+  View shdrs_view = this->view(shdrs_location);
+  View shstrndx_view = this->view(shstrndx_location);
+  elfcpp::Elf_strtab shstrtab(shstrndx_view.data(),
+			      shstrndx_location.data_size);
+
+  layout->set_incremental_base(this);
+
+  // Initialize the layout.
+  this->section_map_.resize(shnum);
+  const unsigned char* pshdr = shdrs_view.data() + shdr_size;
+  for (unsigned int i = 1; i < shnum; i++)
+    {
+      Shdr shdr(pshdr);
+      const char* name;
+      if (!shstrtab.get_c_string(shdr.get_sh_name(), &name))
+        name = NULL;
+      gold_debug(DEBUG_INCREMENTAL,
+		 "Output section: %2d %08lx %08lx %08lx %3d %s",
+	         i,
+	         static_cast<long>(shdr.get_sh_addr()),
+	         static_cast<long>(shdr.get_sh_offset()),
+	         static_cast<long>(shdr.get_sh_size()),
+	         shdr.get_sh_type(), name ? name : "<null>");
+      this->section_map_[i] = layout->init_fixed_output_section(name, shdr);
+      pshdr += shdr_size;
+    }
+}
+
+// Mark regions of the input file that must be kept unchanged.
+
+template<int size, bool big_endian>
+void
+Sized_incremental_binary<size, big_endian>::do_reserve_layout(
+    unsigned int input_file_index)
+{
+  Input_entry_reader input_file =
+      this->inputs_reader_.input_file(input_file_index);
+
+  if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY)
+    return;
+
+  unsigned int shnum = input_file.get_input_section_count();
+  for (unsigned int i = 0; i < shnum; i++)
+    {
+      typename Input_entry_reader::Input_section_info sect =
+          input_file.get_input_section(i);
+      if (sect.output_shndx == 0 || sect.sh_offset == -1)
+        continue;
+      Output_section* os = this->section_map_[sect.output_shndx];
+      gold_assert(os != NULL);
+      os->reserve(sect.sh_offset, sect.sh_size);
+    }
+}
+
+// Get a view of the main symbol table and the symbol string table.
 
 template<int size, bool big_endian>
-Incremental_binary::Input_reader*
-Sized_incremental_binary<size, big_endian>::do_get_input_reader(
-    const char*)
+void
+Sized_incremental_binary<size, big_endian>::get_symtab_view(
+    View* symtab_view,
+    unsigned int* nsyms,
+    elfcpp::Elf_strtab* strtab)
 {
-  unsigned int file_index = this->current_input_file_++;
-  gold_assert(file_index < this->inputs_reader_.input_file_count());
-  return new Sized_input_reader(this->inputs_reader_.input_file(file_index));
+  unsigned int symtab_shndx =
+      this->elf_file_.find_section_by_type(elfcpp::SHT_SYMTAB);
+  gold_assert(symtab_shndx != elfcpp::SHN_UNDEF);
+  Location symtab_location(this->elf_file_.section_contents(symtab_shndx));
+  *symtab_view = this->view(symtab_location);
+  *nsyms = symtab_location.data_size / elfcpp::Elf_sizes<size>::sym_size;
+
+  unsigned int strtab_shndx = this->elf_file_.section_link(symtab_shndx);
+  gold_assert(strtab_shndx != elfcpp::SHN_UNDEF
+              && strtab_shndx < this->elf_file_.shnum());
+
+  Location strtab_location(this->elf_file_.section_contents(strtab_shndx));
+  View strtab_view(this->view(strtab_location));
+  *strtab = elfcpp::Elf_strtab(strtab_view.data(), strtab_location.data_size);
 }
 
 namespace
@@ -417,21 +653,6 @@ open_incremental_binary(Output_file* file)
   return result;
 }
 
-// Analyzes the output file to check if incremental linking is possible and
-// (to be done) what files need to be relinked.
-
-bool
-Incremental_checker::can_incrementally_link_output_file()
-{
-  Output_file output(this->output_name_);
-  if (!output.open_for_modification())
-    return false;
-  Incremental_binary* binary = open_incremental_binary(&output);
-  if (binary == NULL)
-    return false;
-  return binary->check_inputs(this->incremental_inputs_);
-}
-
 // Class Incremental_inputs.
 
 // Add the command line to the string table, setting
@@ -454,7 +675,8 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
 	  || strcmp(argv[i], "--incremental-update") == 0
 	  || strcmp(argv[i], "--incremental-changed") == 0
 	  || strcmp(argv[i], "--incremental-unchanged") == 0
-	  || strcmp(argv[i], "--incremental-unknown") == 0)
+	  || strcmp(argv[i], "--incremental-unknown") == 0
+	  || is_prefix_of("--debug=", argv[i]))
         continue;
 
       args.append(" '");
@@ -485,16 +707,20 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv)
 
 void
 Incremental_inputs::report_archive_begin(Library_base* arch,
+					 unsigned int arg_serial,
 					 Script_info* script_info)
 {
   Stringpool::Key filename_key;
   Timespec mtime = arch->get_mtime();
 
+  // For a file loaded from a script, don't record its argument serial number.
+  if (script_info != NULL)
+    arg_serial = 0;
+
   this->strtab_->add(arch->filename().c_str(), false, &filename_key);
   Incremental_archive_entry* entry =
-      new Incremental_archive_entry(filename_key, mtime);
+      new Incremental_archive_entry(filename_key, arg_serial, mtime);
   arch->set_incremental_info(entry);
-  this->inputs_.push_back(entry);
 
   if (script_info != NULL)
     {
@@ -536,6 +762,7 @@ Incremental_inputs::report_archive_end(Library_base* arch)
   Incremental_archive_entry* entry = arch->incremental_info();
 
   gold_assert(entry != NULL);
+  this->inputs_.push_back(entry);
 
   // Collect unused global symbols.
   Unused_symbol_visitor v(entry, this->strtab_);
@@ -547,15 +774,21 @@ Incremental_inputs::report_archive_end(Library_base* arch)
 // Add_symbols task after finding out the type of the file.
 
 void
-Incremental_inputs::report_object(Object* obj, Library_base* arch,
-				  Script_info* script_info)
+Incremental_inputs::report_object(Object* obj, unsigned int arg_serial,
+				  Library_base* arch, Script_info* script_info)
 {
   Stringpool::Key filename_key;
-  Timespec mtime = obj->input_file()->file().get_mtime();
+  Timespec mtime = obj->get_mtime();
+
+  // For a file loaded from a script, don't record its argument serial number.
+  if (script_info != NULL)
+    arg_serial = 0;
 
   this->strtab_->add(obj->name().c_str(), false, &filename_key);
   Incremental_object_entry* obj_entry =
-      new Incremental_object_entry(filename_key, obj, mtime);
+      new Incremental_object_entry(filename_key, obj, arg_serial, mtime);
+  if (obj->is_in_system_directory())
+    obj_entry->set_is_in_system_directory();
   this->inputs_.push_back(obj_entry);
 
   if (arch != NULL)
@@ -598,14 +831,15 @@ Incremental_inputs::report_input_section(Object* obj, unsigned int shndx,
 // of inputs added by this script.
 
 void
-Incremental_inputs::report_script(const std::string& filename,
-				  Script_info* script, Timespec mtime)
+Incremental_inputs::report_script(Script_info* script,
+				  unsigned int arg_serial,
+				  Timespec mtime)
 {
   Stringpool::Key filename_key;
 
-  this->strtab_->add(filename.c_str(), false, &filename_key);
+  this->strtab_->add(script->filename().c_str(), false, &filename_key);
   Incremental_script_entry* entry =
-      new Incremental_script_entry(filename_key, script, mtime);
+      new Incremental_script_entry(filename_key, arg_serial, script, mtime);
   this->inputs_.push_back(entry);
   script->set_incremental_info(entry);
 }
@@ -723,7 +957,7 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
 			    * (8 + 2 * sizeof_addr));
 	    // Each global symbol.
 	    const Object::Symbols* syms = entry->object()->get_global_symbols();
-	    info_offset += syms->size() * 16;
+	    info_offset += syms->size() * 20;
 	  }
 	  break;
 	case INCREMENTAL_INPUT_SHARED_LIBRARY:
@@ -735,8 +969,20 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size()
 	    info_offset += 4;
 	    // Each global symbol.
 	    const Object::Symbols* syms = entry->object()->get_global_symbols();
-	    unsigned int nsyms = syms != NULL ? syms->size() : 0;
-	    info_offset += nsyms * 4;
+	    gold_assert(syms != NULL);
+	    unsigned int nsyms = syms->size();
+	    unsigned int nsyms_out = 0;
+	    for (unsigned int i = 0; i < nsyms; ++i)
+	      {
+		const Symbol* sym = (*syms)[i];
+		if (sym == NULL)
+		  continue;
+		if (sym->is_forwarder())
+		  sym = this->symtab_->resolve_forwards(sym);
+	        if (sym->symtab_index() != -1U)
+	          ++nsyms_out;
+	      }
+	    info_offset += nsyms_out * 4;
 	  }
 	  break;
 	case INCREMENTAL_INPUT_ARCHIVE:
@@ -879,12 +1125,15 @@ Output_section_incremental_inputs<size, big_endian>::write_input_files(
       section_offset_type filename_offset =
           strtab->get_offset_from_key((*p)->get_filename_key());
       const Timespec& mtime = (*p)->get_mtime();
+      unsigned int flags = (*p)->type();
+      if ((*p)->is_in_system_directory())
+        flags |= INCREMENTAL_INPUT_IN_SYSTEM_DIR;
       Swap32::writeval(pov, filename_offset);
       Swap32::writeval(pov + 4, (*p)->get_info_offset());
       Swap64::writeval(pov + 8, mtime.seconds);
       Swap32::writeval(pov + 16, mtime.nanoseconds);
-      Swap16::writeval(pov + 20, (*p)->type());
-      Swap16::writeval(pov + 22, 0);
+      Swap16::writeval(pov + 20, flags);
+      Swap16::writeval(pov + 22, (*p)->arg_serial());
       pov += this->input_entry_size;
     }
   return pov;
@@ -949,10 +1198,18 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks(
 	    Swap32::writeval(pov + 4, nsyms);
 	    pov += 8;
 
+	    // Build a temporary array to map input section indexes
+	    // from the original object file index to the index in the
+	    // incremental info table.
+	    unsigned int* index_map = new unsigned int[obj->shnum()];
+	    memset(index_map, 0, obj->shnum() * sizeof(unsigned int));
+
 	    // For each input section, write the name, output section index,
 	    // offset within output section, and input section size.
 	    for (unsigned int i = 0; i < nsections; i++)
 	      {
+		unsigned int shndx = entry->get_input_section_index(i);
+		index_map[shndx] = i + 1;
 		Stringpool::Key key = entry->get_input_section_name_key(i);
 		off_t name_offset = 0;
 		if (key != 0)
@@ -960,11 +1217,11 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks(
 		int out_shndx = 0;
 		off_t out_offset = 0;
 		off_t sh_size = 0;
-		Output_section* os = obj->output_section(i);
+		Output_section* os = obj->output_section(shndx);
 		if (os != NULL)
 		  {
 		    out_shndx = os->out_shndx();
-		    out_offset = obj->output_section_offset(i);
+		    out_offset = obj->output_section_offset(shndx);
 		    sh_size = entry->get_input_section_size(i);
 		  }
 		Swap32::writeval(pov, name_offset);
@@ -977,13 +1234,23 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks(
 	    // For each global symbol, write its associated relocations,
 	    // add it to the linked list of globals, then write the
 	    // supplemental information:  global symbol table index,
-	    // linked list chain pointer, relocation count, and offset
-	    // to the relocations.
+	    // input section index, linked list chain pointer, relocation
+	    // count, and offset to the relocations.
 	    for (unsigned int i = 0; i < nsyms; i++)
 	      {
 		const Symbol* sym = (*syms)[i];
 		if (sym->is_forwarder())
 		  sym = this->symtab_->resolve_forwards(sym);
+		unsigned int shndx = 0;
+		if (sym->source() == Symbol::FROM_OBJECT
+		    && sym->object() == obj
+		    && sym->is_defined())
+		  {
+		    bool is_ordinary;
+		    unsigned int orig_shndx = sym->shndx(&is_ordinary);
+		    if (is_ordinary)
+		      shndx = index_map[orig_shndx];
+		  }
 		unsigned int symtab_index = sym->symtab_index();
 		unsigned int chain = 0;
 		unsigned int first_reloc = 0;
@@ -999,11 +1266,14 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks(
 			pov - oview;
 		  }
 		Swap32::writeval(pov, symtab_index);
-		Swap32::writeval(pov + 4, chain);
-		Swap32::writeval(pov + 8, nrelocs);
-		Swap32::writeval(pov + 12, first_reloc * 3 * sizeof_addr);
-		pov += 16;
+		Swap32::writeval(pov + 4, shndx);
+		Swap32::writeval(pov + 8, chain);
+		Swap32::writeval(pov + 12, nrelocs);
+		Swap32::writeval(pov + 16, first_reloc * 3 * sizeof_addr);
+		pov += 20;
 	      }
+
+	    delete[] index_map;
 	  }
 	  break;
 
@@ -1016,18 +1286,34 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks(
 	    const Object* obj = entry->object();
 	    const Object::Symbols* syms = obj->get_global_symbols();
 
-	    // Write the global symbol count.
-	    unsigned int nsyms = syms != NULL ? syms->size() : 0;
-	    Swap32::writeval(pov, nsyms);
+	    // Skip the global symbol count for now.
+	    unsigned char* orig_pov = pov;
 	    pov += 4;
 
 	    // For each global symbol, write the global symbol table index.
+	    unsigned int nsyms = syms->size();
+	    unsigned int nsyms_out = 0;
 	    for (unsigned int i = 0; i < nsyms; i++)
 	      {
 		const Symbol* sym = (*syms)[i];
-		Swap32::writeval(pov, sym->symtab_index());
+		if (sym == NULL)
+		  continue;
+		if (sym->is_forwarder())
+		  sym = this->symtab_->resolve_forwards(sym);
+	        if (sym->symtab_index() == -1U)
+	          continue;
+		unsigned int def_flag = 0;
+		if (sym->source() == Symbol::FROM_OBJECT
+		    && sym->object() == obj
+		    && sym->is_defined())
+		  def_flag = 1U << 31;
+		Swap32::writeval(pov, sym->symtab_index() | def_flag);
 		pov += 4;
+		++nsyms_out;
 	      }
+
+	    // Now write the global symbol count.
+	    Swap32::writeval(orig_pov, nsyms_out);
 	  }
 	  break;
 
@@ -1117,7 +1403,7 @@ struct Got_plt_view_info
 // arrays in the output section.
 
 template<int size, bool big_endian>
-class Local_got_offset_visitor
+class Local_got_offset_visitor : public Got_offset_list::Visitor
 {
  public:
   Local_got_offset_visitor(struct Got_plt_view_info& info)
@@ -1125,7 +1411,7 @@ class Local_got_offset_visitor
   { }
 
   void
-  operator()(unsigned int got_type, unsigned int got_offset)
+  visit(unsigned int got_type, unsigned int got_offset)
   {
     unsigned int got_index = got_offset / this->got_entry_size_;
     gold_assert(got_index < this->info_.got_count);
@@ -1148,7 +1434,7 @@ class Local_got_offset_visitor
 // section.
 
 template<int size, bool big_endian>
-class Global_got_offset_visitor
+class Global_got_offset_visitor : public Got_offset_list::Visitor
 {
  public:
   Global_got_offset_visitor(struct Got_plt_view_info& info)
@@ -1156,7 +1442,7 @@ class Global_got_offset_visitor
   { }
 
   void
-  operator()(unsigned int got_type, unsigned int got_offset)
+  visit(unsigned int got_type, unsigned int got_offset)
   {
     unsigned int got_index = got_offset / this->got_entry_size_;
     gold_assert(got_index < this->info_.got_count);
@@ -1193,8 +1479,9 @@ class Global_symbol_visitor_got_plt
     const Got_offset_list* got_offsets = sym->got_offset_list();
     if (got_offsets != NULL)
       {
-        info_.got_descriptor = sym->symtab_index();
-	got_offsets->for_all_got_offsets(Got_visitor(info_));
+        this->info_.got_descriptor = sym->symtab_index();
+        Got_visitor v(this->info_);
+	got_offsets->for_all_got_offsets(v);
       }
     if (sym->has_plt_offset())
       {
@@ -1244,6 +1531,7 @@ Output_section_incremental_inputs<size, big_endian>::write_got_plt(
   memset(view_info.got_type_p, 0xff, view_info.got_count);
 
   // Write the incremental GOT descriptors for local symbols.
+  typedef Local_got_offset_visitor<size, big_endian> Got_visitor;
   for (Incremental_inputs::Input_list::const_iterator p =
 	   this->inputs_->input_files().begin();
        p != this->inputs_->input_files().end();
@@ -1254,20 +1542,11 @@ Output_section_incremental_inputs<size, big_endian>::write_got_plt(
 	continue;
       Incremental_object_entry* entry = (*p)->object_entry();
       gold_assert(entry != NULL);
-      const Sized_relobj<size, big_endian>* obj =
-          static_cast<Sized_relobj<size, big_endian>*>(entry->object());
+      const Object* obj = entry->object();
       gold_assert(obj != NULL);
-      unsigned int nsyms = obj->local_symbol_count();
-      for (unsigned int i = 0; i < nsyms; i++)
-        {
-          const Got_offset_list* got_offsets = obj->local_got_offset_list(i);
-          if (got_offsets != NULL)
-            {
-	      typedef Local_got_offset_visitor<size, big_endian> Got_visitor;
-	      view_info.got_descriptor = (*p)->get_offset();
-	      got_offsets->for_all_got_offsets(Got_visitor(view_info));
-	    }
-	}
+      view_info.got_descriptor = (*p)->get_offset();
+      Got_visitor v(view_info);
+      obj->for_all_local_got_entries(v);
     }
 
   // Write the incremental GOT and PLT descriptors for global symbols.
@@ -1275,26 +1554,860 @@ Output_section_incremental_inputs<size, big_endian>::write_got_plt(
   symtab_->for_all_symbols<size, Symbol_visitor>(Symbol_visitor(view_info));
 }
 
+// Class Sized_incr_relobj.  Most of these methods are not used for
+// Incremental objects, but are required to be implemented by the
+// base class Object.
+
+template<int size, bool big_endian>
+Sized_incr_relobj<size, big_endian>::Sized_incr_relobj(
+    const std::string& name,
+    Sized_incremental_binary<size, big_endian>* ibase,
+    unsigned int input_file_index)
+  : Sized_relobj_base<size, big_endian>(name, NULL), ibase_(ibase),
+    input_file_index_(input_file_index),
+    input_reader_(ibase->inputs_reader().input_file(input_file_index)),
+    symbols_(), section_offsets_(), incr_reloc_offset_(-1U),
+    incr_reloc_count_(0), incr_reloc_output_index_(0), incr_relocs_(NULL)
+{
+  if (this->input_reader_.is_in_system_directory())
+    this->set_is_in_system_directory();
+  const unsigned int shnum = this->input_reader_.get_input_section_count() + 1;
+  this->set_shnum(shnum);
+}
+
+// Read the symbols.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_read_symbols(Read_symbols_data*)
+{
+  gold_unreachable();
+}
+
+// Lay out the input sections.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_layout(
+    Symbol_table*,
+    Layout* layout,
+    Read_symbols_data*)
+{
+  const unsigned int shnum = this->shnum();
+  Incremental_inputs* incremental_inputs = layout->incremental_inputs();
+  gold_assert(incremental_inputs != NULL);
+  Output_sections& out_sections(this->output_sections());
+  out_sections.resize(shnum);
+  this->section_offsets_.resize(shnum);
+  for (unsigned int i = 1; i < shnum; i++)
+    {
+      typename Input_entry_reader::Input_section_info sect =
+          this->input_reader_.get_input_section(i - 1);
+      // Add the section to the incremental inputs layout.
+      incremental_inputs->report_input_section(this, i, sect.name,
+					       sect.sh_size);
+      if (sect.output_shndx == 0 || sect.sh_offset == -1)
+        continue;
+      Output_section* os = this->ibase_->output_section(sect.output_shndx);
+      gold_assert(os != NULL);
+      out_sections[i] = os;
+      this->section_offsets_[i] = static_cast<Address>(sect.sh_offset);
+    }
+}
+
+// Layout sections whose layout was deferred while waiting for
+// input files from a plugin.
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_layout_deferred_sections(Layout*)
+{
+}
+
+// Add the symbols to the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_add_symbols(
+    Symbol_table* symtab,
+    Read_symbols_data*,
+    Layout*)
+{
+  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  unsigned char symbuf[sym_size];
+  elfcpp::Sym<size, big_endian> sym(symbuf);
+  elfcpp::Sym_write<size, big_endian> osym(symbuf);
+
+  typedef typename elfcpp::Elf_types<size>::Elf_WXword Elf_size_type;
+
+  unsigned int nsyms = this->input_reader_.get_global_symbol_count();
+  this->symbols_.resize(nsyms);
+
+  Incremental_binary::View symtab_view(NULL);
+  unsigned int symtab_count;
+  elfcpp::Elf_strtab strtab(NULL, 0);
+  this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab);
+
+  // Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader());
+  // Incremental_relocs_reader<size, big_endian> irelocs(this->ibase_->relocs_reader());
+  // unsigned int isym_count = isymtab.symbol_count();
+  // unsigned int first_global = symtab_count - isym_count;
+
+  unsigned const char* sym_p;
+  for (unsigned int i = 0; i < nsyms; ++i)
+    {
+      Incremental_global_symbol_reader<big_endian> info =
+	  this->input_reader_.get_global_symbol_reader(i);
+      sym_p = symtab_view.data() + info.output_symndx() * sym_size;
+      elfcpp::Sym<size, big_endian> gsym(sym_p);
+      const char* name;
+      if (!strtab.get_c_string(gsym.get_st_name(), &name))
+	name = "";
+
+      typename elfcpp::Elf_types<size>::Elf_Addr v;
+      unsigned int shndx = gsym.get_st_shndx();
+      elfcpp::STB st_bind = gsym.get_st_bind();
+      elfcpp::STT st_type = gsym.get_st_type();
+
+      // Local hidden symbols start out as globals, but get converted to
+      // to local during output.
+      if (st_bind == elfcpp::STB_LOCAL)
+        st_bind = elfcpp::STB_GLOBAL;
+
+      unsigned int input_shndx = info.shndx();
+      if (input_shndx == 0)
+	{
+	  shndx = elfcpp::SHN_UNDEF;
+	  v = 0;
+	}
+      else if (shndx != elfcpp::SHN_ABS)
+	{
+	  // Find the input section and calculate the section-relative value.
+	  gold_assert(shndx != elfcpp::SHN_UNDEF);
+	  v = gsym.get_st_value();
+	  Output_section* os = this->ibase_->output_section(shndx);
+	  gold_assert(os != NULL && os->has_fixed_layout());
+	  typename Input_entry_reader::Input_section_info sect =
+	      this->input_reader_.get_input_section(input_shndx - 1);
+	  gold_assert(sect.output_shndx == shndx);
+	  if (st_type != elfcpp::STT_TLS)
+	    v -= os->address();
+	  v -= sect.sh_offset;
+	  shndx = input_shndx;
+	}
+
+      osym.put_st_name(0);
+      osym.put_st_value(v);
+      osym.put_st_size(gsym.get_st_size());
+      osym.put_st_info(st_bind, st_type);
+      osym.put_st_other(gsym.get_st_other());
+      osym.put_st_shndx(shndx);
+
+      this->symbols_[i] =
+	symtab->add_from_incrobj(this, name, NULL, &sym);
+    }
+}
+
+// Return TRUE if we should include this object from an archive library.
+
+template<int size, bool big_endian>
+Archive::Should_include
+Sized_incr_relobj<size, big_endian>::do_should_include_member(
+    Symbol_table*,
+    Layout*,
+    Read_symbols_data*,
+    std::string*)
+{
+  gold_unreachable();
+}
+
+// Iterate over global symbols, calling a visitor class V for each.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_for_all_global_symbols(
+    Read_symbols_data*,
+    Library_base::Symbol_visitor_base&)
+{
+  // FIXME: Implement Sized_incr_relobj::do_for_all_global_symbols.
+}
+
+// Iterate over local symbols, calling a visitor class V for each GOT offset
+// associated with a local symbol.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_for_all_local_got_entries(
+    Got_offset_list::Visitor&) const
+{
+  // FIXME: Implement Sized_incr_relobj::do_for_all_local_got_entries.
+}
+
+// Get the size of a section.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_relobj<size, big_endian>::do_section_size(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Get the name of a section.
+
+template<int size, bool big_endian>
+std::string
+Sized_incr_relobj<size, big_endian>::do_section_name(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return a view of the contents of a section.
+
+template<int size, bool big_endian>
+Object::Location
+Sized_incr_relobj<size, big_endian>::do_section_contents(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return section flags.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_relobj<size, big_endian>::do_section_flags(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return section entsize.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_relobj<size, big_endian>::do_section_entsize(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return section address.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_relobj<size, big_endian>::do_section_address(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return section type.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_relobj<size, big_endian>::do_section_type(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return the section link field.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_relobj<size, big_endian>::do_section_link(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return the section link field.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_relobj<size, big_endian>::do_section_info(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return the section alignment.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_relobj<size, big_endian>::do_section_addralign(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return the Xindex structure to use.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_incr_relobj<size, big_endian>::do_initialize_xindex()
+{
+  gold_unreachable();
+}
+
+// Get symbol counts.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_get_global_symbol_counts(
+    const Symbol_table*, size_t*, size_t*) const
+{
+  gold_unreachable();
+}
+
+// Read the relocs.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_read_relocs(Read_relocs_data*)
+{
+}
+
+// Process the relocs to find list of referenced sections. Used only
+// during garbage collection.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_gc_process_relocs(Symbol_table*,
+							  Layout*,
+							  Read_relocs_data*)
+{
+  gold_unreachable();
+}
+
+// Scan the relocs and adjust the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_scan_relocs(Symbol_table*,
+						    Layout* layout,
+						    Read_relocs_data*)
+{
+  // Count the incremental relocations for this object.
+  unsigned int nsyms = this->input_reader_.get_global_symbol_count();
+  this->allocate_incremental_reloc_counts();
+  for (unsigned int i = 0; i < nsyms; i++)
+    {
+      Incremental_global_symbol_reader<big_endian> sym =
+	  this->input_reader_.get_global_symbol_reader(i);
+      unsigned int reloc_count = sym.reloc_count();
+      if (reloc_count > 0 && this->incr_reloc_offset_ == -1U)
+	this->incr_reloc_offset_ = sym.reloc_offset();
+      this->incr_reloc_count_ += reloc_count;
+      for (unsigned int j = 0; j < reloc_count; j++)
+	this->count_incremental_reloc(i);
+    }
+  this->incr_reloc_output_index_ =
+      layout->incremental_inputs()->get_reloc_count();
+  this->finalize_incremental_relocs(layout, false);
+
+  // The incoming incremental relocations may not end up in the same
+  // location after the incremental update, because the incremental info
+  // is regenerated in each link.  Because the new location may overlap
+  // with other data in the updated output file, we need to copy the
+  // relocations into a buffer so that we can still read them safely
+  // after we start writing updates to the output file.
+  if (this->incr_reloc_count_ > 0)
+    {
+      const Incremental_relocs_reader<size, big_endian>& relocs_reader =
+	  this->ibase_->relocs_reader();
+      const unsigned int incr_reloc_size = relocs_reader.reloc_size;
+      unsigned int len = this->incr_reloc_count_ * incr_reloc_size;
+      this->incr_relocs_ = new unsigned char[len];
+      memcpy(this->incr_relocs_,
+	     relocs_reader.data(this->incr_reloc_offset_),
+	     len);
+    }
+}
+
+// Count the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_count_local_symbols(
+    Stringpool_template<char>*,
+    Stringpool_template<char>*)
+{
+  // FIXME: Count local symbols.
+}
+
+// Finalize the local symbols.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_relobj<size, big_endian>::do_finalize_local_symbols(
+    unsigned int index,
+    off_t,
+    Symbol_table*)
+{
+  // FIXME: Finalize local symbols.
+  return index;
+}
+
+// Set the offset where local dynamic symbol information will be stored.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_relobj<size, big_endian>::do_set_local_dynsym_indexes(
+    unsigned int index)
+{
+  // FIXME: set local dynsym indexes.
+  return index;
+}
+
+// Set the offset where local dynamic symbol information will be stored.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_relobj<size, big_endian>::do_set_local_dynsym_offset(off_t)
+{
+  return 0;
+}
+
+// Relocate the input sections and write out the local symbols.
+// We don't actually do any relocation here.  For unchanged input files,
+// we reapply relocations only for symbols that have changed; that happens
+// in queue_final_tasks.  We do need to rewrite the incremental relocations
+// for this object.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_relocate(const Symbol_table*,
+						 const Layout* layout,
+						 Output_file* of)
+{
+  if (this->incr_reloc_count_ == 0)
+    return;
+
+  const unsigned int incr_reloc_size =
+      Incremental_relocs_reader<size, big_endian>::reloc_size;
+
+  // Get a view for the .gnu_incremental_relocs section.
+  Incremental_inputs* inputs = layout->incremental_inputs();
+  gold_assert(inputs != NULL);
+  const off_t relocs_off = inputs->relocs_section()->offset();
+  const off_t relocs_size = inputs->relocs_section()->data_size();
+  unsigned char* const view = of->get_output_view(relocs_off, relocs_size);
+
+  // Copy the relocations from the buffer.
+  off_t off = this->incr_reloc_output_index_ * incr_reloc_size;
+  unsigned int len = this->incr_reloc_count_ * incr_reloc_size;
+  memcpy(view + off, this->incr_relocs_, len);
+  of->write_output_view(off, len, view);
+}
+
+// Set the offset of a section.
+
+template<int size, bool big_endian>
+void
+Sized_incr_relobj<size, big_endian>::do_set_section_offset(unsigned int,
+							   uint64_t)
+{
+}
+
+// Class Sized_incr_dynobj.  Most of these methods are not used for
+// Incremental objects, but are required to be implemented by the
+// base class Object.
+
+template<int size, bool big_endian>
+Sized_incr_dynobj<size, big_endian>::Sized_incr_dynobj(
+    const std::string& name,
+    Sized_incremental_binary<size, big_endian>* ibase,
+    unsigned int input_file_index)
+  : Dynobj(name, NULL), ibase_(ibase),
+    input_file_index_(input_file_index),
+    input_reader_(ibase->inputs_reader().input_file(input_file_index)),
+    symbols_()
+{
+  if (this->input_reader_.is_in_system_directory())
+    this->set_is_in_system_directory();
+  this->set_shnum(0);
+}
+
+// Read the symbols.
+
+template<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data*)
+{
+  gold_unreachable();
+}
+
+// Lay out the input sections.
+
+template<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_layout(
+    Symbol_table*,
+    Layout*,
+    Read_symbols_data*)
+{
+}
+
+// Add the symbols to the symbol table.
+
+template<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_add_symbols(
+    Symbol_table* symtab,
+    Read_symbols_data*,
+    Layout*)
+{
+  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  unsigned char symbuf[sym_size];
+  elfcpp::Sym<size, big_endian> sym(symbuf);
+  elfcpp::Sym_write<size, big_endian> osym(symbuf);
+
+  typedef typename elfcpp::Elf_types<size>::Elf_WXword Elf_size_type;
+
+  unsigned int nsyms = this->input_reader_.get_global_symbol_count();
+  this->symbols_.resize(nsyms);
+
+  Incremental_binary::View symtab_view(NULL);
+  unsigned int symtab_count;
+  elfcpp::Elf_strtab strtab(NULL, 0);
+  this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab);
+
+  // Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader());
+  // Incremental_relocs_reader<size, big_endian> irelocs(this->ibase_->relocs_reader());
+  // unsigned int isym_count = isymtab.symbol_count();
+  // unsigned int first_global = symtab_count - isym_count;
+
+  unsigned const char* sym_p;
+  for (unsigned int i = 0; i < nsyms; ++i)
+    {
+      bool is_def;
+      unsigned int output_symndx =
+	  this->input_reader_.get_output_symbol_index(i, &is_def);
+      sym_p = symtab_view.data() + output_symndx * sym_size;
+      elfcpp::Sym<size, big_endian> gsym(sym_p);
+      const char* name;
+      if (!strtab.get_c_string(gsym.get_st_name(), &name))
+	name = "";
+
+      typename elfcpp::Elf_types<size>::Elf_Addr v;
+      unsigned int shndx;
+      elfcpp::STB st_bind = gsym.get_st_bind();
+      elfcpp::STT st_type = gsym.get_st_type();
+
+      // Local hidden symbols start out as globals, but get converted to
+      // to local during output.
+      if (st_bind == elfcpp::STB_LOCAL)
+        st_bind = elfcpp::STB_GLOBAL;
+
+      if (!is_def)
+	{
+	  shndx = elfcpp::SHN_UNDEF;
+	  v = 0;
+	}
+      else
+	{
+	  // For a symbol defined in a shared object, the section index
+	  // is meaningless, as long as it's not SHN_UNDEF.
+	  shndx = 1;
+	  v = gsym.get_st_value();
+	}
+
+      osym.put_st_name(0);
+      osym.put_st_value(v);
+      osym.put_st_size(gsym.get_st_size());
+      osym.put_st_info(st_bind, st_type);
+      osym.put_st_other(gsym.get_st_other());
+      osym.put_st_shndx(shndx);
+
+      this->symbols_[i] =
+	symtab->add_from_incrobj<size, big_endian>(this, name, NULL, &sym);
+    }
+}
+
+// Return TRUE if we should include this object from an archive library.
+
+template<int size, bool big_endian>
+Archive::Should_include
+Sized_incr_dynobj<size, big_endian>::do_should_include_member(
+    Symbol_table*,
+    Layout*,
+    Read_symbols_data*,
+    std::string*)
+{
+  gold_unreachable();
+}
+
+// Iterate over global symbols, calling a visitor class V for each.
+
+template<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_for_all_global_symbols(
+    Read_symbols_data*,
+    Library_base::Symbol_visitor_base&)
+{
+  // FIXME: Implement Sized_incr_dynobj::do_for_all_global_symbols.
+}
+
+// Iterate over local symbols, calling a visitor class V for each GOT offset
+// associated with a local symbol.
+
+template<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_for_all_local_got_entries(
+    Got_offset_list::Visitor&) const
+{
+  // FIXME: Implement Sized_incr_dynobj::do_for_all_local_got_entries.
+}
+
+// Get the size of a section.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_size(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Get the name of a section.
+
+template<int size, bool big_endian>
+std::string
+Sized_incr_dynobj<size, big_endian>::do_section_name(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return a view of the contents of a section.
+
+template<int size, bool big_endian>
+Object::Location
+Sized_incr_dynobj<size, big_endian>::do_section_contents(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return section flags.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_flags(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return section entsize.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_entsize(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return section address.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_address(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return section type.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_dynobj<size, big_endian>::do_section_type(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return the section link field.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_dynobj<size, big_endian>::do_section_link(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return the section link field.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_incr_dynobj<size, big_endian>::do_section_info(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return the section alignment.
+
+template<int size, bool big_endian>
+uint64_t
+Sized_incr_dynobj<size, big_endian>::do_section_addralign(unsigned int)
+{
+  gold_unreachable();
+}
+
+// Return the Xindex structure to use.
+
+template<int size, bool big_endian>
+Xindex*
+Sized_incr_dynobj<size, big_endian>::do_initialize_xindex()
+{
+  gold_unreachable();
+}
+
+// Get symbol counts.
+
+template<int size, bool big_endian>
+void
+Sized_incr_dynobj<size, big_endian>::do_get_global_symbol_counts(
+    const Symbol_table*, size_t*, size_t*) const
+{
+  gold_unreachable();
+}
+
+// Allocate an incremental object of the appropriate size and endianness.
+
+Object*
+make_sized_incremental_object(
+    Incremental_binary* ibase,
+    unsigned int input_file_index,
+    Incremental_input_type input_type,
+    const Incremental_binary::Input_reader* input_reader)
+{
+  Object* obj = NULL;
+  std::string name(input_reader->filename());
+
+  switch (parameters->size_and_endianness())
+    {
+#ifdef HAVE_TARGET_32_LITTLE
+    case Parameters::TARGET_32_LITTLE:
+      {
+	Sized_incremental_binary<32, false>* sized_ibase =
+	    static_cast<Sized_incremental_binary<32, false>*>(ibase);
+	if (input_type == INCREMENTAL_INPUT_SHARED_LIBRARY)
+	  obj = new Sized_incr_dynobj<32, false>(name, sized_ibase,
+						 input_file_index);
+	else
+	  obj = new Sized_incr_relobj<32, false>(name, sized_ibase,
+						 input_file_index);
+      }
+      break;
+#endif
+#ifdef HAVE_TARGET_32_BIG
+    case Parameters::TARGET_32_BIG:
+      {
+	Sized_incremental_binary<32, true>* sized_ibase =
+	    static_cast<Sized_incremental_binary<32, true>*>(ibase);
+	if (input_type == INCREMENTAL_INPUT_SHARED_LIBRARY)
+	  obj = new Sized_incr_dynobj<32, true>(name, sized_ibase,
+						input_file_index);
+	else
+	  obj = new Sized_incr_relobj<32, true>(name, sized_ibase,
+						input_file_index);
+      }
+      break;
+#endif
+#ifdef HAVE_TARGET_64_LITTLE
+    case Parameters::TARGET_64_LITTLE:
+      {
+	Sized_incremental_binary<64, false>* sized_ibase =
+	    static_cast<Sized_incremental_binary<64, false>*>(ibase);
+	if (input_type == INCREMENTAL_INPUT_SHARED_LIBRARY)
+	  obj = new Sized_incr_dynobj<64, false>(name, sized_ibase,
+						 input_file_index);
+	else
+	  obj = new Sized_incr_relobj<64, false>(name, sized_ibase,
+						 input_file_index);
+     }
+      break;
+#endif
+#ifdef HAVE_TARGET_64_BIG
+    case Parameters::TARGET_64_BIG:
+      {
+	Sized_incremental_binary<64, true>* sized_ibase =
+	    static_cast<Sized_incremental_binary<64, true>*>(ibase);
+	if (input_type == INCREMENTAL_INPUT_SHARED_LIBRARY)
+	  obj = new Sized_incr_dynobj<64, true>(name, sized_ibase,
+						input_file_index);
+	else
+	  obj = new Sized_incr_relobj<64, true>(name, sized_ibase,
+						input_file_index);
+      }
+      break;
+#endif
+    default:
+      gold_unreachable();
+    }
+
+  gold_assert(obj != NULL);
+  return obj;
+}
+
+// Copy the unused symbols from the incremental input info.
+// We need to do this because we may be overwriting the incremental
+// input info in the base file before we write the new incremental
+// info.
+void
+Incremental_library::copy_unused_symbols()
+{ 
+  unsigned int symcount = this->input_reader_->get_unused_symbol_count();
+  this->unused_symbols_.reserve(symcount);
+  for (unsigned int i = 0; i < symcount; ++i)
+    {
+      std::string name(this->input_reader_->get_unused_symbol(i));
+      this->unused_symbols_.push_back(name);
+    }
+}
+
+// Iterator for unused global symbols in the library.
+void
+Incremental_library::do_for_all_unused_symbols(Symbol_visitor_base& v) const
+{
+  for (Symbol_list::const_iterator p = this->unused_symbols_.begin();
+       p != this->unused_symbols_.end();
+       ++p)
+  v.visit(p->c_str());
+}
+
 // Instantiate the templates we need.
 
 #ifdef HAVE_TARGET_32_LITTLE
 template
 class Sized_incremental_binary<32, false>;
+
+template
+class Sized_incr_relobj<32, false>;
+
+template
+class Sized_incr_dynobj<32, false>;
 #endif
 
 #ifdef HAVE_TARGET_32_BIG
 template
 class Sized_incremental_binary<32, true>;
+
+template
+class Sized_incr_relobj<32, true>;
+
+template
+class Sized_incr_dynobj<32, true>;
 #endif
 
 #ifdef HAVE_TARGET_64_LITTLE
 template
 class Sized_incremental_binary<64, false>;
+
+template
+class Sized_incr_relobj<64, false>;
+
+template
+class Sized_incr_dynobj<64, false>;
 #endif
 
 #ifdef HAVE_TARGET_64_BIG
 template
 class Sized_incremental_binary<64, true>;
+
+template
+class Sized_incr_relobj<64, true>;
+
+template
+class Sized_incr_dynobj<64, true>;
 #endif
 
 } // End namespace gold.
diff --git a/gold/incremental.h b/gold/incremental.h
index 2d0640c..c1f8148 100644
--- a/gold/incremental.h
+++ b/gold/incremental.h
@@ -31,11 +31,11 @@
 #include "workqueue.h"
 #include "fileread.h"
 #include "output.h"
+#include "archive.h"
 
 namespace gold
 {
 
-class Archive;
 class Input_argument;
 class Incremental_inputs_checker;
 class Incremental_script_entry;
@@ -43,7 +43,9 @@ class Incremental_object_entry;
 class Incremental_archive_entry;
 class Incremental_inputs;
 class Incremental_binary;
+class Incremental_library;
 class Object;
+class Script_info;
 
 // Incremental input type as stored in .gnu_incremental_inputs.
 
@@ -56,49 +58,29 @@ enum Incremental_input_type
   INCREMENTAL_INPUT_SCRIPT = 5
 };
 
+// Incremental input file flags.
+// The input file type is stored in the lower eight bits.
+
+enum Incremental_input_flags
+{
+  INCREMENTAL_INPUT_IN_SYSTEM_DIR = 0x0800
+};
+
 // Create an Incremental_binary object for FILE. Returns NULL is this is not
 // possible, e.g. FILE is not an ELF file or has an unsupported target.
 
 Incremental_binary*
 open_incremental_binary(Output_file* file);
 
-// Code invoked early during an incremental link that checks what files need
-// to be relinked.
-
-class Incremental_checker
-{
- public:
-  // Check if the file named OUTPUT_NAME can be linked incrementally.
-  // INCREMENTAL_INPUTS must have the canonical form of the command line
-  // and input arguments filled - at this point of linking other fields are
-  // probably not filled yet.  TODO: for inputs that don't need to be
-  // rebuilt, this function should fill the incremental input information.
-  Incremental_checker(const char* output_name,
-                      Incremental_inputs* incremental_inputs)
-    : output_name_(output_name), incremental_inputs_(incremental_inputs)
-  { }
-
-  // Analyzes the output file to check if incremental linking is possible and
-  // what files needs to be relinked.
-  bool
-  can_incrementally_link_output_file();
-
- private:
-  // Name of the output file to analyze.
-  const char* output_name_;
-
-  // The Incremental_inputs object. At this stage of link, only the command
-  // line and inputs are filled.
-  Incremental_inputs* incremental_inputs_;
-};
-
 // Base class for recording each input file.
 
 class Incremental_input_entry
 {
  public:
-  Incremental_input_entry(Stringpool::Key filename_key, Timespec mtime)
-    : filename_key_(filename_key), offset_(0), info_offset_(0), mtime_(mtime)
+  Incremental_input_entry(Stringpool::Key filename_key, unsigned int arg_serial,
+			  Timespec mtime)
+    : filename_key_(filename_key), offset_(0), info_offset_(0),
+      arg_serial_(arg_serial), mtime_(mtime), is_in_system_directory_(false)
   { }
 
   virtual
@@ -135,11 +117,26 @@ class Incremental_input_entry
   get_filename_key() const
   { return this->filename_key_; }
 
+  // Get the serial number of the input file.
+  unsigned int
+  arg_serial() const
+  { return this->arg_serial_; }
+
   // Get the modification time of the input file.
   const Timespec&
   get_mtime() const
   { return this->mtime_; }
 
+  // Record that the file was found in a system directory.
+  void
+  set_is_in_system_directory()
+  { this->is_in_system_directory_ = true; }
+
+  // Return TRUE if the file was found in a system directory.
+  bool
+  is_in_system_directory() const
+  { return this->is_in_system_directory_; }
+
   // Return a pointer to the derived Incremental_script_entry object.
   // Return NULL for input entries that are not script files.
   Incremental_script_entry*
@@ -191,8 +188,45 @@ class Incremental_input_entry
   // Offset of the extra information in the output section.
   unsigned int info_offset_;
 
+  // Serial number of the file in the argument list.
+  unsigned int arg_serial_;
+
   // Last modification time of the file.
   Timespec mtime_;
+
+  // TRUE if the file was found in a system directory.
+  bool is_in_system_directory_;
+};
+
+// Information about a script input that will persist during the whole linker
+// run.  Needed only during an incremental build to retrieve the input files
+// added by this script.
+
+class Script_info
+{
+ public:
+  Script_info(const std::string& filename)
+    : filename_(filename), incremental_script_entry_(NULL)
+  { }
+
+  // Store a pointer to the incremental information for this script.
+  void
+  set_incremental_info(Incremental_script_entry* entry)
+  { this->incremental_script_entry_ = entry; }
+
+  // Return the filename.
+  const std::string&
+  filename() const
+  { return this->filename_; }
+
+  // Return the pointer to the incremental information for this script.
+  Incremental_script_entry*
+  incremental_info() const
+  { return this->incremental_script_entry_; }
+
+ private:
+  const std::string filename_;
+  Incremental_script_entry* incremental_script_entry_;
 };
 
 // Class for recording input scripts.
@@ -200,9 +234,11 @@ class Incremental_input_entry
 class Incremental_script_entry : public Incremental_input_entry
 {
  public:
-  Incremental_script_entry(Stringpool::Key filename_key, Script_info* script,
+  Incremental_script_entry(Stringpool::Key filename_key,
+			   unsigned int arg_serial, Script_info* script,
 			   Timespec mtime)
-    : Incremental_input_entry(filename_key, mtime), script_(script), objects_()
+    : Incremental_input_entry(filename_key, arg_serial, mtime),
+      script_(script), objects_()
   { }
 
   // Add a member object to the archive.
@@ -245,8 +281,8 @@ class Incremental_object_entry : public Incremental_input_entry
 {
  public:
   Incremental_object_entry(Stringpool::Key filename_key, Object* obj,
-			   Timespec mtime)
-    : Incremental_input_entry(filename_key, mtime), obj_(obj),
+			   unsigned int arg_serial, Timespec mtime)
+    : Incremental_input_entry(filename_key, arg_serial, mtime), obj_(obj),
       is_member_(false), sections_()
   {
     if (!obj_->is_dynamic())
@@ -271,27 +307,27 @@ class Incremental_object_entry : public Incremental_input_entry
   // Add an input section.
   void
   add_input_section(unsigned int shndx, Stringpool::Key name_key, off_t sh_size)
-  {
-    if (shndx >= this->sections_.size())
-      this->sections_.resize(shndx + 1);
-    this->sections_[shndx].name_key = name_key;
-    this->sections_[shndx].sh_size = sh_size;
-  }
+  { this->sections_.push_back(Input_section(shndx, name_key, sh_size)); }
 
   // Return the number of input sections in this object.
   unsigned int
   get_input_section_count() const
   { return this->sections_.size(); }
 
+  // Return the input section index for the Nth input section.
+  Stringpool::Key
+  get_input_section_index(unsigned int n) const
+  { return this->sections_[n].shndx_; }
+
   // Return the stringpool key of the Nth input section.
   Stringpool::Key
   get_input_section_name_key(unsigned int n) const
-  { return this->sections_[n].name_key; }
+  { return this->sections_[n].name_key_; }
 
   // Return the size of the Nth input section.
   off_t
   get_input_section_size(unsigned int n) const
-  { return this->sections_[n].sh_size; }
+  { return this->sections_[n].sh_size_; }
 
  protected:
   virtual Incremental_input_type
@@ -319,8 +355,12 @@ class Incremental_object_entry : public Incremental_input_entry
   // Input sections.
   struct Input_section
   {
-    Stringpool::Key name_key;
-    off_t sh_size;
+    Input_section(unsigned int shndx, Stringpool::Key name_key, off_t sh_size)
+      : shndx_(shndx), name_key_(name_key), sh_size_(sh_size)
+    { }
+    unsigned int shndx_;
+    Stringpool::Key name_key_;
+    off_t sh_size_;
   };
   std::vector<Input_section> sections_;
 };
@@ -330,8 +370,10 @@ class Incremental_object_entry : public Incremental_input_entry
 class Incremental_archive_entry : public Incremental_input_entry
 {
  public:
-  Incremental_archive_entry(Stringpool::Key filename_key, Timespec mtime)
-    : Incremental_input_entry(filename_key, mtime), members_(), unused_syms_()
+  Incremental_archive_entry(Stringpool::Key filename_key,
+			    unsigned int arg_serial, Timespec mtime)
+    : Incremental_input_entry(filename_key, arg_serial, mtime), members_(),
+      unused_syms_()
   { }
 
   // Add a member object to the archive.
@@ -409,7 +451,8 @@ class Incremental_inputs
 
   // Record the initial info for archive file ARCHIVE.
   void
-  report_archive_begin(Library_base* arch, Script_info* script_info);
+  report_archive_begin(Library_base* arch, unsigned int arg_serial,
+		       Script_info* script_info);
 
   // Record the final info for archive file ARCHIVE.
   void
@@ -418,7 +461,8 @@ class Incremental_inputs
   // Record the info for object file OBJ.  If ARCH is not NULL,
   // attach the object file to the archive.
   void
-  report_object(Object* obj, Library_base* arch, Script_info* script_info);
+  report_object(Object* obj, unsigned int arg_serial, Library_base* arch,
+		Script_info* script_info);
 
   // Record an input section belonging to object file OBJ.
   void
@@ -427,7 +471,7 @@ class Incremental_inputs
 
   // Record the info for input script SCRIPT.
   void
-  report_script(const std::string& filename, Script_info* script,
+  report_script(Script_info* script, unsigned int arg_serial,
 		Timespec mtime);
 
   // Return the running count of incremental relocations.
@@ -534,6 +578,45 @@ class Incremental_inputs
   unsigned int reloc_count_;
 };
 
+// Reader class for global symbol info from an object file entry in
+// the .gnu_incremental_inputs section.
+
+template<bool big_endian>
+class Incremental_global_symbol_reader
+{
+ private:
+  typedef elfcpp::Swap<32, big_endian> Swap32;
+
+ public:
+  Incremental_global_symbol_reader(const unsigned char* p)
+    : p_(p)
+  { }
+
+  unsigned int
+  output_symndx() const
+  { return Swap32::readval(this->p_); }
+
+  unsigned int
+  shndx() const
+  { return Swap32::readval(this->p_ + 4); }
+
+  unsigned int
+  next_offset() const
+  { return Swap32::readval(this->p_ + 8); }
+
+  unsigned int
+  reloc_count() const
+  { return Swap32::readval(this->p_ + 12); }
+
+  unsigned int
+  reloc_offset() const
+  { return Swap32::readval(this->p_ + 16); }
+
+ private:
+  // Base address of the symbol entry.
+  const unsigned char* p_;
+};
+
 // Reader class for .gnu_incremental_inputs section.
 
 template<int size, bool big_endian>
@@ -582,8 +665,7 @@ class Incremental_inputs_reader
       : inputs_(inputs), offset_(offset)
     {
       this->info_offset_ = Swap32::readval(inputs->p_ + offset + 4);
-      int type = Swap16::readval(this->inputs_->p_ + offset + 20);
-      this->type_ = static_cast<Incremental_input_type>(type);
+      this->flags_ = Swap16::readval(this->inputs_->p_ + offset + 20);
     }
 
     // Return the filename.
@@ -594,6 +676,13 @@ class Incremental_inputs_reader
       return this->inputs_->get_string(offset);
     }
 
+    // Return the argument serial number.
+    unsigned int
+    arg_serial() const
+    {
+      return Swap16::readval(this->inputs_->p_ + this->offset_ + 22);
+    }
+
     // Return the timestamp.
     Timespec
     get_mtime() const
@@ -608,14 +697,19 @@ class Incremental_inputs_reader
     // Return the type of input file.
     Incremental_input_type
     type() const
-    { return this->type_; }
+    { return static_cast<Incremental_input_type>(this->flags_ & 0xff); }
+
+    // Return TRUE if the file was found in a system directory.
+    bool
+    is_in_system_directory() const
+    { return (this->flags_ & INCREMENTAL_INPUT_IN_SYSTEM_DIR) != 0; }
 
     // Return the input section count -- for objects only.
     unsigned int
     get_input_section_count() const
     {
-      gold_assert(this->type_ == INCREMENTAL_INPUT_OBJECT
-		  || this->type_ == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
+      gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT
+		  || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
       return Swap32::readval(this->inputs_->p_ + this->info_offset_);
     }
 
@@ -624,20 +718,20 @@ class Incremental_inputs_reader
     unsigned int
     get_symbol_offset(unsigned int symndx) const
     {
-      gold_assert(this->type_ == INCREMENTAL_INPUT_OBJECT
-		  || this->type_ == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
+      gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT
+		  || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
 
       unsigned int section_count = this->get_input_section_count();
       return (this->info_offset_ + 8
 	      + section_count * input_section_entry_size
-	      + symndx * 16);
+	      + symndx * 20);
     }
 
     // Return the global symbol count -- for objects & shared libraries only.
     unsigned int
     get_global_symbol_count() const
     {
-      switch (this->type_)
+      switch (this->type())
 	{
 	case INCREMENTAL_INPUT_OBJECT:
 	case INCREMENTAL_INPUT_ARCHIVE_MEMBER:
@@ -653,7 +747,7 @@ class Incremental_inputs_reader
     unsigned int
     get_object_count() const
     {
-      gold_assert(this->type_ == INCREMENTAL_INPUT_SCRIPT);
+      gold_assert(this->type() == INCREMENTAL_INPUT_SCRIPT);
       return Swap32::readval(this->inputs_->p_ + this->info_offset_);
     }
 
@@ -661,7 +755,7 @@ class Incremental_inputs_reader
     unsigned int
     get_object_offset(unsigned int n) const
     {
-      gold_assert(this->type_ == INCREMENTAL_INPUT_SCRIPT);
+      gold_assert(this->type() == INCREMENTAL_INPUT_SCRIPT);
       return Swap32::readval(this->inputs_->p_ + this->info_offset_
 			     + 4 + n * 4);
     }
@@ -670,7 +764,7 @@ class Incremental_inputs_reader
     unsigned int
     get_member_count() const
     {
-      gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE);
+      gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE);
       return Swap32::readval(this->inputs_->p_ + this->info_offset_);
     }
 
@@ -678,7 +772,7 @@ class Incremental_inputs_reader
     unsigned int
     get_unused_symbol_count() const
     {
-      gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE);
+      gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE);
       return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4);
     }
 
@@ -686,7 +780,7 @@ class Incremental_inputs_reader
     unsigned int
     get_member_offset(unsigned int n) const
     {
-      gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE);
+      gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE);
       return Swap32::readval(this->inputs_->p_ + this->info_offset_
 			     + 8 + n * 4);
     }
@@ -695,7 +789,7 @@ class Incremental_inputs_reader
     const char*
     get_unused_symbol(unsigned int n) const
     {
-      gold_assert(this->type_ == INCREMENTAL_INPUT_ARCHIVE);
+      gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE);
       unsigned int member_count = this->get_member_count();
       unsigned int offset = Swap32::readval(this->inputs_->p_
 					    + this->info_offset_ + 8
@@ -729,30 +823,33 @@ class Incremental_inputs_reader
       return info;
     }
 
-    // Information about a global symbol.
-    struct Global_symbol_info
-    {
-      unsigned int output_symndx;
-      unsigned int next_offset;
-      unsigned int reloc_count;
-      unsigned int reloc_offset;
-    };
-
     // Return info about the Nth global symbol -- for objects only.
-    Global_symbol_info
-    get_global_symbol_info(unsigned int n) const
+    Incremental_global_symbol_reader<big_endian>
+    get_global_symbol_reader(unsigned int n) const
     {
-      Global_symbol_info info;
+      gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT
+		  || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER);
       unsigned int section_count = this->get_input_section_count();
       const unsigned char* p = (this->inputs_->p_
 				+ this->info_offset_ + 8
 				+ section_count * input_section_entry_size
-				+ n * 16);
-      info.output_symndx = Swap32::readval(p);
-      info.next_offset = Swap32::readval(p + 4);
-      info.reloc_count = Swap::readval(p + 8);
-      info.reloc_offset = Swap::readval(p + 12);
-      return info;
+				+ n * 20);
+      return Incremental_global_symbol_reader<big_endian>(p);
+    }
+
+    // Return the output symbol index for the Nth global symbol -- for shared
+    // libraries only.  Sets *IS_DEF to TRUE if the symbol is defined in this
+    // input file.
+    unsigned int
+    get_output_symbol_index(unsigned int n, bool* is_def)
+    {
+      gold_assert(this->type() == INCREMENTAL_INPUT_SHARED_LIBRARY);
+      const unsigned char* p = (this->inputs_->p_
+				+ this->info_offset_ + 4
+				+ n * 4);
+      unsigned int output_symndx = Swap32::readval(p);
+      *is_def = (output_symndx & (1U << 31)) != 0;
+      return output_symndx & ((1U << 31) - 1);
     }
 
    private:
@@ -760,21 +857,42 @@ class Incremental_inputs_reader
     static const unsigned int input_section_entry_size = 8 + 2 * size / 8;
     // The reader instance for the containing section.
     const Incremental_inputs_reader* inputs_;
-    // The type of input file.
-    Incremental_input_type type_;
+    // The flags, including the type of input file.
+    unsigned int flags_;
     // Section offset to the input file entry.
     unsigned int offset_;
     // Section offset to the supplemental info for the input file.
     unsigned int info_offset_;
   };
 
+  // Return the offset of an input file entry given its index N.
+  unsigned int
+  input_file_offset(unsigned int n) const
+  {
+    gold_assert(n < this->input_file_count_);
+    return 16 + n * 24;
+  }
+
+  // Return the index of an input file entry given its OFFSET.
+  unsigned int
+  input_file_index(unsigned int offset) const
+  {
+    int n = (offset - 16) / 24;
+    gold_assert(input_file_offset(n) == offset);
+    return n;
+  }
+
   // Return a reader for the Nth input file entry.
   Incremental_input_entry_reader
   input_file(unsigned int n) const
+  { return Incremental_input_entry_reader(this, this->input_file_offset(n)); }
+
+  // Return a reader for the input file entry at OFFSET.
+  Incremental_input_entry_reader
+  input_file_at_offset(unsigned int offset) const
   {
-    gold_assert(n < this->input_file_count_);
-    Incremental_input_entry_reader input(this, 16 + n * 24);
-    return input;
+    gold_assert(offset < 16 + this->input_file_count_ * 24);
+    return Incremental_input_entry_reader(this, offset);
   }
 
  private:
@@ -858,23 +976,17 @@ class Incremental_relocs_reader
   // Return the relocation type for relocation entry at offset OFF.
   unsigned int
   get_r_type(unsigned int off) const
-  {
-    return elfcpp::Swap<32, big_endian>::readval(this->p_ + off);
-  }
+  { return elfcpp::Swap<32, big_endian>::readval(this->p_ + off); }
 
   // Return the output section index for relocation entry at offset OFF.
   unsigned int
   get_r_shndx(unsigned int off) const
-  {
-    return elfcpp::Swap<32, big_endian>::readval(this->p_ + off + 4);
-  }
+  { return elfcpp::Swap<32, big_endian>::readval(this->p_ + off + 4); }
 
   // Return the output section offset for relocation entry at offset OFF.
   Address
   get_r_offset(unsigned int off) const
-  {
-    return elfcpp::Swap<size, big_endian>::readval(this->p_ + off + 8);
-  }
+  { return elfcpp::Swap<size, big_endian>::readval(this->p_ + off + 8); }
 
   // Return the addend for relocation entry at offset OFF.
   Addend
@@ -884,6 +996,11 @@ class Incremental_relocs_reader
 						   + this->field_size);
   }
 
+  // Return a pointer to the relocation entry at offset OFF.
+  const unsigned char*
+  data(unsigned int off) const
+  { return this->p_ + off; }
+
  private:
   // Base address of the .gnu_incremental_relocs section.
   const unsigned char* p_;
@@ -964,7 +1081,8 @@ class Incremental_binary
 {
  public:
   Incremental_binary(Output_file* output, Target* target)
-    : output_(output), target_(target)
+    : input_args_map_(), library_map_(), script_map_(),
+      output_(output), target_(target)
   { }
 
   virtual
@@ -974,20 +1092,15 @@ class Incremental_binary
   // Check the .gnu_incremental_inputs section to see whether an incremental
   // build is possible.
   bool
-  check_inputs(Incremental_inputs* incremental_inputs)
-  { return this->do_check_inputs(incremental_inputs); }
-
-  // Return TRUE if the file specified by INPUT_ARGUMENT is unchanged
-  // with respect to the base file.
-  bool
-  file_is_unchanged(const Input_argument* input_argument) const
-  { return this->do_file_is_unchanged(input_argument); }
+  check_inputs(const Command_line& cmdline,
+	       Incremental_inputs* incremental_inputs)
+  { return this->do_check_inputs(cmdline, incremental_inputs); }
 
   // Report an error.
   void
   error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
 
-  // Wrapper class for a sized Incremental_input_entry_reader.
+  // Proxy class for a sized Incremental_input_entry_reader.
   
   class Input_reader
   {
@@ -1011,6 +1124,18 @@ class Incremental_binary
     type() const
     { return this->do_type(); }
 
+    unsigned int
+    arg_serial() const
+    { return this->do_arg_serial(); }
+
+    unsigned int
+    get_unused_symbol_count() const
+    { return this->do_get_unused_symbol_count(); }
+
+    const char*
+    get_unused_symbol(unsigned int n) const
+    { return this->do_get_unused_symbol(n); }
+
    protected:
     virtual const char*
     do_filename() const = 0;
@@ -1020,11 +1145,64 @@ class Incremental_binary
 
     virtual Incremental_input_type
     do_type() const = 0;
+
+    virtual unsigned int
+    do_arg_serial() const = 0;
+
+    virtual unsigned int
+    do_get_unused_symbol_count() const = 0;
+
+    virtual const char*
+    do_get_unused_symbol(unsigned int n) const = 0;
   };
 
-  Input_reader*
-  get_input_reader(const char* filename)
-  { return this->do_get_input_reader(filename); }
+  // Return the number of input files.
+  unsigned int
+  input_file_count() const
+  { return this->do_input_file_count(); }
+
+  // Return an Input_reader for input file N.
+  const Input_reader*
+  get_input_reader(unsigned int n) const
+  { return this->do_get_input_reader(n); }
+
+  // Return TRUE if the input file N has changed since the last link.
+  bool
+  file_has_changed(unsigned int n) const
+  { return this->do_file_has_changed(n); }
+
+  // Return the Input_argument for input file N.  Returns NULL if
+  // the Input_argument is not available.
+  const Input_argument*
+  get_input_argument(unsigned int n) const
+  {
+    const Input_reader* input_file = this->do_get_input_reader(n);
+    unsigned int arg_serial = input_file->arg_serial();
+    if (arg_serial == 0 || arg_serial > this->input_args_map_.size())
+      return NULL;
+    return this->input_args_map_[arg_serial - 1];
+  }
+
+  // Return an Incremental_library for the given input file.
+  Incremental_library*
+  get_library(unsigned int n)
+  { return this->library_map_[n]; }
+
+  // Return a Script_info for the given input file.
+  Script_info*
+  get_script_info(unsigned int n)
+  { return this->script_map_[n]; }
+
+  // Initialize the layout of the output file based on the existing
+  // output file.
+  void
+  init_layout(Layout* layout)
+  { this->do_init_layout(layout); }
+
+  // Mark regions of the input file that must be kept unchanged.
+  void
+  reserve_layout(unsigned int input_file_index)
+  { this->do_reserve_layout(input_file_index); }
 
   // Functions and types for the elfcpp::Elf_file interface.  This
   // permit us to use Incremental_binary as the File template parameter for
@@ -1073,19 +1251,43 @@ class Incremental_binary
   view(Location loc)
   { return View(this->view(loc.file_offset, loc.data_size)); }
 
+  // Return the Output_file.
+  Output_file*
+  output_file()
+  { return this->output_; }
+
  protected:
   // Check the .gnu_incremental_inputs section to see whether an incremental
   // build is possible.
   virtual bool
-  do_check_inputs(Incremental_inputs* incremental_inputs) = 0;
+  do_check_inputs(const Command_line& cmdline,
+		  Incremental_inputs* incremental_inputs) = 0;
 
-  // Return TRUE if the file specified by INPUT_ARGUMENT is unchanged
-  // with respect to the base file.
+  // Return TRUE if input file N has changed since the last incremental link.
   virtual bool
-  do_file_is_unchanged(const Input_argument* input_argument) const = 0;
+  do_file_has_changed(unsigned int n) const = 0;
+
+  // Initialize the layout of the output file based on the existing
+  // output file.
+  virtual void
+  do_init_layout(Layout* layout) = 0;
+
+  // Mark regions of the input file that must be kept unchanged.
+  virtual void
+  do_reserve_layout(unsigned int input_file_index) = 0;
+
+  virtual unsigned int
+  do_input_file_count() const = 0;
 
-  virtual Input_reader*
-  do_get_input_reader(const char* filename) = 0;
+  virtual const Input_reader*
+  do_get_input_reader(unsigned int) const = 0;
+
+  // Map from input file index to Input_argument.
+  std::vector<const Input_argument*> input_args_map_;
+  // Map from an input file index to an Incremental_library.
+  std::vector<Incremental_library*> library_map_;
+  // Map from an input file index to a Script_info.
+  std::vector<Script_info*> script_map_;
 
  private:
   // Edited output file object.
@@ -1102,8 +1304,9 @@ class Sized_incremental_binary : public Incremental_binary
                            const elfcpp::Ehdr<size, big_endian>& ehdr,
                            Target* target)
     : Incremental_binary(output, target), elf_file_(this, ehdr),
-      has_incremental_info_(false), inputs_reader_(), symtab_reader_(),
-      relocs_reader_(), got_plt_reader_(), current_input_file_(0)
+      section_map_(), has_incremental_info_(false), inputs_reader_(),
+      symtab_reader_(), relocs_reader_(), got_plt_reader_(),
+      input_entry_readers_()
   { this->setup_readers(); }
 
   // Returns TRUE if the file contains incremental info.
@@ -1111,42 +1314,60 @@ class Sized_incremental_binary : public Incremental_binary
   has_incremental_info() const
   { return this->has_incremental_info_; }
 
+  // Return the Output_section for section index SHNDX.
+  Output_section*
+  output_section(unsigned int shndx)
+  { return this->section_map_[shndx]; }
+
   // Readers for the incremental info sections.
 
-  Incremental_inputs_reader<size, big_endian>
+  const Incremental_inputs_reader<size, big_endian>&
   inputs_reader() const
   { return this->inputs_reader_; }
 
-  Incremental_symtab_reader<big_endian>
+  const Incremental_symtab_reader<big_endian>&
   symtab_reader() const
   { return this->symtab_reader_; }
 
-  Incremental_relocs_reader<size, big_endian>
+  const Incremental_relocs_reader<size, big_endian>&
   relocs_reader() const
   { return this->relocs_reader_; }
 
-  Incremental_got_plt_reader<big_endian>
+  const Incremental_got_plt_reader<big_endian>&
   got_plt_reader() const
   { return this->got_plt_reader_; }
 
+  void
+  get_symtab_view(View* symtab_view, unsigned int* sym_count,
+		  elfcpp::Elf_strtab* strtab);
+
  protected:
+  typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+  typedef typename Inputs_reader::Incremental_input_entry_reader
+      Input_entry_reader;
+
   virtual bool
-  do_check_inputs(Incremental_inputs* incremental_inputs);
+  do_check_inputs(const Command_line& cmdline,
+		  Incremental_inputs* incremental_inputs);
 
-  // Return TRUE if the file specified by INPUT_ARGUMENT is unchanged
-  // with respect to the base file.
+  // Return TRUE if input file N has changed since the last incremental link.
   virtual bool
-  do_file_is_unchanged(const Input_argument* input_argument) const;
+  do_file_has_changed(unsigned int n) const;
+
+  // Initialize the layout of the output file based on the existing
+  // output file.
+  virtual void
+  do_init_layout(Layout* layout);
 
-  // Wrapper class for a sized Incremental_input_entry_reader.
+  // Mark regions of the input file that must be kept unchanged.
+  virtual void
+  do_reserve_layout(unsigned int input_file_index);
+
+  // Proxy class for a sized Incremental_input_entry_reader.
   
   class Sized_input_reader : public Input_reader
   {
    public:
-    typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
-    typedef typename Inputs_reader::Incremental_input_entry_reader
-        Input_entry_reader;
-
     Sized_input_reader(Input_entry_reader r)
       : Input_reader(), reader_(r)
     { }
@@ -1168,11 +1389,31 @@ class Sized_incremental_binary : public Incremental_binary
     do_type() const
     { return this->reader_.type(); }
 
+    unsigned int
+    do_arg_serial() const
+    { return this->reader_.arg_serial(); }
+
+    unsigned int
+    do_get_unused_symbol_count() const
+    { return this->reader_.get_unused_symbol_count(); }
+
+    const char*
+    do_get_unused_symbol(unsigned int n) const
+    { return this->reader_.get_unused_symbol(n); }
+
     Input_entry_reader reader_;
   };
 
-  virtual Input_reader*
-  do_get_input_reader(const char* filename);
+  virtual unsigned int
+  do_input_file_count() const
+  { return this->inputs_reader_.input_file_count(); }
+
+  virtual const Input_reader*
+  do_get_input_reader(unsigned int n) const
+  {
+    gold_assert(n < this->input_entry_readers_.size());
+    return &this->input_entry_readers_[n];
+  }
 
  private:
   bool
@@ -1188,15 +1429,418 @@ class Sized_incremental_binary : public Incremental_binary
   // Output as an ELF file.
   elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file_;
 
+  // Map section index to an Output_section in the updated layout.
+  std::vector<Output_section*> section_map_;
+
   // Readers for the incremental info sections.
   bool has_incremental_info_;
   Incremental_inputs_reader<size, big_endian> inputs_reader_;
   Incremental_symtab_reader<big_endian> symtab_reader_;
   Incremental_relocs_reader<size, big_endian> relocs_reader_;
   Incremental_got_plt_reader<big_endian> got_plt_reader_;
+  std::vector<Sized_input_reader> input_entry_readers_;
+};
+
+// An incremental Relobj.  This class represents a relocatable object
+// that has not changed since the last incremental link, and whose contents
+// can be used directly from the base file.
+
+template<int size, bool big_endian>
+class Sized_incr_relobj : public Sized_relobj_base<size, big_endian>
+{
+ public:
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+  typedef typename Sized_relobj_base<size, big_endian>::Symbols Symbols;
+
+  static const Address invalid_address = static_cast<Address>(0) - 1;
+
+  Sized_incr_relobj(const std::string& name,
+		    Sized_incremental_binary<size, big_endian>* ibase,
+		    unsigned int input_file_index);
+
+  // Checks if the offset of input section SHNDX within its output
+  // section is invalid. 
+  bool
+  is_output_section_offset_invalid(unsigned int shndx) const
+  { return this->section_offsets_[shndx] == invalid_address; }
+
+  // Get the offset of input section SHNDX within its output section.
+  // This is -1 if the input section requires a special mapping, such
+  // as a merge section.  The output section can be found in the
+  // output_sections_ field of the parent class Incrobj.
+  uint64_t
+  do_output_section_offset(unsigned int shndx) const
+  {
+    gold_assert(shndx < this->section_offsets_.size());
+    Address off = this->section_offsets_[shndx];
+    if (off == invalid_address)
+      return -1ULL;
+    return off;
+  }
+
+ private:
+  typedef typename Sized_relobj_base<size, big_endian>::Output_sections
+      Output_sections;
+  typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+  typedef typename Inputs_reader::Incremental_input_entry_reader
+      Input_entry_reader;
+
+  // Return TRUE if this is an incremental (unchanged) input file.
+  bool
+  do_is_incremental() const
+  { return true; }
+
+  // Return the last modified time of the file.
+  Timespec
+  do_get_mtime()
+  { return this->input_reader_.get_mtime(); }
+
+  // Read the symbols.
+  void
+  do_read_symbols(Read_symbols_data*);
+
+  // Lay out the input sections.
+  void
+  do_layout(Symbol_table*, Layout*, Read_symbols_data*);
+
+  // Layout sections whose layout was deferred while waiting for
+  // input files from a plugin.
+  void
+  do_layout_deferred_sections(Layout*);
+
+  // Add the symbols to the symbol table.
+  void
+  do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*);
+
+  Archive::Should_include
+  do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*,
+                           std::string* why);
+
+  // Iterate over global symbols, calling a visitor class V for each.
+  void
+  do_for_all_global_symbols(Read_symbols_data* sd,
+			    Library_base::Symbol_visitor_base& v);
+
+  // Iterate over local symbols, calling a visitor class V for each GOT offset
+  // associated with a local symbol.
+  void
+  do_for_all_local_got_entries(Got_offset_list::Visitor& v) const;
+
+  // Get the size of a section.
+  uint64_t
+  do_section_size(unsigned int shndx);
+
+  // Get the name of a section.
+  std::string
+  do_section_name(unsigned int shndx);
+
+  // Return a view of the contents of a section.
+  Object::Location
+  do_section_contents(unsigned int shndx);
+
+  // Return section flags.
+  uint64_t
+  do_section_flags(unsigned int shndx);
+
+  // Return section entsize.
+  uint64_t
+  do_section_entsize(unsigned int shndx);
+
+  // Return section address.
+  uint64_t
+  do_section_address(unsigned int shndx);
+
+  // Return section type.
+  unsigned int
+  do_section_type(unsigned int shndx);
+
+  // Return the section link field.
+  unsigned int
+  do_section_link(unsigned int shndx);
+
+  // Return the section link field.
+  unsigned int
+  do_section_info(unsigned int shndx);
+
+  // Return the section alignment.
+  uint64_t
+  do_section_addralign(unsigned int shndx);
+
+  // Return the Xindex structure to use.
+  Xindex*
+  do_initialize_xindex();
+
+  // Get symbol counts.
+  void
+  do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const;
+
+  // Get global symbols.
+  const Symbols*
+  do_get_global_symbols() const
+  { return &this->symbols_; }
+
+  // Return the number of local symbols.
+  unsigned int
+  do_local_symbol_count() const
+  { return 0; }
+
+  // Read the relocs.
+  void
+  do_read_relocs(Read_relocs_data*);
+
+  // Process the relocs to find list of referenced sections. Used only
+  // during garbage collection.
+  void
+  do_gc_process_relocs(Symbol_table*, Layout*, Read_relocs_data*);
+
+  // Scan the relocs and adjust the symbol table.
+  void
+  do_scan_relocs(Symbol_table*, Layout*, Read_relocs_data*);
+
+  // Count the local symbols.
+  void
+  do_count_local_symbols(Stringpool_template<char>*,
+			 Stringpool_template<char>*);
+
+  // Finalize the local symbols.
+  unsigned int
+  do_finalize_local_symbols(unsigned int, off_t, Symbol_table*);
+
+  // Set the offset where local dynamic symbol information will be stored.
+  unsigned int
+  do_set_local_dynsym_indexes(unsigned int);
+
+  // Set the offset where local dynamic symbol information will be stored.
+  unsigned int
+  do_set_local_dynsym_offset(off_t);
+
+  // Relocate the input sections and write out the local symbols.
+  void
+  do_relocate(const Symbol_table* symtab, const Layout*, Output_file* of);
+
+  // Set the offset of a section.
+  void
+  do_set_section_offset(unsigned int shndx, uint64_t off);
+
+  // The Incremental_binary base file.
+  Sized_incremental_binary<size, big_endian>* ibase_;
+  // The index of the object in the input file list.
+  unsigned int input_file_index_;
+  // The reader for the input file.
+  Input_entry_reader input_reader_;
+  // The entries in the symbol table for the external symbols.
+  Symbols symbols_;
+  // For each input section, the offset of the input section in its
+  // output section.  This is INVALID_ADDRESS if the input section requires a
+  // special mapping.
+  std::vector<Address> section_offsets_;
+  // The offset of the first incremental relocation for this object.
+  unsigned int incr_reloc_offset_;
+  // The number of incremental relocations for this object.
+  unsigned int incr_reloc_count_;
+  // The index of the first incremental relocation for this object in the
+  // updated output file.
+  unsigned int incr_reloc_output_index_;
+  // A copy of the incremental relocations from this object.
+  unsigned char* incr_relocs_;
+};
+
+// An incremental Dynobj.  This class represents a shared object that has
+// not changed since the last incremental link, and whose contents can be
+// used directly from the base file.
+
+template<int size, bool big_endian>
+class Sized_incr_dynobj : public Dynobj
+{
+ public:
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
+  static const Address invalid_address = static_cast<Address>(0) - 1;
+
+  Sized_incr_dynobj(const std::string& name,
+		    Sized_incremental_binary<size, big_endian>* ibase,
+		    unsigned int input_file_index);
+
+ private:
+  typedef Incremental_inputs_reader<size, big_endian> Inputs_reader;
+  typedef typename Inputs_reader::Incremental_input_entry_reader
+      Input_entry_reader;
+
+  // Return TRUE if this is an incremental (unchanged) input file.
+  bool
+  do_is_incremental() const
+  { return true; }
+
+  // Return the last modified time of the file.
+  Timespec
+  do_get_mtime()
+  { return this->input_reader_.get_mtime(); }
+
+  // Read the symbols.
+  void
+  do_read_symbols(Read_symbols_data*);
+
+  // Lay out the input sections.
+  void
+  do_layout(Symbol_table*, Layout*, Read_symbols_data*);
+
+  // Add the symbols to the symbol table.
+  void
+  do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*);
+
+  Archive::Should_include
+  do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*,
+                           std::string* why);
+
+  // Iterate over global symbols, calling a visitor class V for each.
+  void
+  do_for_all_global_symbols(Read_symbols_data* sd,
+			    Library_base::Symbol_visitor_base& v);
+
+  // Iterate over local symbols, calling a visitor class V for each GOT offset
+  // associated with a local symbol.
+  void
+  do_for_all_local_got_entries(Got_offset_list::Visitor& v) const;
+
+  // Get the size of a section.
+  uint64_t
+  do_section_size(unsigned int shndx);
+
+  // Get the name of a section.
+  std::string
+  do_section_name(unsigned int shndx);
+
+  // Return a view of the contents of a section.
+  Object::Location
+  do_section_contents(unsigned int shndx);
+
+  // Return section flags.
+  uint64_t
+  do_section_flags(unsigned int shndx);
 
-  // Index of the current input file entry.
-  int current_input_file_;
+  // Return section entsize.
+  uint64_t
+  do_section_entsize(unsigned int shndx);
+
+  // Return section address.
+  uint64_t
+  do_section_address(unsigned int shndx);
+
+  // Return section type.
+  unsigned int
+  do_section_type(unsigned int shndx);
+
+  // Return the section link field.
+  unsigned int
+  do_section_link(unsigned int shndx);
+
+  // Return the section link field.
+  unsigned int
+  do_section_info(unsigned int shndx);
+
+  // Return the section alignment.
+  uint64_t
+  do_section_addralign(unsigned int shndx);
+
+  // Return the Xindex structure to use.
+  Xindex*
+  do_initialize_xindex();
+
+  // Get symbol counts.
+  void
+  do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const;
+
+  // Get global symbols.
+  const Symbols*
+  do_get_global_symbols() const
+  { return &this->symbols_; }
+
+  // The Incremental_binary base file.
+  Sized_incremental_binary<size, big_endian>* ibase_;
+  // The index of the object in the input file list.
+  unsigned int input_file_index_;
+  // The reader for the input file.
+  Input_entry_reader input_reader_;
+  // The entries in the symbol table for the external symbols.
+  Symbols symbols_;
+};
+
+// Allocate an incremental object of the appropriate size and endianness.
+Object*
+make_sized_incremental_object(
+    Incremental_binary* base,
+    unsigned int input_file_index,
+    Incremental_input_type input_type,
+    const Incremental_binary::Input_reader* input_reader);
+
+// This class represents an Archive library (or --start-lib/--end-lib group)
+// that has not changed since the last incremental link.  Its contents come
+// from the incremental inputs entry in the base file.
+
+class Incremental_library : public Library_base
+{
+ public:
+  Incremental_library(const char* filename, unsigned int input_file_index,
+		      const Incremental_binary::Input_reader* input_reader)
+    : Library_base(NULL), filename_(filename),
+      input_file_index_(input_file_index), input_reader_(input_reader),
+      unused_symbols_(), is_reported_(false)
+  { }
+
+  // Return the input file index.
+  unsigned int
+  input_file_index() const
+  { return this->input_file_index_; }
+
+  // Return the serial number of the input file.
+  unsigned int
+  arg_serial() const
+  { return this->input_reader_->arg_serial(); }
+
+  // Copy the unused symbols from the incremental input info.
+  // We need to do this because we may be overwriting the incremental
+  // input info in the base file before we write the new incremental
+  // info.
+  void
+  copy_unused_symbols();
+
+  // Return FALSE on the first call to indicate that the library needs
+  // to be recorded; return TRUE subsequently.
+  bool
+  is_reported()
+  {
+    bool was_reported = this->is_reported_;
+    is_reported_ = true;
+    return was_reported;
+  }
+
+ private:
+  typedef std::vector<std::string> Symbol_list;
+
+  // The file name.
+  const std::string&
+  do_filename() const
+  { return this->filename_; }
+
+  // Return the modification time of the archive file.
+  Timespec
+  do_get_mtime()
+  { return this->input_reader_->get_mtime(); }
+
+  // Iterator for unused global symbols in the library.
+  void
+  do_for_all_unused_symbols(Symbol_visitor_base& v) const;
+
+  // The name of the library.
+  std::string filename_;
+  // The input file index of this library.
+  unsigned int input_file_index_;
+  // A reader for the incremental input information.
+  const Incremental_binary::Input_reader* input_reader_;
+  // List of unused symbols defined in this library.
+  Symbol_list unused_symbols_;
+  // TRUE when this library has been reported to the new incremental info.
+  bool is_reported_;
 };
 
 } // End namespace gold.
diff --git a/gold/layout.cc b/gold/layout.cc
index 63b9e0d..26ac130 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -55,6 +55,168 @@
 namespace gold
 {
 
+// Class Free_list.
+
+// The total number of free lists used.
+unsigned int Free_list::num_lists = 0;
+// The total number of free list nodes used.
+unsigned int Free_list::num_nodes = 0;
+// The total number of calls to Free_list::remove.
+unsigned int Free_list::num_removes = 0;
+// The total number of nodes visited during calls to Free_list::remove.
+unsigned int Free_list::num_remove_visits = 0;
+// The total number of calls to Free_list::allocate.
+unsigned int Free_list::num_allocates = 0;
+// The total number of nodes visited during calls to Free_list::allocate.
+unsigned int Free_list::num_allocate_visits = 0;
+
+// Initialize the free list.  Creates a single free list node that
+// describes the entire region of length LEN.  If EXTEND is true,
+// allocate() is allowed to extend the region beyond its initial
+// length.
+
+void
+Free_list::init(off_t len, bool extend)
+{
+  this->list_.push_front(Free_list_node(0, len));
+  this->last_remove_ = this->list_.begin();
+  this->extend_ = extend;
+  this->length_ = len;
+  ++Free_list::num_lists;
+  ++Free_list::num_nodes;
+}
+
+// Remove a chunk from the free list.  Because we start with a single
+// node that covers the entire section, and remove chunks from it one
+// at a time, we do not need to coalesce chunks or handle cases that
+// span more than one free node.  We expect to remove chunks from the
+// free list in order, and we expect to have only a few chunks of free
+// space left (corresponding to files that have changed since the last
+// incremental link), so a simple linear list should provide sufficient
+// performance.
+
+void
+Free_list::remove(off_t start, off_t end)
+{
+  if (start == end)
+    return;
+  gold_assert(start < end);
+
+  ++Free_list::num_removes;
+
+  Iterator p = this->last_remove_;
+  if (p->start_ > start)
+    p = this->list_.begin();
+
+  for (; p != this->list_.end(); ++p)
+    {
+      ++Free_list::num_remove_visits;
+      // Find a node that wholly contains the indicated region.
+      if (p->start_ <= start && p->end_ >= end)
+	{
+	  // Case 1: the indicated region spans the whole node.
+	  // Add some fuzz to avoid creating tiny free chunks.
+	  if (p->start_ + 3 >= start && p->end_ <= end + 3)
+	    p = this->list_.erase(p);
+	  // Case 2: remove a chunk from the start of the node.
+	  else if (p->start_ + 3 >= start)
+	    p->start_ = end;
+	  // Case 3: remove a chunk from the end of the node.
+	  else if (p->end_ <= end + 3)
+	    p->end_ = start;
+	  // Case 4: remove a chunk from the middle, and split
+	  // the node into two.
+	  else
+	    {
+	      Free_list_node newnode(p->start_, start);
+	      p->start_ = end;
+	      this->list_.insert(p, newnode);
+	      ++Free_list::num_nodes;
+	    }
+	  this->last_remove_ = p;
+	  return;
+	}
+    }
+
+  // Did not find a node containing the given chunk.  This could happen
+  // because a small chunk was already removed due to the fuzz.
+  gold_debug(DEBUG_INCREMENTAL,
+	     "Free_list::remove(%d,%d) not found",
+	     static_cast<int>(start), static_cast<int>(end));
+}
+
+// Allocate a chunk of size LEN from the free list.  Returns -1ULL
+// if a sufficiently large chunk of free space is not found.
+// We use a simple first-fit algorithm.
+
+off_t
+Free_list::allocate(off_t len, uint64_t align, off_t minoff)
+{
+  gold_debug(DEBUG_INCREMENTAL,
+  	     "Free_list::allocate(%08lx, %d, %08lx)",
+  	     static_cast<long>(len), static_cast<int>(align),
+  	     static_cast<long>(minoff));
+  if (len == 0)
+    return align_address(minoff, align);
+
+  ++Free_list::num_allocates;
+
+  for (Iterator p = this->list_.begin(); p != this->list_.end(); ++p)
+    {
+      ++Free_list::num_allocate_visits;
+      off_t start = p->start_ > minoff ? p->start_ : minoff;
+      start = align_address(start, align);
+      off_t end = start + len;
+      if (end <= p->end_)
+	{
+	  if (p->start_ + 3 >= start && p->end_ <= end + 3)
+	    this->list_.erase(p);
+	  else if (p->start_ + 3 >= start)
+	    p->start_ = end;
+	  else if (p->end_ <= end + 3)
+	    p->end_ = start;
+	  else
+	    {
+	      Free_list_node newnode(p->start_, start);
+	      p->start_ = end;
+	      this->list_.insert(p, newnode);
+	      ++Free_list::num_nodes;
+	    }
+	  return start;
+	}
+    }
+  return -1;
+}
+
+// Dump the free list (for debugging).
+void
+Free_list::dump()
+{
+  gold_info("Free list:\n     start      end   length\n");
+  for (Iterator p = this->list_.begin(); p != this->list_.end(); ++p)
+    gold_info("  %08lx %08lx %08lx", static_cast<long>(p->start_),
+	      static_cast<long>(p->end_),
+	      static_cast<long>(p->end_ - p->start_));
+}
+
+// Print the statistics for the free lists.
+void
+Free_list::print_stats()
+{
+  fprintf(stderr, _("%s: total free lists: %u\n"),
+          program_name, Free_list::num_lists);
+  fprintf(stderr, _("%s: total free list nodes: %u\n"),
+          program_name, Free_list::num_nodes);
+  fprintf(stderr, _("%s: calls to Free_list::remove: %u\n"),
+          program_name, Free_list::num_removes);
+  fprintf(stderr, _("%s: nodes visited: %u\n"),
+          program_name, Free_list::num_remove_visits);
+  fprintf(stderr, _("%s: calls to Free_list::allocate: %u\n"),
+          program_name, Free_list::num_allocates);
+  fprintf(stderr, _("%s: nodes visited: %u\n"),
+          program_name, Free_list::num_allocate_visits);
+}
+
 // Layout::Relaxation_debug_check methods.
 
 // Check that sections and special data are in reset states.
@@ -150,10 +312,19 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task)
       this->layout_->print_to_mapfile(this->mapfile_);
     }
 
-  Output_file* of = new Output_file(parameters->options().output_file_name());
-  if (this->options_.oformat_enum() != General_options::OBJECT_FORMAT_ELF)
-    of->set_is_temporary();
-  of->open(file_size);
+  Output_file* of;
+  if (this->layout_->incremental_base() == NULL)
+    {
+      of = new Output_file(parameters->options().output_file_name());
+      if (this->options_.oformat_enum() != General_options::OBJECT_FORMAT_ELF)
+	of->set_is_temporary();
+      of->open(file_size);
+    }
+  else
+    {
+      of = this->layout_->incremental_base()->output_file();
+      of->resize(file_size);
+    }
 
   // Queue up the final set of tasks.
   gold::queue_final_tasks(this->options_, this->input_objects_,
@@ -207,7 +378,9 @@ Layout::Layout(int number_of_input_files, Script_options* script_options)
     record_output_section_data_from_script_(false),
     script_output_section_data_list_(),
     segment_states_(NULL),
-    relaxation_debug_check_(NULL)
+    relaxation_debug_check_(NULL),
+    incremental_base_(NULL),
+    free_list_()
 {
   // Make space for more than enough segments for a typical file.
   // This is just for efficiency--it's OK if we wind up needing more.
@@ -226,6 +399,15 @@ Layout::Layout(int number_of_input_files, Script_options* script_options)
   this->namepool_.set_optimize();
 }
 
+// For incremental links, record the base file to be modified.
+
+void
+Layout::set_incremental_base(Incremental_binary* base)
+{
+  this->incremental_base_ = base;
+  this->free_list_.init(base->output_file()->filesize(), true);
+}
+
 // Hash a key we use to look up an output section mapping.
 
 size_t
@@ -639,6 +821,41 @@ Layout::choose_output_section(const Relobj* relobj, const char* name,
   return this->get_output_section(name, name_key, type, flags, order, is_relro);
 }
 
+// For incremental links, record the initial fixed layout of a section
+// from the base file, and return a pointer to the Output_section.
+
+template<int size, bool big_endian>
+Output_section*
+Layout::init_fixed_output_section(const char* name,
+				  elfcpp::Shdr<size, big_endian>& shdr)
+{
+  unsigned int sh_type = shdr.get_sh_type();
+
+  // We preserve the layout of PROGBITS, NOBITS, and NOTE sections.
+  // All others will be created from scratch and reallocated.
+  if (sh_type != elfcpp::SHT_PROGBITS
+      && sh_type != elfcpp::SHT_NOBITS
+      && sh_type != elfcpp::SHT_NOTE)
+    return NULL;
+
+  typename elfcpp::Elf_types<size>::Elf_Addr sh_addr = shdr.get_sh_addr();
+  typename elfcpp::Elf_types<size>::Elf_Off sh_offset = shdr.get_sh_offset();
+  typename elfcpp::Elf_types<size>::Elf_WXword sh_size = shdr.get_sh_size();
+  typename elfcpp::Elf_types<size>::Elf_WXword sh_flags = shdr.get_sh_flags();
+  typename elfcpp::Elf_types<size>::Elf_WXword sh_addralign =
+      shdr.get_sh_addralign();
+
+  // Make the output section.
+  Stringpool::Key name_key;
+  name = this->namepool_.add(name, true, &name_key);
+  Output_section* os = this->get_output_section(name, name_key, sh_type,
+  						sh_flags, ORDER_INVALID, false);
+  os->set_fixed_layout(sh_addr, sh_offset, sh_size, sh_addralign);
+  if (sh_type != elfcpp::SHT_NOBITS)
+    this->free_list_.remove(sh_offset, sh_offset + sh_size);
+  return os;
+}
+
 // Return the output section to use for input section SHNDX, with name
 // NAME, with header HEADER, from object OBJECT.  RELOC_SHNDX is the
 // index of a relocation section which applies to this section, or 0
@@ -869,7 +1086,9 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
       this->eh_frame_section_ = os;
       this->eh_frame_data_ = new Eh_frame();
 
-      if (parameters->options().eh_frame_hdr())
+      // For incremental linking, we do not optimize .eh_frame sections
+      // or create a .eh_frame_hdr section.
+      if (parameters->options().eh_frame_hdr() && !parameters->incremental())
 	{
 	  Output_section* hdr_os =
 	    this->choose_output_section(NULL, ".eh_frame_hdr",
@@ -901,14 +1120,15 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
 
   gold_assert(this->eh_frame_section_ == os);
 
-  if (this->eh_frame_data_->add_ehframe_input_section(object,
-						      symbols,
-						      symbols_size,
-						      symbol_names,
-						      symbol_names_size,
-						      shndx,
-						      reloc_shndx,
-						      reloc_type))
+  if (!parameters->incremental()
+      && this->eh_frame_data_->add_ehframe_input_section(object,
+							 symbols,
+							 symbols_size,
+							 symbol_names,
+							 symbol_names_size,
+							 shndx,
+							 reloc_shndx,
+							 reloc_type))
     {
       os->update_flags_for_input_section(shdr.get_sh_flags());
 
@@ -2147,7 +2367,8 @@ Layout::create_note(const char* name, int note_type,
 void
 Layout::create_gold_note()
 {
-  if (parameters->options().relocatable())
+  if (parameters->options().relocatable()
+      || parameters->incremental_update())
     return;
 
   std::string desc = std::string("gold ") + gold::get_version_string();
@@ -2709,7 +2930,10 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
 	  // aligned so that the relro data ends at a page boundary,
 	  // we do not try to realign it.
 
-	  if (!are_addresses_set && !has_relro && aligned_addr != addr)
+	  if (!are_addresses_set
+	      && !has_relro
+	      && aligned_addr != addr
+	      && !parameters->incremental_update())
 	    {
 	      uint64_t first_off = (common_pagesize
 				    - (aligned_addr
@@ -2826,6 +3050,9 @@ Layout::set_relocatable_section_offsets(Output_data* file_header,
 off_t
 Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
 {
+  off_t startoff = off;
+  off_t maxoff = off;
+
   for (Section_list::iterator p = this->unattached_section_list_.begin();
        p != this->unattached_section_list_.end();
        ++p)
@@ -2857,16 +3084,53 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
                    || (*p)->type() != elfcpp::SHT_STRTAB))
         continue;
 
-      off = align_address(off, (*p)->addralign());
-      (*p)->set_file_offset(off);
-      (*p)->finalize_data_size();
+      if (!parameters->incremental_update())
+	{
+	  off = align_address(off, (*p)->addralign());
+	  (*p)->set_file_offset(off);
+	  (*p)->finalize_data_size();
+	}
+      else
+	{
+	  // Incremental update: allocate file space from free list.
+	  (*p)->pre_finalize_data_size();
+	  off_t current_size = (*p)->current_data_size();
+	  off = this->allocate(current_size, (*p)->addralign(), startoff);
+	  if (off == -1)
+	    {
+	      if (is_debugging_enabled(DEBUG_INCREMENTAL))
+	        this->free_list_.dump();
+	      gold_assert((*p)->output_section() != NULL);
+	      gold_fatal(_("out of patch space for section %s; "
+			   "relink with --incremental-full"),
+			 (*p)->output_section()->name());
+	    }
+	  (*p)->set_file_offset(off);
+	  (*p)->finalize_data_size();
+	  if ((*p)->data_size() > current_size)
+	    {
+	      gold_assert((*p)->output_section() != NULL);
+	      gold_fatal(_("%s: section changed size; "
+			   "relink with --incremental-full"),
+			 (*p)->output_section()->name());
+	    }
+	  gold_debug(DEBUG_INCREMENTAL,
+		     "set_section_offsets: %08lx %08lx %s",
+		     static_cast<long>(off),
+		     static_cast<long>((*p)->data_size()),
+		     ((*p)->output_section() != NULL
+		      ? (*p)->output_section()->name() : "(special)"));
+	}
+
       off += (*p)->data_size();
+      if (off > maxoff)
+        maxoff = off;
 
       // At this point the name must be set.
       if (pass != STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS)
 	this->namepool_.add((*p)->name(), false, NULL);
     }
-  return off;
+  return maxoff;
 }
 
 // Set the section indexes of all the sections not associated with a
@@ -2980,9 +3244,8 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
   else
     gold_unreachable();
 
-  off_t off = *poff;
-  off = align_address(off, align);
-  off_t startoff = off;
+  // Compute file offsets relative to the start of the symtab section.
+  off_t off = 0;
 
   // Save space for the dummy symbol at the start of the section.  We
   // never bother to write this out--it will just be left as zero.
@@ -3015,7 +3278,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
     }
 
   unsigned int local_symcount = local_symbol_index;
-  gold_assert(static_cast<off_t>(local_symcount * symsize) == off - startoff);
+  gold_assert(static_cast<off_t>(local_symcount * symsize) == off);
 
   off_t dynoff;
   size_t dyn_global_index;
@@ -3036,6 +3299,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
 		  == this->dynsym_section_->data_size() - locsize);
     }
 
+  off_t global_off = off;
   off = symtab->finalize(off, dynoff, dyn_global_index, dyncount,
 			 &this->sympool_, &local_symcount);
 
@@ -3050,8 +3314,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
 							  false);
       this->symtab_section_ = osymtab;
 
-      Output_section_data* pos = new Output_data_fixed_space(off - startoff,
-							     align,
+      Output_section_data* pos = new Output_data_fixed_space(off, align,
 							     "** symtab");
       osymtab->add_output_section_data(pos);
 
@@ -3071,7 +3334,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
 				      elfcpp::SHT_SYMTAB_SHNDX, 0,
 				      ORDER_INVALID, false);
 
-	  size_t symcount = (off - startoff) / symsize;
+	  size_t symcount = off / symsize;
 	  this->symtab_xindex_ = new Output_symtab_xindex(symcount);
 
 	  osymtab_xindex->add_output_section_data(this->symtab_xindex_);
@@ -3097,13 +3360,30 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
       Output_section_data* pstr = new Output_data_strtab(&this->sympool_);
       ostrtab->add_output_section_data(pstr);
 
-      osymtab->set_file_offset(startoff);
+      off_t symtab_off;
+      if (!parameters->incremental_update())
+	symtab_off = align_address(*poff, align);
+      else
+	{
+	  symtab_off = this->allocate(off, align, *poff);
+          if (off == -1)
+	    gold_fatal(_("out of patch space for symbol table; "
+		         "relink with --incremental-full"));
+	  gold_debug(DEBUG_INCREMENTAL,
+		     "create_symtab_sections: %08lx %08lx .symtab",
+		     static_cast<long>(symtab_off),
+		     static_cast<long>(off));
+	}
+
+      symtab->set_file_offset(symtab_off + global_off);
+      osymtab->set_file_offset(symtab_off);
       osymtab->finalize_data_size();
       osymtab->set_link_section(ostrtab);
       osymtab->set_info(local_symcount);
       osymtab->set_entsize(symsize);
 
-      *poff = off;
+      if (symtab_off + off > *poff)
+	*poff = symtab_off + off;
     }
 }
 
@@ -3150,10 +3430,25 @@ Layout::create_shdrs(const Output_section* shstrtab_section, off_t* poff)
 				      &this->unattached_section_list_,
 				      &this->namepool_,
 				      shstrtab_section);
-  off_t off = align_address(*poff, oshdrs->addralign());
+  off_t off;
+  if (!parameters->incremental_update())
+    off = align_address(*poff, oshdrs->addralign());
+  else
+    {
+      oshdrs->pre_finalize_data_size();
+      off = this->allocate(oshdrs->data_size(), oshdrs->addralign(), *poff);
+      if (off == -1)
+	  gold_fatal(_("out of patch space for section header table; "
+		       "relink with --incremental-full"));
+      gold_debug(DEBUG_INCREMENTAL,
+		 "create_shdrs: %08lx %08lx (section header table)",
+		 static_cast<long>(off),
+		 static_cast<long>(off + oshdrs->data_size()));
+    }
   oshdrs->set_address_and_file_offset(0, off);
   off += oshdrs->data_size();
-  *poff = off;
+  if (off > *poff)
+    *poff = off;
   this->section_headers_ = oshdrs;
 }
 
@@ -3667,6 +3962,7 @@ Layout::finish_dynamic_section(const Input_objects* input_objects,
        ++p)
     {
       if (!(*p)->is_needed()
+	  && !(*p)->is_incremental()
 	  && (*p)->input_file()->options().as_needed())
 	{
 	  // This dynamic object was linked with --as-needed, but it
@@ -4424,6 +4720,38 @@ Close_task_runner::run(Workqueue*, const Task*)
 #ifdef HAVE_TARGET_32_LITTLE
 template
 Output_section*
+Layout::init_fixed_output_section<32, false>(
+    const char* name,
+    elfcpp::Shdr<32, false>& shdr);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+Output_section*
+Layout::init_fixed_output_section<32, true>(
+    const char* name,
+    elfcpp::Shdr<32, true>& shdr);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+Output_section*
+Layout::init_fixed_output_section<64, false>(
+    const char* name,
+    elfcpp::Shdr<64, false>& shdr);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+Output_section*
+Layout::init_fixed_output_section<64, true>(
+    const char* name,
+    elfcpp::Shdr<64, true>& shdr);
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+Output_section*
 Layout::layout<32, false>(Sized_relobj<32, false>* object, unsigned int shndx,
 			  const char* name,
 			  const elfcpp::Shdr<32, false>& shdr,
diff --git a/gold/layout.h b/gold/layout.h
index ba5fa66..917856e 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -41,6 +41,7 @@ namespace gold
 
 class General_options;
 class Incremental_inputs;
+class Incremental_binary;
 class Input_objects;
 class Mapfile;
 class Symbol_table;
@@ -64,6 +65,69 @@ struct Timespec;
 extern bool
 is_compressed_debug_section(const char* secname);
 
+// Maintain a list of free space within a section, segment, or file.
+// Used for incremental update links.
+
+class Free_list
+{
+ public:
+  Free_list()
+    : list_(), last_remove_(list_.begin()), extend_(false), length_(0)
+  { }
+
+  void
+  init(off_t len, bool extend);
+
+  void
+  remove(off_t start, off_t end);
+
+  off_t
+  allocate(off_t len, uint64_t align, off_t minoff);
+
+  void
+  dump();
+
+  static void
+  print_stats();
+
+ private:
+  struct Free_list_node
+  {
+    Free_list_node(off_t start, off_t end)
+      : start_(start), end_(end)
+    { }
+    off_t start_;
+    off_t end_;
+  };
+  typedef std::list<Free_list_node>::iterator Iterator;
+
+  // The free list.
+  std::list<Free_list_node> list_;
+
+  // The last node visited during a remove operation.
+  Iterator last_remove_;
+
+  // Whether we can extend past the original length.
+  bool extend_;
+
+  // The total length of the section, segment, or file.
+  off_t length_;
+
+  // Statistics:
+  // The total number of free lists used.
+  static unsigned int num_lists;
+  // The total number of free list nodes used.
+  static unsigned int num_nodes;
+  // The total number of calls to Free_list::remove.
+  static unsigned int num_removes;
+  // The total number of nodes visited during calls to Free_list::remove.
+  static unsigned int num_remove_visits;
+  // The total number of calls to Free_list::allocate.
+  static unsigned int num_allocates;
+  // The total number of nodes visited during calls to Free_list::allocate.
+  static unsigned int num_allocate_visits;
+};
+
 // This task function handles mapping the input sections to output
 // sections and laying them out in memory.
 
@@ -401,6 +465,20 @@ class Layout
     delete this->segment_states_;
   }
 
+  // For incremental links, record the base file to be modified.
+  void
+  set_incremental_base(Incremental_binary* base);
+
+  Incremental_binary*
+  incremental_base()
+  { return this->incremental_base_; }
+
+  // For incremental links, record the initial fixed layout of a section
+  // from the base file, and return a pointer to the Output_section.
+  template<int size, bool big_endian>
+  Output_section*
+  init_fixed_output_section(const char*, elfcpp::Shdr<size, big_endian>&);
+
   // Given an input section SHNDX, named NAME, with data in SHDR, from
   // the object file OBJECT, return the output section where this
   // input section should go.  RELOC_SHNDX is the index of a
@@ -414,6 +492,12 @@ class Layout
 	 const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
 	 unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset);
 
+  // For incremental updates, allocate a block of memory from the
+  // free list.  Find a block starting at or after MINOFF.
+  off_t
+  allocate(off_t len, uint64_t align, off_t minoff)
+  { return this->free_list_.allocate(len, align, minoff); }
+
   unsigned int
   find_section_order_index(const std::string&);
 
@@ -1151,6 +1235,10 @@ class Layout
   Unordered_map<std::string, unsigned int> input_section_position_;
   // Vector of glob only patterns in the section_ordering file.
   std::vector<std::string> input_section_glob_;
+  // For incremental links, the base file to be modified.
+  Incremental_binary* incremental_base_;
+  // For incremental links, a list of free space within the file.
+  Free_list free_list_;
 };
 
 // This task handles writing out data in output sections which is not
diff --git a/gold/main.cc b/gold/main.cc
index 4e3295d..7ca0d70 100644
--- a/gold/main.cc
+++ b/gold/main.cc
@@ -269,6 +269,7 @@ main(int argc, char** argv)
 	      program_name, static_cast<long long>(layout.output_file_size()));
       symtab.print_stats();
       layout.print_stats();
+      Free_list::print_stats();
     }
 
   // Issue defined symbol report.
diff --git a/gold/object.cc b/gold/object.cc
index 954961a..256b556 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -349,11 +349,11 @@ Relobj::is_section_name_included(const char* name)
 
 // Finalize the incremental relocation information.  Allocates a block
 // of relocation entries for each symbol, and sets the reloc_bases_
-// array to point to the first entry in each block.  Returns the next
-// available relocation index.
+// array to point to the first entry in each block.  If CLEAR_COUNTS
+// is TRUE, also clear the per-symbol relocation counters.
 
 void
-Relobj::finalize_incremental_relocs(Layout* layout)
+Relobj::finalize_incremental_relocs(Layout* layout, bool clear_counts)
 {
   unsigned int nsyms = this->get_global_symbols()->size();
   this->reloc_bases_ = new unsigned int[nsyms];
@@ -366,7 +366,8 @@ Relobj::finalize_incremental_relocs(Layout* layout)
     {
       this->reloc_bases_[i] = rindex;
       rindex += this->reloc_counts_[i];
-      this->reloc_counts_[i] = 0;
+      if (clear_counts)
+	this->reloc_counts_[i] = 0;
     }
   layout->incremental_inputs()->set_reloc_count(rindex);
 }
@@ -379,7 +380,7 @@ Sized_relobj<size, big_endian>::Sized_relobj(
     Input_file* input_file,
     off_t offset,
     const elfcpp::Ehdr<size, big_endian>& ehdr)
-  : Relobj(name, input_file, offset),
+  : Sized_relobj_base<size, big_endian>(name, input_file, offset),
     elf_file_(this, ehdr),
     symtab_shndx_(-1U),
     local_symbol_count_(0),
@@ -1265,9 +1266,12 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
 
 	  // Add the section to the incremental inputs layout.
 	  Incremental_inputs* incremental_inputs = layout->incremental_inputs();
-	  if (incremental_inputs != NULL)
-	    incremental_inputs->report_input_section(this, i,
-						     discard ? NULL : name,
+	  if (incremental_inputs != NULL
+	      && !discard
+	      && (shdr.get_sh_type() == elfcpp::SHT_PROGBITS
+	          || shdr.get_sh_type() == elfcpp::SHT_NOBITS
+	          || shdr.get_sh_type() == elfcpp::SHT_NOTE))
+	    incremental_inputs->report_input_section(this, i, name,
 						     shdr.get_sh_size());
 
           if (discard)
@@ -1281,7 +1285,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
  
       if (is_gc_pass_one && parameters->options().gc_sections())
         {
-          if (is_section_name_included(name)
+          if (this->is_section_name_included(name)
               || shdr.get_sh_type() == elfcpp::SHT_INIT_ARRAY 
               || shdr.get_sh_type() == elfcpp::SHT_FINI_ARRAY)
             {
@@ -1716,6 +1720,26 @@ Sized_relobj<size, big_endian>::do_for_all_global_symbols(
     }
 }
 
+// Iterate over local symbols, calling a visitor class V for each GOT offset
+// associated with a local symbol.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::do_for_all_local_got_entries(
+    Got_offset_list::Visitor& v) const
+{
+  unsigned int nsyms = this->local_symbol_count();
+  for (unsigned int i = 0; i < nsyms; i++)
+    {
+      Local_got_offsets::const_iterator p = this->local_got_offsets_.find(i);
+      if (p != this->local_got_offsets_.end())
+	{
+	  const Got_offset_list* got_offsets = p->second;
+	  got_offsets->for_all_got_offsets(v);
+	}
+    }
+}
+
 // Return whether the local symbol SYMNDX has a PLT offset.
 
 template<int size, bool big_endian>
@@ -2199,7 +2223,8 @@ Sized_relobj<size, big_endian>::write_local_symbols(
     const Stringpool* sympool,
     const Stringpool* dynpool,
     Output_symtab_xindex* symtab_xindex,
-    Output_symtab_xindex* dynsym_xindex)
+    Output_symtab_xindex* dynsym_xindex,
+    off_t symtab_off)
 {
   const bool strip_all = parameters->options().strip_all();
   if (strip_all)
@@ -2244,7 +2269,8 @@ Sized_relobj<size, big_endian>::write_local_symbols(
   off_t output_size = this->output_local_symbol_count_ * sym_size;
   unsigned char* oview = NULL;
   if (output_size > 0)
-    oview = of->get_output_view(this->local_symbol_offset_, output_size);
+    oview = of->get_output_view(symtab_off + this->local_symbol_offset_,
+				output_size);
 
   off_t dyn_output_size = this->output_local_dynsym_count_ * sym_size;
   unsigned char* dyn_oview = NULL;
@@ -2324,7 +2350,8 @@ Sized_relobj<size, big_endian>::write_local_symbols(
   if (output_size > 0)
     {
       gold_assert(ov - oview == output_size);
-      of->write_output_view(this->local_symbol_offset_, output_size, oview);
+      of->write_output_view(symtab_off + this->local_symbol_offset_,
+			    output_size, oview);
     }
 
   if (dyn_output_size > 0)
@@ -2450,7 +2477,7 @@ Sized_relobj<size, big_endian>::do_get_global_symbol_counts(
 {
   *defined = this->defined_count_;
   size_t count = 0;
-  for (Symbols::const_iterator p = this->symbols_.begin();
+  for (typename Symbols::const_iterator p = this->symbols_.begin();
        p != this->symbols_.end();
        ++p)
     if (*p != NULL
diff --git a/gold/object.h b/gold/object.h
index f48e664..f76f8ce 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -203,6 +203,117 @@ class Xindex
   Symtab_xindex symtab_xindex_;
 };
 
+// A GOT offset list.  A symbol may have more than one GOT offset
+// (e.g., when mixing modules compiled with two different TLS models),
+// but will usually have at most one.  GOT_TYPE identifies the type of
+// GOT entry; its values are specific to each target.
+
+class Got_offset_list
+{
+ public:
+  Got_offset_list()
+    : got_type_(-1U), got_offset_(0), got_next_(NULL)
+  { }
+
+  Got_offset_list(unsigned int got_type, unsigned int got_offset)
+    : got_type_(got_type), got_offset_(got_offset), got_next_(NULL)
+  { }
+
+  ~Got_offset_list()
+  { 
+    if (this->got_next_ != NULL)
+      {
+        delete this->got_next_;
+        this->got_next_ = NULL;
+      }
+  }
+
+  // Initialize the fields to their default values.
+  void
+  init()
+  {
+    this->got_type_ = -1U;
+    this->got_offset_ = 0;
+    this->got_next_ = NULL;
+  }
+
+  // Set the offset for the GOT entry of type GOT_TYPE.
+  void
+  set_offset(unsigned int got_type, unsigned int got_offset)
+  {
+    if (this->got_type_ == -1U)
+      {
+        this->got_type_ = got_type;
+        this->got_offset_ = got_offset;
+      }
+    else
+      {
+        for (Got_offset_list* g = this; g != NULL; g = g->got_next_)
+          {
+            if (g->got_type_ == got_type)
+              {
+                g->got_offset_ = got_offset;
+                return;
+              }
+          }
+        Got_offset_list* g = new Got_offset_list(got_type, got_offset);
+        g->got_next_ = this->got_next_;
+        this->got_next_ = g;
+      }
+  }
+
+  // Return the offset for a GOT entry of type GOT_TYPE.
+  unsigned int
+  get_offset(unsigned int got_type) const
+  {
+    for (const Got_offset_list* g = this; g != NULL; g = g->got_next_)
+      {
+        if (g->got_type_ == got_type)
+          return g->got_offset_;
+      }
+    return -1U;
+  }
+
+  // Return a pointer to the list, or NULL if the list is empty.
+  const Got_offset_list*
+  get_list() const
+  {
+    if (this->got_type_ == -1U)
+      return NULL;
+    return this;
+  }
+
+  // Abstract visitor class for iterating over GOT offsets.
+  class Visitor
+  {
+   public:
+    Visitor()
+    { }
+
+    virtual
+    ~Visitor()
+    { }
+
+    virtual void
+    visit(unsigned int, unsigned int) = 0;
+  };
+
+  // Loop over all GOT offset entries, calling a visitor class V for each.
+  void
+  for_all_got_offsets(Visitor& v) const
+  {
+    if (this->got_type_ == -1U)
+      return;
+    for (const Got_offset_list* g = this; g != NULL; g = g->got_next_)
+      v.visit(g->got_type_, g->got_offset_);
+  }
+
+ private:
+  unsigned int got_type_;
+  unsigned int got_offset_;
+  Got_offset_list* got_next_;
+};
+
 // Object is an abstract base class which represents either a 32-bit
 // or a 64-bit input object.  This can be a regular object file
 // (ET_REL) or a shared object (ET_DYN).
@@ -220,11 +331,21 @@ class Object
 	 off_t offset = 0)
     : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
       is_dynamic_(is_dynamic), is_needed_(false), uses_split_stack_(false),
-      has_no_split_stack_(false), no_export_(false), xindex_(NULL)
-  { input_file->file().add_object(); }
+      has_no_split_stack_(false), no_export_(false),
+      is_in_system_directory_(false), xindex_(NULL)
+  {
+    if (input_file != NULL)
+      {
+	input_file->file().add_object();
+	this->is_in_system_directory_ = input_file->is_in_system_directory();
+      }
+  }
 
   virtual ~Object()
-  { this->input_file_->file().remove_object(); }
+  { 
+    if (this->input_file_ != NULL)
+      this->input_file_->file().remove_object();
+  }
 
   // Return the name of the object as we would report it to the tuser.
   const std::string&
@@ -274,42 +395,71 @@ class Object
   // Get the file.  We pass on const-ness.
   Input_file*
   input_file()
-  { return this->input_file_; }
+  {
+    gold_assert(this->input_file_ != NULL);
+    return this->input_file_;
+  }
 
   const Input_file*
   input_file() const
-  { return this->input_file_; }
+  {
+    gold_assert(this->input_file_ != NULL);
+    return this->input_file_;
+  }
 
   // Lock the underlying file.
   void
   lock(const Task* t)
-  { this->input_file()->file().lock(t); }
+  { 
+    if (this->input_file_ != NULL)
+      this->input_file_->file().lock(t);
+  }
 
   // Unlock the underlying file.
   void
   unlock(const Task* t)
-  { this->input_file()->file().unlock(t); }
+  {
+    if (this->input_file_ != NULL)
+      this->input_file()->file().unlock(t);
+  }
 
   // Return whether the underlying file is locked.
   bool
   is_locked() const
-  { return this->input_file()->file().is_locked(); }
+  { return this->input_file_ != NULL && this->input_file_->file().is_locked(); }
 
   // Return the token, so that the task can be queued.
   Task_token*
   token()
-  { return this->input_file()->file().token(); }
+  { 
+    if (this->input_file_ == NULL)
+      return NULL;
+    return this->input_file()->file().token();
+  }
 
   // Release the underlying file.
   void
   release()
-  { this->input_file_->file().release(); }
+  {
+    if (this->input_file_ != NULL)
+      this->input_file()->file().release();
+  }
 
   // Return whether we should just read symbols from this file.
   bool
   just_symbols() const
   { return this->input_file()->just_symbols(); }
 
+  // Return whether this is an incremental object.
+  bool
+  is_incremental() const
+  { return this->do_is_incremental(); }
+
+  // Return the last modified time of the file.
+  Timespec
+  get_mtime()
+  { return this->do_get_mtime(); }
+
   // Get the number of sections.
   unsigned int
   shnum() const
@@ -428,6 +578,12 @@ class Object
 			 Library_base::Symbol_visitor_base& v)
   { return this->do_for_all_global_symbols(sd, v); }
 
+  // Iterate over local symbols, calling a visitor class V for each GOT offset
+  // associated with a local symbol.
+  void
+  for_all_local_got_entries(Got_offset_list::Visitor& v) const
+  { this->do_for_all_local_got_entries(v); }
+
   // Functions and types for the elfcpp::Elf_file interface.  This
   // permit us to use Object as the File template parameter for
   // elfcpp::Elf_file.
@@ -504,7 +660,10 @@ class Object
   // Stop caching views in the underlying file.
   void
   clear_view_cache_marks()
-  { this->input_file()->file().clear_view_cache_marks(); }
+  {
+    if (this->input_file_ != NULL)
+      this->input_file_->file().clear_view_cache_marks();
+  }
 
   // Get the number of global symbols defined by this object, and the
   // number of the symbols whose final definition came from this
@@ -519,10 +678,15 @@ class Object
   get_global_symbols() const
   { return this->do_get_global_symbols(); }
 
+  // Set flag that this object was found in a system directory.
+  void
+  set_is_in_system_directory()
+  { this->is_in_system_directory_ = true; }
+
   // Return whether this object was found in a system directory.
   bool
   is_in_system_directory() const
-  { return this->input_file()->is_in_system_directory(); }
+  { return this->is_in_system_directory_; }
 
   // Return whether we found this object by searching a directory.
   bool
@@ -561,6 +725,20 @@ class Object
   do_pluginobj()
   { return NULL; }
 
+  // Return TRUE if this is an incremental (unchanged) input file.
+  // We return FALSE by default; the incremental object classes
+  // override this method.
+  virtual bool
+  do_is_incremental() const
+  { return false; }
+
+  // Return the last modified time of the file.  This method may be
+  // overridden for subclasses that don't use an actual file (e.g.,
+  // Incremental objects).
+  virtual Timespec
+  do_get_mtime()
+  { return this->input_file()->file().get_mtime(); }
+
   // Read the symbols--implemented by child class.
   virtual void
   do_read_symbols(Read_symbols_data*) = 0;
@@ -583,6 +761,11 @@ class Object
   do_for_all_global_symbols(Read_symbols_data* sd,
 			    Library_base::Symbol_visitor_base& v) = 0;
 
+  // Iterate over local symbols, calling a visitor class V for each GOT offset
+  // associated with a local symbol.
+  virtual void
+  do_for_all_local_got_entries(Got_offset_list::Visitor& v) const = 0;
+
   // Return the location of the contents of a section.  Implemented by
   // child class.
   virtual Location
@@ -726,6 +909,8 @@ class Object
   // True if exclude this object from automatic symbol export.
   // This is used only for archive objects.
   bool no_export_ : 1;
+  // True if the object was found in a system directory.
+  bool is_in_system_directory_ : 1;
   // Many sections for objects with more than SHN_LORESERVE sections.
   Xindex* xindex_;
 };
@@ -1019,7 +1204,7 @@ class Relobj : public Object
 
   // Finalize the incremental relocation information.
   void
-  finalize_incremental_relocs(Layout* layout);
+  finalize_incremental_relocs(Layout* layout, bool clear_counts);
 
   // Return the index of the next relocation to be written for global symbol
   // SYMNDX.  Only valid after finalize_incremental_relocs() has been called.
@@ -1443,103 +1628,6 @@ class Symbol_value
   } u_;
 };
 
-// A GOT offset list.  A symbol may have more than one GOT offset
-// (e.g., when mixing modules compiled with two different TLS models),
-// but will usually have at most one.  GOT_TYPE identifies the type of
-// GOT entry; its values are specific to each target.
-
-class Got_offset_list
-{
- public:
-  Got_offset_list()
-    : got_type_(-1U), got_offset_(0), got_next_(NULL)
-  { }
-
-  Got_offset_list(unsigned int got_type, unsigned int got_offset)
-    : got_type_(got_type), got_offset_(got_offset), got_next_(NULL)
-  { }
-
-  ~Got_offset_list()
-  { 
-    if (this->got_next_ != NULL)
-      {
-        delete this->got_next_;
-        this->got_next_ = NULL;
-      }
-  }
-
-  // Initialize the fields to their default values.
-  void
-  init()
-  {
-    this->got_type_ = -1U;
-    this->got_offset_ = 0;
-    this->got_next_ = NULL;
-  }
-
-  // Set the offset for the GOT entry of type GOT_TYPE.
-  void
-  set_offset(unsigned int got_type, unsigned int got_offset)
-  {
-    if (this->got_type_ == -1U)
-      {
-        this->got_type_ = got_type;
-        this->got_offset_ = got_offset;
-      }
-    else
-      {
-        for (Got_offset_list* g = this; g != NULL; g = g->got_next_)
-          {
-            if (g->got_type_ == got_type)
-              {
-                g->got_offset_ = got_offset;
-                return;
-              }
-          }
-        Got_offset_list* g = new Got_offset_list(got_type, got_offset);
-        g->got_next_ = this->got_next_;
-        this->got_next_ = g;
-      }
-  }
-
-  // Return the offset for a GOT entry of type GOT_TYPE.
-  unsigned int
-  get_offset(unsigned int got_type) const
-  {
-    for (const Got_offset_list* g = this; g != NULL; g = g->got_next_)
-      {
-        if (g->got_type_ == got_type)
-          return g->got_offset_;
-      }
-    return -1U;
-  }
-
-  // Return a pointer to the list, or NULL if the list is empty.
-  const Got_offset_list*
-  get_list() const
-  {
-    if (this->got_type_ == -1U)
-      return NULL;
-    return this;
-  }
-
-  // Loop over all GOT offset entries, applying the function F to each.
-  template<typename F>
-  void
-  for_all_got_offsets(F f) const
-  {
-    if (this->got_type_ == -1U)
-      return;
-    for (const Got_offset_list* g = this; g != NULL; g = g->got_next_)
-      f(g->got_type_, g->got_offset_);
-  }
-
- private:
-  unsigned int got_type_;
-  unsigned int got_offset_;
-  Got_offset_list* got_next_;
-};
-
 // This type is used to modify relocations for -fsplit-stack.  It is
 // indexed by relocation index, and means that the relocation at that
 // index should use the symbol from the vector, rather than the one
@@ -1568,14 +1656,41 @@ class Reloc_symbol_changes
 
 typedef std::map<unsigned int, section_size_type> Compressed_section_map;
 
+// Abstract base class for a regular object file, either a real object file
+// or an incremental (unchanged) object.  This is size and endian specific.
+
+template<int size, bool big_endian>
+class Sized_relobj_base : public Relobj
+{
+ public:
+  typedef Relobj::Symbols Symbols;
+
+  Sized_relobj_base(const std::string& name, Input_file* input_file)
+    : Relobj(name, input_file)
+  { }
+
+  Sized_relobj_base(const std::string& name, Input_file* input_file,
+		    off_t offset)
+    : Relobj(name, input_file, offset)
+  { }
+
+  ~Sized_relobj_base()
+  { }
+
+ protected:
+  typedef Relobj::Output_sections Output_sections;
+
+ private:
+};
+
 // A regular object file.  This is size and endian specific.
 
 template<int size, bool big_endian>
-class Sized_relobj : public Relobj
+class Sized_relobj : public Sized_relobj_base<size, big_endian>
 {
  public:
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
-  typedef std::vector<Symbol*> Symbols;
+  typedef typename Sized_relobj_base<size, big_endian>::Symbols Symbols;
   typedef std::vector<Symbol_value<size> > Local_values;
 
   static const Address invalid_address = static_cast<Address>(0) - 1;
@@ -1726,17 +1841,6 @@ class Sized_relobj : public Relobj
       }
   }
 
-  // Return the GOT offset list for the local symbol SYMNDX.
-  const Got_offset_list*
-  local_got_offset_list(unsigned int symndx) const
-  {
-    Local_got_offsets::const_iterator p =
-        this->local_got_offsets_.find(symndx);
-    if (p == this->local_got_offsets_.end())
-      return NULL;
-    return p->second;
-  }
-
   // Return whether the local symbol SYMNDX has a PLT offset.
   bool
   local_has_plt_offset(unsigned int symndx) const;
@@ -1791,6 +1895,9 @@ class Sized_relobj : public Relobj
 			    const Symbol_table* symtab);
 
  protected:
+  typedef typename Sized_relobj_base<size, big_endian>::Output_sections
+      Output_sections;
+
   // Set up.
   virtual void
   do_setup();
@@ -1826,6 +1933,11 @@ class Sized_relobj : public Relobj
   do_for_all_global_symbols(Read_symbols_data* sd,
 			    Library_base::Symbol_visitor_base& v);
 
+  // Iterate over local symbols, calling a visitor class V for each GOT offset
+  // associated with a local symbol.
+  void
+  do_for_all_local_got_entries(Got_offset_list::Visitor& v) const;
+
   // Read the relocs.
   void
   do_read_relocs(Read_relocs_data*);
@@ -2179,7 +2291,8 @@ class Sized_relobj : public Relobj
 		      const Stringpool_template<char>*,
 		      const Stringpool_template<char>*,
 		      Output_symtab_xindex*,
-		      Output_symtab_xindex*);
+		      Output_symtab_xindex*,
+		      off_t);
 
   // Record a mapping from discarded section SHNDX to the corresponding
   // kept section.
@@ -2269,9 +2382,9 @@ class Sized_relobj : public Relobj
   Symbols symbols_;
   // Number of symbols defined in object file itself.
   size_t defined_count_;
-  // File offset for local symbols.
+  // File offset for local symbols (relative to start of symbol table).
   off_t local_symbol_offset_;
-  // File offset for local dynamic symbols.
+  // File offset for local dynamic symbols (absolute).
   off_t local_dynsym_offset_;
   // Values of local symbols.
   Local_values local_values_;
diff --git a/gold/options.cc b/gold/options.cc
index 7e86543..3ec76a8 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -1215,8 +1215,9 @@ Search_directory::add_sysroot(const char* sysroot,
 // Add a file to the list.
 
 Input_argument&
-Input_arguments::add_file(const Input_file_argument& file)
+Input_arguments::add_file(Input_file_argument& file)
 {
+  file.set_arg_serial(++this->file_count_);
   if (this->in_group_)
     {
       gold_assert(!this->input_argument_list_.empty());
diff --git a/gold/options.h b/gold/options.h
index 042b8cf..3949690 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -57,6 +57,7 @@ class Input_file_lib;
 class Position_dependent_options;
 class Target;
 class Plugin_manager;
+class Script_info;
 
 // Incremental build action for a specific file, as selected by the user.
 
@@ -1519,7 +1520,7 @@ class Input_file_argument
   //         command line, such as --whole-archive.
   Input_file_argument()
     : name_(), type_(INPUT_FILE_TYPE_FILE), extra_search_path_(""),
-      just_symbols_(false), options_()
+      just_symbols_(false), options_(), arg_serial_(0)
   { }
 
   Input_file_argument(const char* name, Input_file_type type,
@@ -1527,7 +1528,7 @@ class Input_file_argument
                       bool just_symbols,
                       const Position_dependent_options& options)
     : name_(name), type_(type), extra_search_path_(extra_search_path),
-      just_symbols_(just_symbols), options_(options)
+      just_symbols_(just_symbols), options_(options), arg_serial_(0)
   { }
 
   // You can also pass in a General_options instance instead of a
@@ -1539,7 +1540,7 @@ class Input_file_argument
                       bool just_symbols,
                       const General_options& options)
     : name_(name), type_(type), extra_search_path_(extra_search_path),
-      just_symbols_(just_symbols), options_(options)
+      just_symbols_(just_symbols), options_(options), arg_serial_(0)
   { }
 
   const char*
@@ -1581,6 +1582,16 @@ class Input_file_argument
 	    || !this->extra_search_path_.empty());
   }
 
+  // Set the serial number for this argument.
+  void
+  set_arg_serial(unsigned int arg_serial)
+  { this->arg_serial_ = arg_serial; }
+
+  // Get the serial number.
+  unsigned int
+  arg_serial() const
+  { return this->arg_serial_; }
+
  private:
   // We use std::string, not const char*, here for convenience when
   // using script files, so that we do not have to preserve the string
@@ -1590,6 +1601,8 @@ class Input_file_argument
   std::string extra_search_path_;
   bool just_symbols_;
   Position_dependent_options options_;
+  // A unique index for this file argument in the argument list.
+  unsigned int arg_serial_;
 };
 
 // A file or library, or a group, from the command line.
@@ -1772,12 +1785,12 @@ class Input_arguments
   typedef Input_argument_list::const_iterator const_iterator;
 
   Input_arguments()
-    : input_argument_list_(), in_group_(false), in_lib_(false)
+    : input_argument_list_(), in_group_(false), in_lib_(false), file_count_(0)
   { }
 
   // Add a file.
   Input_argument&
-  add_file(const Input_file_argument& arg);
+  add_file(Input_file_argument& arg);
 
   // Start a group (the --start-group option).
   void
@@ -1825,10 +1838,18 @@ class Input_arguments
   empty() const
   { return this->input_argument_list_.empty(); }
 
+  // Return the number of input files.  This may be larger than
+  // input_argument_list_.size(), because of files that are part
+  // of groups or libs.
+  int
+  number_of_input_files() const
+  { return this->file_count_; }
+
  private:
   Input_argument_list input_argument_list_;
   bool in_group_;
   bool in_lib_;
+  unsigned int file_count_;
 };
 
 
@@ -1885,7 +1906,7 @@ class Command_line
   // The number of input files.
   int
   number_of_input_files() const
-  { return this->inputs_.size(); }
+  { return this->inputs_.number_of_input_files(); }
 
   // Iterators to iterate over the list of input files.
 
diff --git a/gold/output.cc b/gold/output.cc
index 739e00e..5c1fae9 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -280,6 +280,7 @@ Output_segment_headers::Output_segment_headers(
     const Layout::Segment_list& segment_list)
   : segment_list_(segment_list)
 {
+  this->set_current_data_size_for_child(this->do_size());
 }
 
 void
@@ -1794,6 +1795,21 @@ Output_symtab_xindex::endian_do_write(unsigned char* const oview)
 
 // Output_section::Input_section methods.
 
+// Return the current data size.  For an input section we store the size here.
+// For an Output_section_data, we have to ask it for the size.
+
+off_t
+Output_section::Input_section::current_data_size() const
+{
+  if (this->is_input_section())
+    return this->u1_.data_size;
+  else
+    {
+      this->u2_.posd->pre_finalize_data_size();
+      return this->u2_.posd->current_data_size();
+    }
+}
+
 // Return the data size.  For an input section we store the size here.
 // For an Output_section_data, we have to ask it for the size.
 
@@ -2003,9 +2019,11 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     section_offsets_need_adjustment_(false),
     is_noload_(false),
     always_keeps_input_sections_(false),
+    has_fixed_layout_(false),
     tls_offset_(0),
     checkpoint_(NULL),
-    lookup_maps_(new Output_section_lookup_maps)
+    lookup_maps_(new Output_section_lookup_maps),
+    free_list_()
 {
   // An unallocated section has no address.  Forcing this means that
   // we don't need special treatment for symbols defined in debug
@@ -2086,9 +2104,11 @@ Output_section::add_input_section(Layout* layout,
   // a Output_data_merge.  We don't try to handle relocations for such
   // a section.  We don't try to handle empty merge sections--they
   // mess up the mappings, and are useless anyhow.
+  // FIXME: Need to handle merge sections during incremental update.
   if ((sh_flags & elfcpp::SHF_MERGE) != 0
       && reloc_shndx == 0
-      && shdr.get_sh_size() > 0)
+      && shdr.get_sh_size() > 0
+      && !parameters->incremental())
     {
       // Keep information about merged input sections for rebuilding fast
       // lookup maps if we have sections-script or we do relaxation.
@@ -2105,9 +2125,30 @@ Output_section::add_input_section(Layout* layout,
 	}
     }
 
-  off_t offset_in_section = this->current_data_size_for_child();
-  off_t aligned_offset_in_section = align_address(offset_in_section,
-                                                  addralign);
+  section_size_type input_section_size = shdr.get_sh_size();
+  section_size_type uncompressed_size;
+  if (object->section_is_compressed(shndx, &uncompressed_size))
+    input_section_size = uncompressed_size;
+
+  off_t offset_in_section;
+  off_t aligned_offset_in_section;
+  if (this->has_fixed_layout())
+    {
+      // For incremental updates, find a chunk of unused space in the section.
+      offset_in_section = this->free_list_.allocate(input_section_size,
+						    addralign, 0);
+      if (offset_in_section == -1)
+        gold_fatal(_("out of patch space; relink with --incremental-full"));
+      aligned_offset_in_section = offset_in_section;
+    }
+  else
+    {
+      offset_in_section = this->current_data_size_for_child();
+      aligned_offset_in_section = align_address(offset_in_section,
+						addralign);
+      this->set_current_data_size_for_child(aligned_offset_in_section
+					    + input_section_size);
+    }
 
   // Determine if we want to delay code-fill generation until the output
   // section is written.  When the target is relaxing, we want to delay fill
@@ -2144,14 +2185,6 @@ Output_section::add_input_section(Layout* layout,
         }
     }
 
-  section_size_type input_section_size = shdr.get_sh_size();
-  section_size_type uncompressed_size;
-  if (object->section_is_compressed(shndx, &uncompressed_size))
-    input_section_size = uncompressed_size;
-
-  this->set_current_data_size_for_child(aligned_offset_in_section
-					+ input_section_size);
-
   // We need to keep track of this section if we are already keeping
   // track of sections, or if we are relaxing.  Also, if this is a
   // section which requires sorting, or which may require sorting in
@@ -2178,6 +2211,14 @@ Output_section::add_input_section(Layout* layout,
               this->set_input_section_order_specified();
             }
         }
+      if (this->has_fixed_layout())
+	{
+	  // For incremental updates, finalize the address and offset now.
+	  uint64_t addr = this->address();
+	  isecn.set_address_and_file_offset(addr + aligned_offset_in_section,
+					    aligned_offset_in_section,
+					    this->offset());
+	}
       this->input_sections_.push_back(isecn);
     }
 
@@ -2194,11 +2235,38 @@ Output_section::add_output_section_data(Output_section_data* posd)
 
   if (posd->is_data_size_valid())
     {
-      off_t offset_in_section = this->current_data_size_for_child();
-      off_t aligned_offset_in_section = align_address(offset_in_section,
-						      posd->addralign());
-      this->set_current_data_size_for_child(aligned_offset_in_section
-					    + posd->data_size());
+      off_t offset_in_section;
+      if (this->has_fixed_layout())
+	{
+	  // For incremental updates, find a chunk of unused space.
+	  offset_in_section = this->free_list_.allocate(posd->data_size(),
+							posd->addralign(), 0);
+	  if (offset_in_section == -1)
+	    gold_fatal(_("out of patch space; relink with --incremental-full"));
+	  // Finalize the address and offset now.
+	  uint64_t addr = this->address();
+	  off_t offset = this->offset();
+	  posd->set_address_and_file_offset(addr + offset_in_section,
+					    offset + offset_in_section);
+	}
+      else
+	{
+	  offset_in_section = this->current_data_size_for_child();
+	  off_t aligned_offset_in_section = align_address(offset_in_section,
+							  posd->addralign());
+	  this->set_current_data_size_for_child(aligned_offset_in_section
+						+ posd->data_size());
+	}
+    }
+  else if (this->has_fixed_layout())
+    {
+      // For incremental updates, arrange for the data to have a fixed layout.
+      // This will mean that additions to the data must be allocated from
+      // free space within the containing output section.
+      uint64_t addr = this->address();
+      posd->set_address(addr);
+      posd->set_file_offset(0);
+      // FIXME: Mark *POSD as part of a fixed-layout section.
     }
 }
 
@@ -2713,6 +2781,30 @@ Output_section::find_starting_output_address(const Relobj* object,
   return false;
 }
 
+// Update the data size of an Output_section.
+
+void
+Output_section::update_data_size()
+{
+  if (this->input_sections_.empty())
+      return;
+
+  if (this->must_sort_attached_input_sections()
+      || this->input_section_order_specified())
+    this->sort_attached_input_sections();
+
+  off_t off = this->first_input_offset_;
+  for (Input_section_list::iterator p = this->input_sections_.begin();
+       p != this->input_sections_.end();
+       ++p)
+    {
+      off = align_address(off, p->addralign());
+      off += p->current_data_size();
+    }
+
+  this->set_current_data_size_for_child(off);
+}
+
 // Set the data size of an Output_section.  This is where we handle
 // setting the addresses of any Output_section_data objects.
 
@@ -3483,6 +3575,30 @@ Output_section::print_merge_stats()
     p->print_merge_stats(this->name_);
 }
 
+// Set a fixed layout for the section.  Used for incremental update links.
+
+void
+Output_section::set_fixed_layout(uint64_t sh_addr, off_t sh_offset,
+				 off_t sh_size, uint64_t sh_addralign)
+{
+  this->addralign_ = sh_addralign;
+  this->set_current_data_size(sh_size);
+  if ((this->flags_ & elfcpp::SHF_ALLOC) != 0)
+    this->set_address(sh_addr);
+  this->set_file_offset(sh_offset);
+  this->finalize_data_size();
+  this->free_list_.init(sh_size, false);
+  this->has_fixed_layout_ = true;
+}
+
+// Reserve space within the fixed layout for the section.  Used for
+// incremental update links.
+void
+Output_section::reserve(uint64_t sh_offset, uint64_t sh_size)
+{
+  this->free_list_.remove(sh_offset, sh_offset + sh_size);
+}
+
 // Output segment methods.
 
 Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
@@ -3692,7 +3808,7 @@ Output_segment::has_dynamic_reloc_list(const Output_data_list* pdl) const
 // and *PSHNDX.
 
 uint64_t
-Output_segment::set_section_addresses(const Layout* layout, bool reset,
+Output_segment::set_section_addresses(Layout* layout, bool reset,
                                       uint64_t addr,
 				      unsigned int* increase_relro,
 				      bool* has_relro,
@@ -3839,13 +3955,16 @@ Output_segment::set_section_addresses(const Layout* layout, bool reset,
 // structures.
 
 uint64_t
-Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
+Output_segment::set_section_list_addresses(Layout* layout, bool reset,
                                            Output_data_list* pdl,
 					   uint64_t addr, off_t* poff,
 					   unsigned int* pshndx,
                                            bool* in_tls)
 {
   off_t startoff = *poff;
+  // For incremental updates, we may allocate non-fixed sections from
+  // free space in the file.  This keeps track of the high-water mark.
+  off_t maxoff = startoff;
 
   off_t off = startoff;
   for (Output_data_list::iterator p = pdl->begin();
@@ -3855,8 +3974,8 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
       if (reset)
 	(*p)->reset_address_and_file_offset();
 
-      // When using a linker script the section will most likely
-      // already have an address.
+      // When doing an incremental update or when using a linker script,
+      // the section will most likely already have an address.
       if (!(*p)->is_address_valid())
 	{
           uint64_t align = (*p)->addralign();
@@ -3894,9 +4013,43 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
                 }
             }
 
-	  off = align_address(off, align);
-	  (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+	  // FIXME: Need to handle TLS and .bss with incremental update.
+	  if (!parameters->incremental_update()
+	      || (*p)->is_section_flag_set(elfcpp::SHF_TLS)
+	      || (*p)->is_section_type(elfcpp::SHT_NOBITS))
+	    {
+	      off = align_address(off, align);
+	      (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+	    }
+	  else
+	    {
+	      // Incremental update: allocate file space from free list.
+	      (*p)->pre_finalize_data_size();
+	      off_t current_size = (*p)->current_data_size();
+	      off = layout->allocate(current_size, align, startoff);
+	      if (off == -1)
+	        {
+		  gold_assert((*p)->output_section() != NULL);
+		  gold_fatal(_("out of patch space for section %s; "
+			       "relink with --incremental-full"),
+			     (*p)->output_section()->name());
+	        }
+	      (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+	      if ((*p)->data_size() > current_size)
+		{
+		  gold_assert((*p)->output_section() != NULL);
+		  gold_fatal(_("%s: section changed size; "
+			       "relink with --incremental-full"),
+			     (*p)->output_section()->name());
+		}
+	    }
 	}
+      else if (parameters->incremental_update())
+        {
+          // For incremental updates, use the fixed offset for the
+          // high-water mark computation.
+          off = (*p)->offset();
+        }
       else
 	{
 	  // The script may have inserted a skip forward, but it
@@ -3930,6 +4083,13 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
 	  (*p)->finalize_data_size();
 	}
 
+      gold_debug(DEBUG_INCREMENTAL,
+		 "set_section_list_addresses: %08lx %08lx %s",
+		 static_cast<long>(off),
+		 static_cast<long>((*p)->data_size()),
+		 ((*p)->output_section() != NULL
+		  ? (*p)->output_section()->name() : "(special)"));
+
       // We want to ignore the size of a SHF_TLS or SHT_NOBITS
       // section.  Such a section does not affect the size of a
       // PT_LOAD segment.
@@ -3937,6 +4097,9 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
 	  || !(*p)->is_section_type(elfcpp::SHT_NOBITS))
 	off += (*p)->data_size();
 
+      if (off > maxoff)
+        maxoff = off;
+
       if ((*p)->is_section())
 	{
 	  (*p)->set_out_shndx(*pshndx);
@@ -3944,8 +4107,8 @@ Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
 	}
     }
 
-  *poff = off;
-  return addr + (off - startoff);
+  *poff = maxoff;
+  return addr + (maxoff - startoff);
 }
 
 // For a non-PT_LOAD segment, set the offset from the sections, if
@@ -4029,7 +4192,15 @@ Output_segment::set_offset(unsigned int increase)
     {
       uint64_t page_align = parameters->target().common_pagesize();
       uint64_t segment_end = this->vaddr_ + this->memsz_;
-      gold_assert(segment_end == align_address(segment_end, page_align));
+      if (parameters->incremental_update())
+	{
+	  // The INCREASE_RELRO calculation is bypassed for an incremental
+	  // update, so we need to adjust the segment size manually here.
+	  segment_end = align_address(segment_end, page_align);
+	  this->memsz_ = segment_end - this->vaddr_;
+	}
+      else
+	gold_assert(segment_end == align_address(segment_end, page_align));
     }
 
   // If this is a TLS segment, align the memory size.  The code in
diff --git a/gold/output.h b/gold/output.h
index 0d88294..d62ae73 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -81,6 +81,11 @@ class Output_data
     return this->data_size_;
   }
 
+  // Get the current data size.
+  off_t
+  current_data_size() const
+  { return this->current_data_size_for_child(); }
+
   // Return true if data size is fixed.
   bool
   is_data_size_fixed() const
@@ -193,6 +198,17 @@ class Output_data
     this->is_offset_valid_ = true;
   }
 
+  // Update the data size without finalizing it.
+  void
+  pre_finalize_data_size()
+  {
+    if (!this->is_data_size_valid_)
+      {
+	// Tell the child class to update the data size.
+	this->update_data_size();
+      }
+  }
+
   // Finalize the data size.
   void
   finalize_data_size()
@@ -320,6 +336,17 @@ class Output_data
   do_set_out_shndx(unsigned int)
   { gold_unreachable(); }
 
+  // This is a hook for derived classes to set the preliminary data size.
+  // This is called by pre_finalize_data_size, normally called during
+  // Layout::finalize, before the section address is set, and is used
+  // during an incremental update, when we need to know the size of a
+  // section before allocating space in the output file.  For classes
+  // where the current data size is up to date, this default version of
+  // the method can be inherited.
+  virtual void
+  update_data_size()
+  { }
+
   // This is a hook for derived classes to set the data size.  This is
   // called by finalize_data_size, normally called during
   // Layout::finalize, when the section address is set.
@@ -462,6 +489,11 @@ class Output_section_headers : public Output_data
   do_print_to_mapfile(Mapfile* mapfile) const
   { mapfile->print_output_data(this, _("** section headers")); }
 
+  // Update the data size.
+  void
+  update_data_size()
+  { this->set_data_size(this->do_size()); }
+
   // Set final data size.
   void
   set_final_data_size()
@@ -732,11 +764,6 @@ class Output_section_data_build : public Output_section_data
     : Output_section_data(addralign)
   { }
 
-  // Get the current data size.
-  off_t
-  current_data_size() const
-  { return this->current_data_size_for_child(); }
-
   // Set the current data size.
   void
   set_current_data_size(off_t data_size)
@@ -918,6 +945,12 @@ class Output_data_strtab : public Output_section_data
   { }
 
  protected:
+  // This is called to update the section size prior to assigning
+  // the address and file offset.
+  void
+  update_data_size()
+  { this->set_final_data_size(); }
+
   // This is called to set the address and file offset.  Here we make
   // sure that the Stringpool is finalized.
   void
@@ -3035,6 +3068,10 @@ class Output_section : public Output_data
 	}
     }
  
+    // Return the current required size, without finalization.
+    off_t
+    current_data_size() const;
+
     // Return the required size.
     off_t
     data_size() const;
@@ -3258,11 +3295,6 @@ class Output_section : public Output_data
   set_current_data_size(off_t size)
   { this->set_current_data_size_for_child(size); }
 
-  // Get the current size of the output section.
-  off_t
-  current_data_size() const
-  { return this->current_data_size_for_child(); }
-
   // End of linker script support.
 
   // Save states before doing section layout.
@@ -3317,6 +3349,21 @@ class Output_section : public Output_data
   void
   print_merge_stats();
 
+  // Set a fixed layout for the section.  Used for incremental update links.
+  void
+  set_fixed_layout(uint64_t sh_addr, off_t sh_offset, off_t sh_size,
+		   uint64_t sh_addralign);
+
+  // Return TRUE if the section has a fixed layout.
+  bool
+  has_fixed_layout() const
+  { return this->has_fixed_layout_; }
+
+  // Reserve space within the fixed layout for the section.  Used for
+  // incremental update links.
+  void
+  reserve(uint64_t sh_offset, uint64_t sh_size);
+
  protected:
   // Return the output section--i.e., the object itself.
   Output_section*
@@ -3343,6 +3390,13 @@ class Output_section : public Output_data
     this->out_shndx_ = shndx;
   }
 
+  // Update the data size of the Output_section.  For a typical
+  // Output_section, there is nothing to do, but if there are any
+  // Output_section_data objects we need to do a trial layout
+  // here.
+  virtual void
+  update_data_size();
+
   // Set the final data size of the Output_section.  For a typical
   // Output_section, there is nothing to do, but if there are any
   // Output_section_data objects we need to set their final addresses
@@ -3761,6 +3815,8 @@ class Output_section : public Output_data
   bool is_noload_ : 1;
   // Whether this always keeps input section.
   bool always_keeps_input_sections_ : 1;
+  // Whether this section has a fixed layout, for incremental update links.
+  bool has_fixed_layout_ : 1;
   // For SHT_TLS sections, the offset of this section relative to the base
   // of the TLS segment.
   uint64_t tls_offset_;
@@ -3768,6 +3824,9 @@ class Output_section : public Output_data
   Checkpoint_output_section* checkpoint_;
   // Fast lookup maps for merged and relaxed input sections.
   Output_section_lookup_maps* lookup_maps_;
+  // List of available regions within the section, for incremental
+  // update links.
+  Free_list free_list_;
 };
 
 // An output segment.  PT_LOAD segments are built from collections of
@@ -3910,7 +3969,7 @@ class Output_segment
   // address of the immediately following segment.  Update *POFF and
   // *PSHNDX.  This should only be called for a PT_LOAD segment.
   uint64_t
-  set_section_addresses(const Layout*, bool reset, uint64_t addr,
+  set_section_addresses(Layout*, bool reset, uint64_t addr,
 			unsigned int* increase_relro, bool* has_relro,
 			off_t* poff, unsigned int* pshndx);
 
@@ -3970,7 +4029,7 @@ class Output_segment
 
   // Set the section addresses in an Output_data_list.
   uint64_t
-  set_section_list_addresses(const Layout*, bool reset, Output_data_list*,
+  set_section_list_addresses(Layout*, bool reset, Output_data_list*,
                              uint64_t addr, off_t* poff, unsigned int* pshndx,
                              bool* in_tls);
 
diff --git a/gold/plugin.cc b/gold/plugin.cc
index 0cd76cb..f176b14 100644
--- a/gold/plugin.cc
+++ b/gold/plugin.cc
@@ -1001,6 +1001,16 @@ Sized_pluginobj<size, big_endian>::do_for_all_global_symbols(
     }
 }
 
+// Iterate over local symbols, calling a visitor class V for each GOT offset
+// associated with a local symbol.
+template<int size, bool big_endian>
+void
+Sized_pluginobj<size, big_endian>::do_for_all_local_got_entries(
+    Got_offset_list::Visitor&) const
+{
+  gold_unreachable();
+}
+
 // Get the size of a section.  Not used for plugin objects.
 
 template<int size, bool big_endian>
diff --git a/gold/plugin.h b/gold/plugin.h
index b9a0718..5ddda91 100644
--- a/gold/plugin.h
+++ b/gold/plugin.h
@@ -454,6 +454,11 @@ class Sized_pluginobj : public Pluginobj
   do_for_all_global_symbols(Read_symbols_data* sd,
 			    Library_base::Symbol_visitor_base& v);
 
+  // Iterate over local symbols, calling a visitor class V for each GOT offset
+  // associated with a local symbol.
+  void
+  do_for_all_local_got_entries(Got_offset_list::Visitor& v) const;
+
   // Get the size of a section.
   uint64_t
   do_section_size(unsigned int shndx);
diff --git a/gold/readsyms.cc b/gold/readsyms.cc
index a6c0454..05b42cd 100644
--- a/gold/readsyms.cc
+++ b/gold/readsyms.cc
@@ -347,6 +347,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
 						this->mapfile_,
 						this->input_argument_,
                                                 obj,
+                                                NULL,
 						NULL,
                                                 this->this_blocker_,
                                                 this->next_blocker_));
@@ -397,6 +398,8 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
         {
           this->member_->sd_ = sd;
           this->member_->obj_ = obj;
+          this->member_->arg_serial_ =
+              this->input_argument_->file().arg_serial();
           return true;
         }
 
@@ -410,6 +413,7 @@ Read_symbols::do_read_symbols(Workqueue* workqueue)
 					    this->mapfile_,
 					    this->input_argument_,
 					    obj,
+					    NULL,
 					    sd,
 					    this->this_blocker_,
 					    this->next_blocker_));
@@ -563,7 +567,9 @@ void
 Add_symbols::locks(Task_locker* tl)
 {
   tl->add(this, this->next_blocker_);
-  tl->add(this, this->object_->token());
+  Task_token* token = this->object_->token();
+  if (token != NULL)
+    tl->add(this, token);
 }
 
 // Add the symbols in the object to the symbol table.
@@ -580,6 +586,7 @@ Add_symbols::run(Workqueue*)
 
   if (!this->input_objects_->add_object(this->object_))
     {
+      gold_assert(this->sd_ != NULL);
       delete this->sd_;
       this->sd_ = NULL;
       this->object_->release();
@@ -590,8 +597,23 @@ Add_symbols::run(Workqueue*)
       Incremental_inputs* incremental_inputs =
           this->layout_->incremental_inputs();
       if (incremental_inputs != NULL)
-	incremental_inputs->report_object(this->object_, NULL,
-					  this->input_argument_->script_info());
+	{
+          if (this->library_ != NULL && !this->library_->is_reported())
+            {
+              Incremental_binary* ibase = this->layout_->incremental_base();
+              gold_assert(ibase != NULL);
+              unsigned int lib_serial = this->library_->arg_serial();
+              unsigned int lib_index = this->library_->input_file_index();
+	      Script_info* lib_script_info = ibase->get_script_info(lib_index);
+	      incremental_inputs->report_archive_begin(this->library_,
+						       lib_serial,
+						       lib_script_info);
+	    }
+	  unsigned int arg_serial = this->input_argument_->file().arg_serial();
+	  Script_info* script_info = this->input_argument_->script_info();
+	  incremental_inputs->report_object(this->object_, arg_serial,
+					    this->library_, script_info);
+	}
       this->object_->layout(this->symtab_, this->layout_, this->sd_);
       this->object_->add_symbols(this->symtab_, this->sd_, this->layout_);
       delete this->sd_;
@@ -600,6 +622,127 @@ Add_symbols::run(Workqueue*)
     }
 }
 
+// Class Read_member.
+
+Read_member::~Read_member()
+{
+  if (this->this_blocker_ != NULL)
+    delete this->this_blocker_;
+  // next_blocker_ is deleted by the task associated with the next
+  // input file.
+}
+
+// Return whether a Read_member task is runnable.
+
+Task_token*
+Read_member::is_runnable()
+{
+  return NULL;
+}
+
+void
+Read_member::locks(Task_locker* tl)
+{
+  tl->add(this, this->next_blocker_);
+}
+
+// Run a Read_member task.
+
+void
+Read_member::run(Workqueue*)
+{
+  // This task doesn't need to do anything for now.  The Read_symbols task
+  // that is queued for the archive library will cause the archive to be
+  // processed from scratch.
+}
+
+// Class Check_script.
+
+Check_script::~Check_script()
+{
+  if (this->this_blocker_ != NULL)
+    delete this->this_blocker_;
+  // next_blocker_ is deleted by the task associated with the next
+  // input file.
+}
+
+// Return whether a Check_script task is runnable.
+
+Task_token*
+Check_script::is_runnable()
+{
+  if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+    return this->this_blocker_;
+  return NULL;
+}
+
+void
+Check_script::locks(Task_locker* tl)
+{
+  tl->add(this, this->next_blocker_);
+}
+
+// Run a Check_script task.
+
+void
+Check_script::run(Workqueue*)
+{
+  Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
+  gold_assert(incremental_inputs != NULL);
+  unsigned int arg_serial = this->input_reader_->arg_serial();
+  Script_info* script_info =
+      this->ibase_->get_script_info(this->input_file_index_);
+  Timespec mtime = this->input_reader_->get_mtime();
+  incremental_inputs->report_script(script_info, arg_serial, mtime);
+}
+
+// Class Check_library.
+
+Check_library::~Check_library()
+{
+  if (this->this_blocker_ != NULL)
+    delete this->this_blocker_;
+  // next_blocker_ is deleted by the task associated with the next
+  // input file.
+}
+
+// Return whether a Check_library task is runnable.
+
+Task_token*
+Check_library::is_runnable()
+{
+  if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
+    return this->this_blocker_;
+  return NULL;
+}
+
+void
+Check_library::locks(Task_locker* tl)
+{
+  tl->add(this, this->next_blocker_);
+}
+
+// Run a Check_library task.
+
+void
+Check_library::run(Workqueue*)
+{
+  Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs();
+  gold_assert(incremental_inputs != NULL);
+  Incremental_library* lib = this->ibase_->get_library(this->input_file_index_);
+  gold_assert(lib != NULL);
+  lib->copy_unused_symbols();
+  // FIXME: Check that unused symbols remain unused.
+  if (!lib->is_reported())
+    {
+      unsigned int lib_serial = lib->arg_serial();
+      unsigned int lib_index = lib->input_file_index();
+      Script_info* script_info = this->ibase_->get_script_info(lib_index);
+      incremental_inputs->report_archive_begin(lib, lib_serial, script_info);
+    }
+  incremental_inputs->report_archive_end(lib);
+}
+
 // Class Input_group.
 
 // When we delete an Input_group we can delete the archive
diff --git a/gold/readsyms.h b/gold/readsyms.h
index 9515ba1..c1e908c 100644
--- a/gold/readsyms.h
+++ b/gold/readsyms.h
@@ -27,6 +27,7 @@
 
 #include "workqueue.h"
 #include "object.h"
+#include "incremental.h"
 
 namespace gold
 {
@@ -138,14 +139,13 @@ class Add_symbols : public Task
   Add_symbols(Input_objects* input_objects, Symbol_table* symtab,
 	      Layout* layout, Dirsearch* dirpath, int dirindex,
 	      Mapfile* mapfile, const Input_argument* input_argument,
-	      Object* object,
+	      Object* object, Incremental_library* library,
 	      Read_symbols_data* sd, Task_token* this_blocker,
 	      Task_token* next_blocker)
     : input_objects_(input_objects), symtab_(symtab), layout_(layout),
       dirpath_(dirpath), dirindex_(dirindex), mapfile_(mapfile),
-      input_argument_(input_argument),
-      object_(object), sd_(sd), this_blocker_(this_blocker),
-      next_blocker_(next_blocker)
+      input_argument_(input_argument), object_(object), library_(library),
+      sd_(sd), this_blocker_(this_blocker), next_blocker_(next_blocker)
   { }
 
   ~Add_symbols();
@@ -174,11 +174,153 @@ private:
   Mapfile* mapfile_;
   const Input_argument* input_argument_;
   Object* object_;
+  Incremental_library* library_;
   Read_symbols_data* sd_;
   Task_token* this_blocker_;
   Task_token* next_blocker_;
 };
 
+// This Task is responsible for reading the symbols from an archive
+// member that has changed since the last incremental link.
+
+class Read_member : public Task
+{
+ public:
+  // INPUT is the file to read.  INPUT_GROUP is not NULL if we are in
+  // the middle of an input group.  THIS_BLOCKER is used to prevent
+  // the associated Add_symbols task from running before the previous
+  // one has completed; it will be NULL for the first task.
+  // NEXT_BLOCKER is used to block the next input file from adding
+  // symbols.
+  Read_member(Input_objects* input_objects, Symbol_table* symtab,
+	      Layout* layout, Mapfile* mapfile,
+	      const Incremental_binary::Input_reader* input_reader,
+              Task_token* this_blocker, Task_token* next_blocker)
+    : input_objects_(input_objects), symtab_(symtab), layout_(layout),
+      mapfile_(mapfile), input_reader_(input_reader),
+      this_blocker_(this_blocker), next_blocker_(next_blocker)
+  { }
+
+  ~Read_member();
+
+  // The standard Task methods.
+
+  Task_token*
+  is_runnable();
+
+  void
+  locks(Task_locker*);
+
+  void
+  run(Workqueue*);
+
+  std::string
+  get_name() const
+  {
+    return (std::string("Read_member ") + this->input_reader_->filename());
+  }
+
+ private:
+  Input_objects* input_objects_;
+  Symbol_table* symtab_;
+  Layout* layout_;
+  Mapfile* mapfile_;
+  const Incremental_binary::Input_reader* input_reader_;
+  Task_token* this_blocker_;
+  Task_token* next_blocker_;
+};
+
+// This Task is responsible for processing an input script file that has
+// not changed since the last incremental link.
+
+class Check_script : public Task
+{
+ public:
+  Check_script(Layout* layout, Incremental_binary* ibase,
+	       unsigned int input_file_index,
+	       const Incremental_binary::Input_reader* input_reader,
+	       Task_token* this_blocker, Task_token* next_blocker)
+    : layout_(layout), ibase_(ibase), input_file_index_(input_file_index),
+      input_reader_(input_reader), this_blocker_(this_blocker),
+      next_blocker_(next_blocker)
+  {
+    this->filename_ = std::string(this->input_reader_->filename());
+  }
+
+  ~Check_script();
+
+  // The standard Task methods.
+
+  Task_token*
+  is_runnable();
+
+  void
+  locks(Task_locker*);
+
+  void
+  run(Workqueue*);
+
+  std::string
+  get_name() const
+  {
+    return (std::string("Check_script ") + this->input_reader_->filename());
+  }
+
+ private:
+  std::string filename_;
+  Layout* layout_;
+  Incremental_binary* ibase_;
+  unsigned int input_file_index_;
+  const Incremental_binary::Input_reader* input_reader_;
+  Task_token* this_blocker_;
+  Task_token* next_blocker_;
+};
+
+// This Task is responsible for processing an archive library that has
+// not changed since the last incremental link.
+
+class Check_library : public Task
+{
+ public:
+  Check_library(Symbol_table* symtab, Layout* layout,
+		Incremental_binary* ibase,
+		unsigned int input_file_index,
+		const Incremental_binary::Input_reader* input_reader,
+		Task_token* this_blocker, Task_token* next_blocker)
+    : layout_(layout), symtab_(symtab), ibase_(ibase),
+      input_file_index_(input_file_index), input_reader_(input_reader),
+      this_blocker_(this_blocker), next_blocker_(next_blocker)
+  { }
+
+  ~Check_library();
+
+  // The standard Task methods.
+
+  Task_token*
+  is_runnable();
+
+  void
+  locks(Task_locker*);
+
+  void
+  run(Workqueue*);
+
+  std::string
+  get_name() const
+  {
+    return (std::string("Check_library ") + this->input_reader_->filename());
+  }
+
+ private:
+  Layout* layout_;
+  Symbol_table* symtab_;
+  Incremental_binary* ibase_;
+  unsigned int input_file_index_;
+  const Incremental_binary::Input_reader* input_reader_;
+  Task_token* this_blocker_;
+  Task_token* next_blocker_;
+};
+
 // This class is used to track the archives in a group.
 
 class Input_group
diff --git a/gold/reloc.cc b/gold/reloc.cc
index bacf52c..7103572 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -56,7 +56,9 @@ Read_relocs::is_runnable()
 void
 Read_relocs::locks(Task_locker* tl)
 {
-  tl->add(this, this->object_->token());
+  Task_token* token = this->object_->token();
+  if (token != NULL)
+    tl->add(this, token);
 }
 
 // Read the relocations and then start a Scan_relocs_task.
@@ -172,7 +174,9 @@ Scan_relocs::is_runnable()
 void
 Scan_relocs::locks(Task_locker* tl)
 {
-  tl->add(this, this->object_->token());
+  Task_token* token = this->object_->token();
+  if (token != NULL)
+    tl->add(this, token);
   tl->add(this, this->next_blocker_);
 }
 
@@ -222,7 +226,9 @@ Relocate_task::locks(Task_locker* tl)
   if (this->input_sections_blocker_ != NULL)
     tl->add(this, this->input_sections_blocker_);
   tl->add(this, this->final_blocker_);
-  tl->add(this, this->object_->token());
+  Task_token* token = this->object_->token();
+  if (token != NULL)
+    tl->add(this, token);
 }
 
 // Run the task.
@@ -483,7 +489,7 @@ Sized_relobj<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
 
   // For incremental links, finalize the allocation of relocations.
   if (layout->incremental_inputs() != NULL)
-    this->finalize_incremental_relocs(layout);
+    this->finalize_incremental_relocs(layout, true);
 
   if (rd->local_symbols != NULL)
     {
@@ -596,7 +602,7 @@ Sized_relobj<size, big_endian>::incremental_relocs_scan(
     }
 }
 
-// Scan the input relocation for --emit-relocs, templatized on the
+// Scan the input relocation for --incremental, templatized on the
 // type of the relocation section.
 
 template<int size, bool big_endian>
@@ -684,7 +690,8 @@ Sized_relobj<size, big_endian>::do_relocate(const Symbol_table* symtab,
 
   // Write out the local symbols.
   this->write_local_symbols(of, layout->sympool(), layout->dynpool(),
-			    layout->symtab_xindex(), layout->dynsym_xindex());
+			    layout->symtab_xindex(), layout->dynsym_xindex(),
+			    layout->symtab_section()->offset());
 }
 
 // Sort a Read_multiple vector by file offset.
@@ -1134,7 +1141,8 @@ Sized_relobj<size, big_endian>::incremental_relocs_write_reltype(
   const unsigned int reloc_size =
       Reloc_types<sh_type, size, big_endian>::reloc_size;
   const unsigned int sizeof_addr = size / 8;
-  const unsigned int incr_reloc_size = 8 + 2 * sizeof_addr;
+  const unsigned int incr_reloc_size =
+      Incremental_relocs_reader<size, big_endian>::reloc_size;
 
   unsigned int out_shndx = output_section->out_shndx();
 
diff --git a/gold/script.cc b/gold/script.cc
index b56ec1c..8f2170d 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -1436,8 +1436,10 @@ read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout,
     {
       const std::string& filename = input_file->filename();
       Timespec mtime = input_file->file().get_mtime();
-      script_info = new Script_info();
-      layout->incremental_inputs()->report_script(filename, script_info, mtime);
+      unsigned int arg_serial = input_argument->file().arg_serial();
+      script_info = new Script_info(filename);
+      layout->incremental_inputs()->report_script(script_info, arg_serial,
+						  mtime);
     }
 
   Parser_closure closure(input_file->filename().c_str(),
diff --git a/gold/script.h b/gold/script.h
index fc83905..73079a4 100644
--- a/gold/script.h
+++ b/gold/script.h
@@ -548,31 +548,6 @@ class Script_options
   Script_sections script_sections_;
 };
 
-// Information about a script input that will persist during the whole linker
-// run. Needed only during an incremental build to retrieve the input files
-// added by this script.
-
-class Script_info
-{
- public:
-  Script_info()
-    : incremental_script_entry_(NULL)
-  { }
-
-  // Store a pointer to the incremental information for this script.
-  void
-  set_incremental_info(Incremental_script_entry* entry)
-  { this->incremental_script_entry_ = entry; }
-
-  // Return the pointer to the incremental information for this script.
-  Incremental_script_entry*
-  incremental_info() const
-  { return this->incremental_script_entry_; }
-
- private:
-  Incremental_script_entry* incremental_script_entry_;
-};
-
 // FILE was found as an argument on the command line, but was not
 // recognized as an ELF file.  Try to read it as a script.  Return
 // true if the file was handled.  This has to handle /usr/lib/libc.so
diff --git a/gold/symtab.cc b/gold/symtab.cc
index e882dea..3880ce1 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -40,6 +40,7 @@
 #include "symtab.h"
 #include "script.h"
 #include "plugin.h"
+#include "incremental.h"
 
 namespace gold
 {
@@ -1485,6 +1486,37 @@ Symbol_table::add_from_dynobj(
   this->record_weak_aliases(&object_symbols);
 }
 
+// Add a symbol from a incremental object file.
+
+template<int size, bool big_endian>
+Symbol*
+Symbol_table::add_from_incrobj(
+    Object* obj,
+    const char* name,
+    const char* ver,
+    elfcpp::Sym<size, big_endian>* sym)
+{
+  unsigned int st_shndx = sym->get_st_shndx();
+  bool is_ordinary = st_shndx < elfcpp::SHN_LORESERVE;
+
+  Stringpool::Key ver_key = 0;
+  bool is_default_version = false;
+  bool is_forced_local = false;
+
+  Stringpool::Key name_key;
+  name = this->namepool_.add(name, true, &name_key);
+
+  Sized_symbol<size>* res;
+  res = this->add_from_object(obj, name, name_key, ver, ver_key,
+		              is_default_version, *sym, st_shndx,
+			      is_ordinary, st_shndx);
+
+  if (is_forced_local)
+    this->force_local(res);
+
+  return res;
+}
+
 // This is used to sort weak aliases.  We sort them first by section
 // index, then by offset, then by weak ahead of strong.
 
@@ -3419,6 +3451,46 @@ Symbol_table::add_from_dynobj<64, true>(
     size_t* defined);
 #endif
 
+#ifdef HAVE_TARGET_32_LITTLE
+template
+Symbol*
+Symbol_table::add_from_incrobj(
+    Object* obj,
+    const char* name,
+    const char* ver,
+    elfcpp::Sym<32, false>* sym);
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+Symbol*
+Symbol_table::add_from_incrobj(
+    Object* obj,
+    const char* name,
+    const char* ver,
+    elfcpp::Sym<32, true>* sym);
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+Symbol*
+Symbol_table::add_from_incrobj(
+    Object* obj,
+    const char* name,
+    const char* ver,
+    elfcpp::Sym<64, false>* sym);
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+Symbol*
+Symbol_table::add_from_incrobj(
+    Object* obj,
+    const char* name,
+    const char* ver,
+    elfcpp::Sym<64, true>* sym);
+#endif
+
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
 template
 void
diff --git a/gold/symtab.h b/gold/symtab.h
index d350d1d..4196138 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -48,6 +48,8 @@ class Sized_pluginobj;
 class Dynobj;
 template<int size, bool big_endian>
 class Sized_dynobj;
+template<int size, bool big_endian>
+class Sized_incrobj;
 class Versions;
 class Version_script_info;
 class Input_objects;
@@ -1336,6 +1338,13 @@ class Symbol_table
 		  typename Sized_relobj<size, big_endian>::Symbols*,
 		  size_t* defined);
 
+  // Add one external symbol from the incremental object OBJ to the symbol
+  // table.  Returns a pointer to the resolved symbol in the symbol table.
+  template<int size, bool big_endian>
+  Symbol*
+  add_from_incrobj(Object* obj, const char* name,
+		   const char* ver, elfcpp::Sym<size, big_endian>* sym);
+
   // Define a special symbol based on an Output_data.  It is a
   // multiple definition error if this symbol is already defined.
   Symbol*
@@ -1466,6 +1475,11 @@ class Symbol_table
   finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount,
 	   Stringpool* pool, unsigned int* plocal_symcount);
 
+  // Set the final file offset of the symbol table.
+  void
+  set_file_offset(off_t off)
+  { this->offset_ = off; }
+
   // Status code of Symbol_table::compute_final_value.
   enum Compute_final_value_status
   {


More information about the Binutils mailing list