Skip to content

debug/pe: add APIs to support reading COMDAT info for sections #51868

Closed
@thanm

Description

@thanm

This is a proposal to add additional APIs to the "debug/pe" package to
enable reading of auxiliary symbol information, specifically to enable
extraction of info about COMDAT sections, needed by the Go linker.

Background + Motivation

The debug/pe package currently provides hooks for reading symbol table
information from PE object files, notably the "COFFSymbols" slice
provided in pe's "File" type:

  // A File represents an open PE file.
  type File struct {
	FileHeader
	OptionalHeader any // of type *OptionalHeader32 or *OptionalHeader64
	Sections       []*Section
	Symbols        []*Symbol    // COFF symbols with auxiliary symbol records removed
	COFFSymbols    []COFFSymbol // all COFF symbols (including auxiliary symbol records)
	StringTable    StringTable

	closer io.Closer
  }

The COFFSymbols array is something of a fiction, in that the slice
includes entries for "regular" symbols, but also for entries in the
file's symbol array that correspond to aux symbols. Both regular
symbols and aux symbols are 18 bytes in size, but the format of aux
symbols varies depending on the type of regular symbol it precedes.
Picture to illustrate:

   ...
   k+0:  regular sym k
   k+1:    1st aux symbol for k
   k+2:    2nd aux symbol for k
   k+3:  regular sym k+3
   k+4:    1st aux symbol for k+3
   k+5:  regular sym k+5
   k+6:  regular sym k+6
   ...

More can be found in the Microsoft PE format documentation.

The existing debug/pe APIs list the number of aux symbols for each
regular symbol, making it possible to skip aux entries when iterating
through the main symbol array, but there is no way to look inside the
aux symbols.

One class of aux symbol is the section definition
aux symbol, which holds additional bits of info about symbols
corresponding to defined sections in the object file.

One part of the section definition aux symbol is material related to
COMDAT sections; the Go linker needs to be able to access this COMDAT
info in order to support more modern clang-based C toolchains on
Windows (see CL stack at
https://go-review.googlesource.com/q/topic:modernize_windows_c_compiler
and associated issue at https://golang.org/issue/35006).

Proposal details

The proposal is to add these new APIs to debug/pe:

// Section characteristics flags.
const (
	IMAGE_SCN_CNT_CODE               = 0x00000020
	IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x00000040
	IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
	IMAGE_SCN_LNK_COMDAT             = 0x00001000
	IMAGE_SCN_MEM_DISCARDABLE        = 0x02000000
	IMAGE_SCN_MEM_EXECUTE            = 0x20000000
	IMAGE_SCN_MEM_READ               = 0x40000000
	IMAGE_SCN_MEM_WRITE              = 0x80000000
)

// COFFSymbolAuxFormat5 describes the expected form of an aux symbol
// attached to a section definition symbol. The PE format defines a
// number of different aux symbol formats: format 1 for function
// definitions, format 2 for .be and .ef symbols, and so on. Format 5
// holds extra info associated with a section definition, including
// number of relocations + line numbers, as well as COMDAT info. See
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
// for more on what's going on here.
type COFFSymbolAuxFormat5 struct {
	Size           uint32
	NumRelocs      uint16
	NumLineNumbers uint16
	Checksum       uint32
	SecNum         uint16
	Selection      uint8
	_              [3]uint8 // Padding
}

// These constants make up the possible values for the 'Selection'
// field in an AuxFormat5.
const (
	IMAGE_COMDAT_SELECT_NODUPLICATES = 1
	IMAGE_COMDAT_SELECT_ANY          = 2
	IMAGE_COMDAT_SELECT_SAME_SIZE    = 3
	IMAGE_COMDAT_SELECT_EXACT_MATCH  = 4
	IMAGE_COMDAT_SELECT_ASSOCIATIVE  = 5
	IMAGE_COMDAT_SELECT_LARGEST      = 6
)

// COFFSymbolReadSectionDefAux returns a blob of axiliary information
// (including COMDAT info) for a section definition symbol. Here 'idx'
// is the index of a section symbol in the main COFFSymbol array for
// the File. Return value is a pointer to the appropriate aux symbol
// struct. For more info, see:
//
// auxiliary symbols: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-symbol-records
// COMDAT sections: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#comdat-sections-object-only
// auxiliary info for section definitions: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
//
func (f *File) COFFSymbolReadSectionDefAux(idx int) (*COFFSymbolAuxFormat5, error) {

...
}

When a client discovers a section definition symbol that has the IMAGE_SCN_LNK_COMDAT bit set in its characteristics flags, it can call into COFFSymbolReadSectionDefAux to obtain a pointer to the aux info for the section, allowing it to read the info about the COMDAT section.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions