Skip to content

Instantly share code, notes, and snippets.

@affixalex
Created December 31, 2013 23:41
Show Gist options
  • Select an option

  • Save affixalex/8203373 to your computer and use it in GitHub Desktop.

Select an option

Save affixalex/8203373 to your computer and use it in GitHub Desktop.
Rough draft of libld.h
// CDDL HEADER START
//
// The contents of this file are subject to the terms of the
// Common Development and Distribution License (the "License").
// You may not use this file except in compliance with the License.
//
// You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
// or http://www.opensolaris.org/os/licensing.
// See the License for the specific language governing permissions
// and limitations under the License.
//
// When distributing Covered Code, include this CDDL HEADER in each
// file and include the License file at usr/src/OPENSOLARIS.LICENSE.
// If applicable, add the following below this CDDL HEADER, with the
// fields enclosed by brackets "[]" replaced with your own identifying
// information: Portions Copyright [yyyy] [name of copyright owner]
//
// CDDL HEADER END
//
// Copyright (c) 1988 AT&T. All Rights Reserved
// Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
#ifndef _LIBLD_H
#define _LIBLD_H
#include <stdlib.h>
#include <libelf.h>
#include <link.h>
#include <sgs.h>
#include <_machelf.h>
#include <string_table.h>
#include <sys/avl.h>
#include <alist.h>
#include <elfcap.h>
#ifdef __cplusplus
extern "C" {
#endif
// Default directory search path manipulation for the link-editor. YLDIR
// indicates which directory in LIBPATH is replaced by the -YL option to cc
// and ld. YUDIR indicates which directory is replaced by -YU.
#define YLDIR 1
#define YUDIR 2
// Define a hash value that can never be returned from elf_hash().
#define SYM_NOHASH (~(Word)0)
// Macro that can be used to represent both ORDER flags in a section header.
#define ALL_SHF_ORDER (SHF_ORDERED | SHF_LINK_ORDER)
// The linker merges (concatenates) sections with the same name and
// compatible section header flags. When comparing these flags,
// there are some that should not be included in the decision.
// The ALL_SHF_IGNORE constant defines these flags.
//
// NOTE: SHF_MERGE|SHF_STRINGS:
// The compiler is allowed to set the SHF_MERGE|SHF_STRINGS flags in
// order to tell the linker that:
//
// 1) There is nothing in the section except null terminated strings.
// 2) Those strings do not contain NULL bytes, except as termination.
// 3) All references to these strings occur via standard relocation records.
//
// As a result, if two compatible sections both have these flags set, it is
// OK to combine the strings they contain into a single merged string table
// with duplicates removed and tail strings merged.
//
// This is a different meaning than the simple concatenating of sections
// that the linker always does. It is a hint that an additional optimization
// is possible, but not required. This means that sections that do not
// share the same SHF_MERGE|SHF_STRINGS values can be concatenated,
// but cannot have their duplicate strings combined. Hence, the
// SHF_MERGE|SHF_STRINGS flags should be ignored when deciding whether
// two sections can be concatenated.
#define ALL_SHF_IGNORE (ALL_SHF_ORDER | SHF_GROUP | SHF_MERGE | SHF_STRINGS)
// Define symbol reference types for use in symbol resolution.
typedef enum {
REF_DYN_SEEN, // a .so symbol has been seen
REF_DYN_NEED, // a .so symbol satisfies a .o symbol
REF_REL_NEED, // a .o symbol
REF_NUM // the number of symbol references */
} sym_ref_t;
// Relocation descriptor cache
struct rel_cache {
APlist *rc_list; // list of rel_cache_buf_t
ElfW(Word) rc_cnt; // and count
};
// GOT reference models
typedef enum {
GOT_REF_GENERIC, // generic symbol reference
GOT_REF_TLSIE, // TLS initial exec (gnu) reference
GOT_REF_TLSLD, // TLS local dynamic reference
GOT_REF_TLSGD // TLS general dynamic reference
} got_ref_t;
typedef struct {
ElfW(Xword) gn_addend; // addend associated with GOT entry
ElfW(Sword) gn_gotndx; // GOT table index
GOTReference gn_gotref;
} got_ndx_t
// Got debugging structure. The got index is defined as a signed value as we
// do so much mucking around with negative and positive gots on SPARC, and sign
// extension is necessary when building 64-bit objects. On intel we explicitly
// cast this variable to an unsigned value.
typedef struct {
sym_desc *gt_sym;
got_ndx_t gt_gndx;
} got_tbl_t;
// The link-editor caches the results of sloppy relocation processing
// in a variable of type Rlxrel_cache. Symbols come for processing in sorted
// order, so a single item cache suffices to eliminate duplicate lookups.
//
// When sloppy relocation processing fails, the Rlxrel_rej enum reports
// the underlying reason.
typedef enum {
RLXREL_REJ_NONE = 0, // Replacement symbol was found
RLXREL_REJ_TARGET, // Target sec disallows relaxed relocations
RLXREL_REJ_SECTION, // Either there is no replacement section, or its attributes are incompatible
RLXREL_REJ_SYMBOL, // Replacement symbol not found
} rlxrel_rej;
typedef struct sreloc_cache {
Sym_desc *sr_osdp; // Original symbol
Sym_desc *sr_rsdp; // Replacement symbol
Rlxrel_rej sr_rej; // Reason for failure if NULL sr_rsdp
} rlxrel_cache;
// Nodes in an ofl_wrap AVL tree
//
// wsn_name is the name of the symbol to be wrapped. wsn_wrapname is used
// when we need to refer to the wrap symbol, and consists of the symbol
// name with a __wrap_ prefix.
typedef struct wrap_sym_node {
avl_node_t wsn_avlnode; // AVL book-keeping
const char *wsn_name; // Symbol name
const char *wsn_wrapname; // Wrap symbol name: __wrap_XXX
} wrap_sym_node_t;
// Capabilities structures, used to maintain a capabilities set.
//
// Capabilities can be defined within input relocatable objects, and can be
// augmented or replaced by mapfile directives. In addition, mapfile directives
// can be used to exclude capabilities that would otherwise be carried over to
// the output object.
//
// CA_SUNW_HW_1, CA_SUNW_SF_1 and CA_SUNW_HW_2 values are bitmasks. A current
// value, and an exclude value are maintained for each capability.
//
// There can be multiple CA_SUNW_PLAT and CA_SUNW_MACH entries and thus Alists
// are used to collect these entries. A current list for each capability is
// maintained as Capstr entries, which provide for maintaining the strings
// eventual index into a string table. An exclude list is maintained as a
// list of string pointers.
//
// Bitmasks for a single capability. Capabilities come from input objects,
// augmented or replaced by mapfile directives. In addition, mapfile directives
// can be used to exclude bits that would otherwise be set in the output object
typedef struct {
elfcap_mask_t cm_val; // bitmask value
elfcap_mask_t cm_exc; // bits to exclude from final object
} cap_mask_t;
typedef struct {
Alist *cl_val; // string (Capstr) value
APlist *cl_exc; // strings to exclude from final
} cap_list_t; // object
typedef struct {
char *cs_str; // platform or machine name
ElfW(Word) cs_ndx; // the entries output Cap index
} cap_str_t;
typedef uint_t oc_flag_t;
typedef struct {
cap_mask_t oc_hw_1; // CA_SUNW_HW_1 capabilities
cap_mask_t oc_sf_1; // CA_SUNW_SF_1 capabilities
cap_mask_t oc_hw_2; // CA_SUNW_HW_2 capabilities
cap_list_t oc_plat; // CA_SUNW_PLAT capabilities
cap_list_t oc_mach; // CA_SUNW_MACH capabilities
cap_str_t oc_id; // CA_SUNW_ID capability
oc_flag_t oc_flags;
} obj_cap_set_t;
#define FLG_OCS_USRDEFID 0x1 // user defined CA_SUNW_ID
// Combine the bitmask in a CapMask with the exclusion mask and return the resulting final value.
#define CAPMASK_VALUE(_cbmp) ((_cbmp)->cm_value & ~(_cbmp)->cm_exclude)
typedef struct {
cap_mask_t c_hw_1; // CA_SUNW_HW_1 capabilities
cap_mask_t c_sf_1; // CA_SUNW_SF_1 capabilities
cap_mask_t c_hw_2; // CA_SUNW_HW_2 capabilities
} cap_set_t;
// Output file processing structure
typedef ElfW(Lword) ofl_flag_t;
typedef ElfW(Word) ofl_guideflag_t;
struct output_fd_t {
char *ofl_sgsid; // link-editor identification
const char *ofl_name; // full file name
Elf *ofl_elf; // elf_memory() elf descriptor
Elf *ofl_welf; // ELF_C_WRITE elf descriptor
ElfW(Ehdr) *ofl_dehdr; // default elf header, and new elf
ElfW(Ehdr) *ofl_nehdr; // header describing this file
ElfW(Phdr) *ofl_phdr; // program header descriptor
ElfW(Phdr) *ofl_tlsphdr; // TLS phdr
int ofl_fd; // file descriptor
size_t ofl_size; // image size
APlist *ofl_maps; // list of input mapfiles
APlist *ofl_segs; // list of segments
APlist *ofl_segs_order; // SEGMENT_ORDER segments
avl_tree_t ofl_segs_avl; // O(log N) access to named segments
APlist *ofl_ents; // list of entrance descriptors
avl_tree_t ofl_ents_avl; // O(log N) access to named ent. desc
APlist *ofl_objs; // relocatable object file list
ElfW(Word) ofl_objscnt; // and count
APlist *ofl_ars; // archive library list
ElfW(Word) ofl_arscnt; // and count
int ofl_ars_gsandx; // archive group argv index. 0 means no current group, < 0 means error reported. >0 is cur ndx
ElfW(Word) ofl_ars_gsndx; // current -zrescan-start ofl_ars ndx
APlist *ofl_sos; // shared object list
ElfW(Word) ofl_soscnt; // and count
APlist *ofl_soneed; // list of implicitly required .so's
APlist *ofl_socntl; // list of .so control definitions
Rel_cache ofl_outrels; // list of output relocations
Rel_cache ofl_actrels; // list of relocations to perform
APlist *ofl_relaux; // Rel_aux cache for outrels/actrels
Word ofl_entrelscnt; // no of relocations entered
Alist *ofl_copyrels; // list of copy relocations
APlist *ofl_ordered; // list of shf_ordered sections
APlist *ofl_symdtent; // list of syminfo symbols that need to reference .dynamic entries
APlist *ofl_ismove; // list of .SUNW_move sections
APlist *ofl_ismoverel; // list of relocation input section targeting to expanded area
APlist *ofl_parsyms; // list of partially initialized symbols (ie. move symbols)
APlist *ofl_extrarels; // relocation sections which havea NULL sh_info
avl_tree_t *ofl_groups; // pointer to head of Groups AVL tree
APlist *ofl_initarray; // list of init array func names
APlist *ofl_finiarray; // list of fini array func names
APlist *ofl_preiarray; // list of preinit array func names
APlist *ofl_rtldinfo; // list of rtldinfo syms
APlist *ofl_osgroups; // list of output GROUP sections
APlist *ofl_ostlsseg; // pointer to sections in TLS segment
APlist *ofl_unwind; // list of unwind output sections
output_sd_t *ofl_unwindhdr; // Unwind hdr
avl_tree_t ofl_symavl; // pointer to head of Syms AVL tree
sym_desc_t **ofl_regsyms; // array of potential register
ElfW(Word) ofl_regsymsno; // symbols and array count
ElfW(Word) ofl_regsymcnt; // no. of output register symbols
ElfW(Word) ofl_lregsymcnt; // no. of local register symbols
sym_desc_t *ofl_dtracesym; // ld -zdtrace=
ofl_flag_t ofl_flags; // various state bits, args etc.
ofl_flag_t ofl_flags1; // more flags
void *ofl_entry; // entry point (-e and sym_desc_t *)
char *ofl_filtees; // shared objects we are a filter for
const char *ofl_soname; // (-h option) output file name for dynamic structure
const char *ofl_interp; // interpreter name used by exec()
char *ofl_rpath; // run path to store in .dynamic
char *ofl_config; // config path to store in .dynamic
APlist *ofl_ulibdirs; // user supplied library search list
APlist *ofl_dlibdirs; // default library search list
ElfW(Word) ofl_vercnt; // number of versions to generate
APlist *ofl_verdesc; // list of version descriptors
size_t ofl_verdefsz; // size of version definition section
size_t ofl_verneedsz; // size of version needed section
ElfW(Word) ofl_entercnt; // no. of global symbols entered
ElfW(Word) ofl_globcnt; // no. of global symbols to output
ElfW(Word) ofl_scopecnt; // no. of scoped symbols to output
ElfW(Word) ofl_dynscopecnt; // no. scoped syms in .SUNW_ldynsym
ElfW(Word) ofl_elimcnt; // no. of eliminated symbols
ElfW(Word) ofl_locscnt; // no. of local symbols in .symtab
ElfW(Word) ofl_dynlocscnt; // no. local symbols in .SUNW_ldynsym
ElfW(Word) ofl_dynsymsortcnt; // no. ndx in .SUNW_dynsymsort
ElfW(Word) ofl_dyntlssortcnt; // no. ndx in .SUNW_dyntlssort
ElfW(Word) ofl_dynshdrcnt; // no. of output section in .dynsym
ElfW(Word) ofl_shdrcnt; // no. of output sections
ElfW(Word) ofl_caploclcnt; // no. of local capabilities symbols
ElfW(Word) ofl_capsymcnt; // no. of symbol capabilities entries required
ElfW(Word) ofl_capchaincnt; // no. of Capchain symbols
APlist *ofl_capgroups; // list of capabilities groups
avl_tree_t *ofl_capfamilies; // capability family AVL tree
Str_tbl *ofl_shdrsttab; // Str_tbl for shdr strtab
Str_tbl *ofl_strtab; // Str_tbl for symtab strtab
Str_tbl *ofl_dynstrtab; // Str_tbl for dymsym strtab
GOTIndex *ofl_tlsldgotndx; // index to LD TLS_index structure
ElfW(Xword) ofl_relocsz; // size of output relocations
ElfW(Xword) ofl_relocgotsz; // size of .got relocations
ElfW(Xword) ofl_relocpltsz; // size of .plt relocations
ElfW(Xword) ofl_relocbsssz; // size of .bss (copy) relocations
ElfW(Xword) ofl_relocrelsz; // size of .rel[a] relocations
ElfW(Word) ofl_relocincnt; // no. of input relocations
ElfW(Word) ofl_reloccnt; // total number of output relocations
ElfW(Word) ofl_reloccntsub; // total numb of output relocations to skip (-zignore)
ElfW(Word) ofl_relocrelcnt; // total number of relative relocations
ElfW(Word) ofl_gotcnt; // no. of .got entries
ElfW(Word) ofl_pltcnt; // no. of .plt entries
ElfW(Word) ofl_pltpad; // no. of .plt padd entries
ElfW(Word) ofl_hashbkts; // no. of hash buckets required
input_sd_t *ofl_isbss; // .bss input section (globals)
input_sd_t *ofl_islbss; // .lbss input section (globals)
input_sd_t *ofl_istlsbss; // .tlsbss input section (globals)
input_sd_t *ofl_isparexpn; // -z nopartial .data input section
output_sd_t *ofl_osdynamic; // .dynamic output section
output_sd_t *ofl_osdynsym; // .dynsym output section
output_sd_t *ofl_osldynsym; // .SUNW_ldynsym output section
output_sd_t *ofl_osdynstr; // .dynstr output section
output_sd_t *ofl_osdynsymsort; // .SUNW_dynsymsort output section
output_sd_t *ofl_osdyntlssort; // .SUNW_dyntlssort output section
output_sd_t *ofl_osgot; // .got output section
output_sd_t *ofl_oshash; // .hash output section
output_sd_t *ofl_osinitarray; // .init_array output section
output_sd_t *ofl_osfiniarray; // .fini_array output section
output_sd_t *ofl_ospreinitarray; // .preinit_array output section
output_sd_t *ofl_osinterp; // .interp output section
output_sd_t *ofl_oscap; // .SUNW_cap output section
output_sd_t *ofl_oscapinfo; // .SUNW_capinfo output section
output_sd_t *ofl_oscapchain; // .SUNW_capchain output section
output_sd_t *ofl_osplt; // .plt output section
output_sd_t *ofl_osmove; // .SUNW_move output section
output_sd_t *ofl_osrelhead; // first relocation section
output_sd_t *ofl_osrel; // .rel[a] relocation section
output_sd_t *ofl_osshstrtab; // .shstrtab output section
output_sd_t *ofl_osstrtab; // .strtab output section
output_sd_t *ofl_ossymtab; // .symtab output section
output_sd_t *ofl_ossymshndx; // .symtab_shndx output section
output_sd_t *ofl_osdynshndx; // .dynsym_shndx output section
output_sd_t *ofl_osldynshndx; // .SUNW_ldynsym_shndx output sec
output_sd_t *ofl_osverdef; // .version definition output section
output_sd_t *ofl_osverneed; // .version needed output section
output_sd_t *ofl_osversym; // .version symbol ndx output section
ElfW(Word) ofl_dtflags_1; // DT_FLAGS_1 entries
ElfW(Word) ofl_dtflags; // DT_FLAGS entries
output_sd_t *ofl_ossyminfo; // .SUNW_syminfo output section
ElfW(Half) ofl_parexpnndx; // -z nopartial section index Ref. at perform_outreloc() in libld/{mach}/machrel.c
ElfW(Xword) *ofl_checksum; // DT_CHECKSUM value address
char *ofl_depaudit; // dependency auditing required (-P)
char *ofl_audit; // object auditing required (-p)
Alist *ofl_symfltrs; // per-symbol filtees and their
Alist *ofl_dtsfltrs; // associated .dynamic/.dynstrs
Objcapset ofl_ocapset; // object capabilities
Lm_list *ofl_lml; // runtime link-map list
GOTTable *ofl_gottable; // debugging got information
Rlxrel_cache ofl_sr_cache; // Cache last result from sloppy_comdat_reloc()
APlist *ofl_maptext; // mapfile added text sections
APlist *ofl_mapdata; // mapfile added data sections
avl_tree_t *ofl_wrap; // -z wrap symbols
ofl_guideflag_t ofl_guideflags; // -z guide flags
APlist *ofl_assdeflib; // -z assert-deflib exceptions
};
#define FLG_OF_DYNAMIC 0x00000001 // generate dynamic output module
#define FLG_OF_STATIC 0x00000002 // generate static output module
#define FLG_OF_EXEC 0x00000004 // generate an executable
#define FLG_OF_RELOBJ 0x00000008 // generate a relocatable object
#define FLG_OF_SHAROBJ 0x00000010 // generate a shared object
#define FLG_OF_BFLAG 0x00000020 // do no special plt building: -b
#define FLG_OF_IGNENV 0x00000040 // ignore LD_LIBRARY_PATH: -i
#define FLG_OF_STRIP 0x00000080 // strip output: -s
#define FLG_OF_NOWARN 0x00000100 // disable symbol warnings: -t
#define FLG_OF_NOUNDEF 0x00000200 // allow no undefined symbols: -zdefs
#define FLG_OF_PURETXT 0x00000400 // allow no text relocations: -ztext
#define FLG_OF_GENMAP 0x00000800 // generate a memory map: -m
#define FLG_OF_DYNLIBS 0x00001000 // dynamic input allowed: -Bdynamic
#define FLG_OF_SYMBOLIC 0x00002000 // bind global symbols: -Bsymbolic
#define FLG_OF_ADDVERS 0x00004000 // add version stamp: -Qy
#define FLG_OF_NOLDYNSYM 0x00008000 // -znoldynsym set
#define FLG_OF_IS_ORDER 0x00010000 // input section ordering within a segment is required
#define FLG_OF_EC_FILES 0x00020000 // Ent_desc exist w/non-NULL ec_files
#define FLG_OF_TEXTREL 0x00040000 // text relocations have been found
#define FLG_OF_MULDEFS 0x00080000 // multiple symbols are allowed
#define FLG_OF_TLSPHDR 0x00100000 // a TLS program header is required
#define FLG_OF_BLDGOT 0x00200000 // build GOT table
#define FLG_OF_VERDEF 0x00400000 // record version definitions
#define FLG_OF_VERNEED 0x00800000 // record version dependencies
#define FLG_OF_NOVERSEC 0x01000000 // don't record version sections
#define FLG_OF_KEY 0x02000000 // file requires sort keys
#define FLG_OF_PROCRED 0x04000000 // process any symbol reductions by effecting the symbol table output and relocations
#define FLG_OF_SYMINFO 0x08000000 // create a syminfo section
#define FLG_OF_AUX 0x10000000 // ofl_filter is an auxiliary filter
#define FLG_OF_FATAL 0x20000000 // fatal error during input
#define FLG_OF_WARN 0x40000000 // warning during input processing.
#define FLG_OF_VERBOSE 0x80000000 // -z verbose flag set
#define FLG_OF_MAPSYMB 0x000100000000 // symbolic scope definition seen
#define FLG_OF_MAPGLOB 0x000200000000 // global scope definition seen
#define FLG_OF_COMREL 0x000400000000 // -z combreloc set, which enables DT_RELACNT tracking,
#define FLG_OF_NOCOMREL 0x000800000000 // -z nocombreloc set
#define FLG_OF_AUTOLCL 0x001000000000 // automatically reduce unspecified global symbols to locals
#define FLG_OF_AUTOELM 0x002000000000 // automatically eliminate unspecified global symbols
#define FLG_OF_REDLSYM 0x004000000000 // reduce local symbols
#define FLG_OF_OS_ORDER 0x008000000000 // output section ordering required
#define FLG_OF_OSABI 0x010000000000 // tag object as ELFOSABI_SOLARIS
#define FLG_OF_ADJOSCNT 0x020000000000 // adjust ofl_shdrcnt to accommodate discarded sections
#define FLG_OF_OTOSCAP 0x040000000000 // convert object capabilities to symbol capabilities
#define FLG_OF_PTCAP 0x080000000000 // PT_SUNWCAP required
#define FLG_OF_CAPSTRS 0x100000000000 // capability strings are required
#define FLG_OF_EHFRAME 0x200000000000 // output contains .eh_frame section
#define FLG_OF_FATWARN 0x400000000000 // make warnings fatal
#define FLG_OF_ADEFLIB 0x800000000000 // no libraries in default path
// In the flags1 arena, establish any options that are applicable to archive
// extraction first, and associate a mask. These values are recorded with any
// archive descriptor so that they may be reset should the archive require a
// rescan to try and resolve undefined symbols.
#define FLG_OF1_ALLEXRT 0x0000000001 // extract all members from an archive file
#define FLG_OF1_WEAKEXT 0x0000000002 // allow archive extraction to resolve weak references
#define MSK_OF1_ARCHIVE 0x0000000003 // archive flags mask
#define FLG_OF1_NOINTRP 0x0000000008 // -z nointerp flag set
#define FLG_OF1_ZDIRECT 0x0000000010 // -z direct flag set
#define FLG_OF1_NDIRECT 0x0000000020 // no-direct bindings specified
#define FLG_OF1_DEFERRED 0x0000000040 // deferred dependency recording
#define FLG_OF1_RELDYN 0x0000000100 // process .dynamic in rel obj
#define FLG_OF1_NRLXREL 0x0000000200 // -z norelaxreloc flag set
#define FLG_OF1_RLXREL 0x0000000400 // -z relaxreloc flag set
#define FLG_OF1_IGNORE 0x0000000800 // ignore unused dependencies
#define FLG_OF1_NOSGHND 0x0000001000 // -z nosighandler flag set
#define FLG_OF1_TEXTOFF 0x0000002000 // text relocations are ok
#define FLG_OF1_ABSEXEC 0x0000004000 // -zabsexec set
#define FLG_OF1_LAZYLD 0x0000008000 // lazy loading of objects enabled
#define FLG_OF1_GRPPRM 0x0000010000 // dependencies are to have GROUPPERM enabled
#define FLG_OF1_NOPARTI 0x0000040000 // -znopartial set
#define FLG_OF1_BSSOREL 0x0000080000 // output relocation against bss section
#define FLG_OF1_TLSOREL 0x0000100000 // output relocation against .tlsbss section
#define FLG_OF1_MEMORY 0x0000200000 // produce a memory model
#define FLG_OF1_NGLBDIR 0x0000400000 // no DT_1_DIRECT flag allowed
#define FLG_OF1_ENCDIFF 0x0000800000 // host running linker has different byte order than output object
#define FLG_OF1_VADDR 0x0001000000 // a segment defines explicit vaddr
#define FLG_OF1_EXTRACT 0x0002000000 // archive member has been extracted
#define FLG_OF1_RESCAN 0x0004000000 // any archives should be rescanned
#define FLG_OF1_IGNPRC 0x0008000000 // ignore processing required
#define FLG_OF1_NCSTTAB 0x0010000000 // -znocompstrtab set
#define FLG_OF1_DONE 0x0020000000 // link-editor processing complete
#define FLG_OF1_NONREG 0x0040000000 // non-regular file specified as the output file
#define FLG_OF1_ALNODIR 0x0080000000 // establish NODIRECT for all exported interfaces.
#define FLG_OF1_OVHWCAP1 0x0100000000 // override CA_SUNW_HW_1 capabilities
#define FLG_OF1_OVSFCAP1 0x0200000000 // override CA_SUNW_SF_1 capabilities
#define FLG_OF1_OVHWCAP2 0x0400000000 // override CA_SUNW_HW_2 capabilities
#define FLG_OF1_OVMACHCAP 0x0800000000 // override CA_SUNW_MACH capability
#define FLG_OF1_OVPLATCAP 0x1000000000 // override CA_SUNW_PLAT capability
#define FLG_OF1_OVIDCAP 0x2000000000 // override CA_SUNW_ID capability
// Guidance flags. The flags with the FLG_OFG_NO_ prefix are used to suppress
// messages for a given category, and use the lower 28 bits of the word,
// The upper nibble is reserved for other guidance status.
#define FLG_OFG_ENABLE 0x10000000 // -z guidance option active
#define FLG_OFG_ISSUED 0x20000000 // -z guidance message issued
#define FLG_OFG_NO_ALL 0x0fffffff // disable all guidance
#define FLG_OFG_NO_DEFS 0x00000001 // specify all dependencies
#define FLG_OFG_NO_DB 0x00000002 // use direct bindings
#define FLG_OFG_NO_LAZY 0x00000004 // be explicit about lazyload
#define FLG_OFG_NO_MF 0x00000008 // use v2 mapfile syntax
#define FLG_OFG_NO_TEXT 0x00000010 // verify pure text segment
#define FLG_OFG_NO_UNUSED 0x00000020 // remove unused dependency
// Test to see if a guidance should be given for a given category
// or not. _no_flag is one of the FLG_OFG_NO_xxx flags. Returns TRUE
// if the guidance should be issued, and FALSE to remain silent.
#define OFL_GUIDANCE(_ofl, _no_flag) (((_ofl)->ofl_guideflags & \
(FLG_OFG_ENABLE | (_no_flag))) == FLG_OFG_ENABLE)
// Test to see if the output file would allow the presence of
// a .dynsym section.
#define OFL_ALLOW_DYNSYM(_ofl) (((_ofl)->ofl_flags & \
(FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) == FLG_OF_DYNAMIC)
// Test to see if the output file would allow the presence of
// a .SUNW_ldynsym section. The requirements are that a .dynsym
// is allowed, and -znoldynsym has not been specified. Note that
// even if the answer is True (1), we will only generate one if there
// are local symbols that require it.
#define OFL_ALLOW_LDYNSYM(_ofl) (((_ofl)->ofl_flags & \
(FLG_OF_DYNAMIC | FLG_OF_RELOBJ | FLG_OF_NOLDYNSYM)) == FLG_OF_DYNAMIC)
// Test to see if relocation processing should be done. This is normally
// true, but can be disabled via the '-z noreloc' option. Note that
// relocatable objects are still relocated even if '-z noreloc' is present.
#define OFL_DO_RELOC(_ofl) (((_ofl)->ofl_flags & FLG_OF_RELOBJ) || \
!((_ofl)->ofl_dtflags_1 & DF_1_NORELOC))
// Determine whether a static executable is being built.
#define OFL_IS_STATIC_EXEC(_ofl) (((_ofl)->ofl_flags & \
(FLG_OF_STATIC | FLG_OF_EXEC)) == (FLG_OF_STATIC | FLG_OF_EXEC))
// Determine whether a static object is being built. This macro is used
// to select the appropriate string table, and symbol table that other
// sections need to reference.
#define OFL_IS_STATIC_OBJ(_ofl) ((_ofl)->ofl_flags & \
(FLG_OF_RELOBJ | FLG_OF_STATIC))
// Macros for counting symbol table entries. These are used to size symbol
// tables and associated sections (.syminfo, SUNW_capinfo, .hash, etc.) and
// set required sh_info entries (the offset to the first global symbol).
#define SYMTAB_LOC_CNT(_ofl) /* local .symtab entries */ \
(2 + /* NULL and STT_FILE */ \
(_ofl)->ofl_shdrcnt + /* section symbol */ \
(_ofl)->ofl_caploclcnt + /* local capabilities */ \
(_ofl)->ofl_scopecnt + /* scoped symbols */ \
(_ofl)->ofl_locscnt) /* standard locals */
#define SYMTAB_ALL_CNT(_ofl) /* all .symtab entries */ \
(SYMTAB_LOC_CNT(_ofl) + /* .symtab locals */ \
(_ofl)->ofl_globcnt) /* standard globals */
#define DYNSYM_LOC_CNT(_ofl) /* local .dynsym entries */ \
(1 + /* NULL */ \
(_ofl)->ofl_dynshdrcnt + /* section symbols */ \
(_ofl)->ofl_caploclcnt + /* local capabilities */ \
(_ofl)->ofl_lregsymcnt) /* local register symbols */
#define DYNSYM_ALL_CNT(_ofl) /* all .dynsym entries */ \
(DYNSYM_LOC_CNT(_ofl) + /* .dynsym locals */ \
(_ofl)->ofl_globcnt) /* standard globals */
// Define a move descriptor used within relocation structures.
typedef struct {
ElfW(Move) *mr_move;
Sym_desc *mr_sym;
} Mv_reloc;
// Relocation (active & output) processing structure - transparent to common
// code. There can be millions of these structures in a large link, so it
// is important to keep it small. You should only add new items to Rel_desc
// if they are critical, apply to most relocations, and cannot be easily
// computed from the other information.
//
// Items that can be derived should be implemented as a function that accepts
// a Rel_desc argument, and returns the desired data. ld_reloc_sym_name() is
// an example of this.
//
// Lesser used relocation data is kept in an auxiliary block, Rel_aux,
// that is only allocated as necessary. In exchange for adding one pointer
// of overhead to Rel_desc (rel_aux), most relocations are reduced in size
// by the size of Rel_aux. This strategy relies on the data in Rel_aux
// being rarely needed --- otherwise it will backfire badly.
//
// Note that rel_raddend is primarily only of interest to RELA relocations,
// and is set to 0 for REL. However, there is an exception: If FLG_REL_NADDEND
// is set, then rel_raddend contains a replacement value for the implicit
// addend found in the relocation target.
//
// Fields should be ordered from largest to smallest, to minimize packing
// holes in the struct layout.
struct relocation_descriptor {
input_section_descriptor *rel_isdesc; // input section reloc is against
Sym_desc *rel_sym; // sym relocation is against
Rel_aux *rel_aux; // NULL, or auxiliary data
ElfW(Xword) rel_roffset; // relocation offset
ElfW(Sxword) rel_raddend; // addend from input relocation
ElfW(Word) rel_flags; // misc. flags for relocations
ElfW(Word) rel_rtype; // relocation type
};
// Data that would be kept in Rel_desc if the size of that structure was
// not an issue. This auxiliary block is only allocated as needed,
// and must only contain rarely needed items. The goal is for the vast
// majority of Rel_desc structs to not have an auxiliary block.
//
// When a Rel_desc does not have an auxiliary block, a default value
// is assumed for each auxiliary item:
//
// - ra_osdesc:
// Output section to which relocation applies. The default
// value for this is the output section associated with the
// input section (rel_isdesc->is_osdesc), or NULL if there
// is no associated input section.
//
// - ra_usym:
// If the symbol associated with a relocation is part of a weak/strong
// pair, then ra_usym contains the strong symbol and rel_sym the weak.
// Otherwise, the default value is the same value as rel_sym.
//
// - ra_move:
// Move table data. The default value is NULL.
//
// - ra_typedata:
// ELF_R_TYPE_DATA(info). This value applies only to a small
// subset of 64-bit sparc relocations, and is otherwise 0. The
// default value is 0.
//
// If any value in Rel_aux is non-default, then an auxiliary block is
// necessary, and each field contains its actual value. If all the auxiliary
// values are default, no Rel_aux is needed, and the RELAUX_GET_xxx()
// macros below are able to supply the proper default.
//
// To set a Rel_aux value, use the ld_reloc_set_aux_XXX() functions.
// These functions are written to avoid unnecessary auxiliary allocations,
// and know the rules for each item.
struct rel_aux {
output_sd_t *ra_osdesc; // output section reloc is against
sym_desc *ra_usym; // strong sym if this is a weak pair
Mv_reloc *ra_move; // move table information
ElfW(Word) ra_typedata; // ELF_R_TYPE_DATA(info)
};
// Test a given auxiliary value to determine if it has the default value
// for that item, as described above. If all the auxiliary items have
// their default values, no auxiliary place is necessary to represent them.
// If any one of them is non-default, the auxiliary block is needed.
#define RELAUX_ISDEFAULT_MOVE(_rdesc, _mv) (_mv == NULL)
#define RELAUX_ISDEFAULT_USYM(_rdesc, _usym) ((_rdesc)->rel_sym == _usym)
#define RELAUX_ISDEFAULT_OSDESC(_rdesc, _osdesc) \
((((_rdesc)->rel_isdesc == NULL) && (_osdesc == NULL)) || \
((_rdesc)->rel_isdesc && ((_rdesc)->rel_isdesc->is_osdesc == _osdesc)))
#define RELAUX_ISDEFAULT_TYPEDATA(_rdesc, _typedata) (_typedata == 0)
// Retrieve the value of an auxiliary relocation item, preserving the illusion
// that every relocation descriptor has an auxiliary block attached. The
// real implementation is that an auxiliary block is only present if one or
// more auxiliary items have non-default values. These macros return the true
// value if an auxiliary block is present, and the default value for the
// item otherwise.
#define RELAUX_GET_MOVE(_rdesc) \
((_rdesc)->rel_aux ? (_rdesc)->rel_aux->ra_move : NULL)
#define RELAUX_GET_USYM(_rdesc) \
((_rdesc)->rel_aux ? (_rdesc)->rel_aux->ra_usym : (_rdesc)->rel_sym)
#define RELAUX_GET_OSDESC(_rdesc) \
((_rdesc)->rel_aux ? (_rdesc)->rel_aux->ra_osdesc : \
((_rdesc)->rel_isdesc ? (_rdesc)->rel_isdesc->is_osdesc : NULL))
#define RELAUX_GET_TYPEDATA(_rdesc) \
((_rdesc)->rel_aux ? (_rdesc)->rel_aux->ra_typedata : 0)
// common flags used on the Rel_desc structure (defined in machrel.h).
#define FLG_REL_GOT 0x00000001 // relocation against GOT
#define FLG_REL_PLT 0x00000002 // relocation against PLT
#define FLG_REL_BSS 0x00000004 // relocation against BSS
#define FLG_REL_LOAD 0x00000008 // section loadable
#define FLG_REL_SCNNDX 0x00000010 // use section index for symbol ndx
#define FLG_REL_CLVAL 0x00000020 // clear VALUE for active relocation
#define FLG_REL_ADVAL 0x00000040 // add VALUE for output relocation, only relevant to SPARC and R_SPARC_RELATIVE
#define FLG_REL_GOTCL 0x00000080 // clear the GOT entry. This is relevant to RELA relocations, not REL (i386) relocations
#define FLG_REL_MOVETAB 0x00000100 // Relocation against .SUNW_move adjustments required before actual relocation
#define FLG_REL_NOINFO 0x00000200 // Relocation comes from a section with a null sh_info field
#define FLG_REL_REG 0x00000400 // Relocation target is reg sym
#define FLG_REL_FPTR 0x00000800 // relocation against func. desc.
#define FLG_REL_RFPTR1 0x00001000 // Relative relocation against 1st part of FD
#define FLG_REL_RFPTR2 0x00002000 // Relative relocation against 2nd part of FD
#define FLG_REL_DISP 0x00004000 // *disp* relocation
#define FLG_REL_STLS 0x00008000 // IE TLS reference to static TLS GOT index
#define FLG_REL_DTLS 0x00010000 // GD TLS reference relative to dynamic TLS GOT index
#define FLG_REL_MTLS 0x00020000 // LD TLS reference against GOT
#define FLG_REL_STTLS 0x00040000 // LE TLS reference directly to static tls index
#define FLG_REL_TLSFIX 0x00080000 // relocation points to TLS instr. which needs updating
#define FLG_REL_RELA 0x00100000 // descriptor captures a Rela
#define FLG_REL_GOTFIX 0x00200000 // relocation points to GOTOP instr. which needs updating
#define FLG_REL_NADDEND 0x00400000 // Replace implicit addend in dest with value in rel_raddend
// Relevant to REL (i386) relocations, not to RELA.
// We often need the name of the symbol contained in a relocation descriptor
// for diagnostic or error output. This is usually the symbol name, but
// we substitute a constructed name in some cases. Hence, the name is
// generated on the fly by a private function within libld. This is the
// prototype for that function.
typedef const char *(* rel_desc_sname_func_t)(Rel_desc *);
// Header for a relocation descriptor cache buffer.
struct rel_cachebuf {
Rel_desc *rc_end;
Rel_desc *rc_free;
Rel_desc rc_arr[1];
};
// Header for a relocation auxiliary descriptor cache buffer.
struct rel_aux_cachebuf {
Rel_aux *rac_end;
Rel_aux *rac_free;
Rel_aux rac_arr[1];
};
// Convenience macro for traversing every relocation descriptor found within
// a given relocation cache, transparently handling the cache buffers and
// skipping any unallocated descriptors within the buffers.
//
// entry:
// _rel_cache - Relocate descriptor cache (Rel_cache) to traverse
// _idx - Aliste index variable for use by the macro
// _rcbp - Cache buffer pointer, for use by the macro
// _orsp - Rel_desc pointer, which will take on the value of a different
// relocation descriptor in the cache in each iteration.
//
// The caller must not assign new values to _idx, _rcbp, or _orsp within
// the scope of REL_CACHE_TRAVERSE.
#define REL_CACHE_TRAVERSE(_rel_cache, _idx, _rcbp, _orsp) \
for (APLIST_TRAVERSE((_rel_cache)->rc_list, _idx, _rcbp)) \
for (_orsp = _rcbp->rc_arr; _orsp < _rcbp->rc_free; _orsp++)
// Symbol value descriptor. For relocatable objects, each symbols value is
// its offset within its associated section. Therefore, to uniquely define
// each symbol within a relocatable object, record and sort the sh_offset and
// symbol value. This information is used to search for displacement
// relocations as part of copy relocation validation.
typedef struct {
Addr ssv_value;
Sym_desc *ssv_sdp;
} Ssv_desc;
// Input file processing structures.
struct input_fd_t { // input file descriptor
const char *ifl_name; // full file name
const char *ifl_soname; // shared object name
dev_t ifl_stdev; // device id and inode number for .so
ino_t ifl_stino; // multiple inclusion checks
ElfW(Ehdr) *ifl_ehdr; // elf header describing this file
Elf *ifl_elf; // elf descriptor for this file
SymbolDescriptor **ifl_oldndx; // original symbol table indices
SymbolDescriptor *ifl_locs; // symbol desc version of locals
Ssv_desc *ifl_sortsyms; // sorted list of symbols by value
ElfW(Word) ifl_locscnt; // no. of local symbols to process
ElfW(Word) ifl_shnum; // number of sections in file
ElfW(Word) ifl_shstrndx; // index to .shstrtab
ElfW(Word) ifl_vercnt; // number of versions in file
ElfW(Half) ifl_neededndx; // index to NEEDED in .dyn section
ElfW(Word) ifl_flags; // explicit/implicit reference
input_sd_t **ifl_isdesc; // isdesc[scn ndx] = Is_desc ptr */
Sdf_desc `*ifl_sdfdesc; // control definition
ElfW(Versym) *ifl_versym; // version symbol table array
VersionIndex *ifl_verndx; // verndx[ver ndx] = Ver_index
APlist *ifl_verdesc; // version descriptor list
APlist *ifl_relsect; // relocation section list
Alist *ifl_groups; // SHT_GROUP section list
cap_desc_t *ifl_caps; // capabilities descriptor
};
#define FLG_IF_CMDLINE 0x00000001 // full filename specified from the command line (no -l)
#define FLG_IF_NEEDED 0x00000002 // shared object should be recorded
#define FLG_IF_DIRECT 0x00000004 // establish direct bindings to this object
#define FLG_IF_EXTRACT 0x00000008 // file extracted from an archive
#define FLG_IF_VERNEED 0x00000010 // version dependency information is required
#define FLG_IF_DEPREQD 0x00000020 // dependency is required to satisfy symbol references
#define FLG_IF_NEEDSTR 0x00000040 // dependency specified by -Nn flag
#define FLG_IF_IGNORE 0x00000080 // ignore unused dependencies
#define FLG_IF_NODIRECT 0x00000100 // object contains symbols that cannot be directly bound to
#define FLG_IF_LAZYLD 0x00000200 // dependency should be lazy loaded
#define FLG_IF_GRPPRM 0x00000400 // dependency establishes a group
#define FLG_IF_DISPPEND 0x00000800 // displacement relocation done at link time.
#define FLG_IF_DISPDONE 0x00001000 // displacement relocation done at run time
#define FLG_IF_MAPFILE 0x00002000 // file is a mapfile
#define FLG_IF_HSTRTAB 0x00004000 // file has a string section
#define FLG_IF_FILEREF 0x00008000 // file contains a section which is included in the output allocatable image
#define FLG_IF_GNUVER 0x00010000 // file used GNU-style versioning
#define FLG_IF_ORDERED 0x00020000 // ordered section processing required
#define FLG_IF_OTOSCAP 0x00040000 // convert object capabilities to symbol capabilities
#define FLG_IF_DEFERRED 0x00080000 // dependency is deferred
#define FLG_IF_RTLDINF 0x00100000 // dependency has DT_SUNW_RTLTINF set
// Symbol states that require the generation of a DT_POSFLAG_1 .dynamic entry.
#define MSK_IF_POSFLAG1 (FLG_IF_LAZYLD | FLG_IF_GRPPRM | FLG_IF_DEFERRED)
// Symbol states that require an associated Syminfo entry.
#define MSK_IF_SYMINFO (FLG_IF_LAZYLD | FLG_IF_DIRECT | FLG_IF_DEFERRED)
struct input_sd_t { // input section descriptor
const char *is_name; // original section name
const char *is_sym_name; // NULL, or name string to use for related STT_SECTION symbols
ElfW(Shdr) *is_shdr; // the elf section header
input_fd_t *is_file; // input file descriptor for this section
output_sd_t *is_osdesc; // new output section for this input section
Elf_Data *is_indata; // input sections raw data
input_sd_t *is_symshndx; // related SHT_SYM_SHNDX section
input_sd_t *is_comdatkeep; // If COMDAT section is discarded, this is section that was kept
ElfW(Word) is_scnndx; // original section index in file
ElfW(Word) is_ordndx; // index for section. Used to decide where to insert section when reordering sections
ElfW(Word) is_keyident; // key for SHF_{ORDERED|LINK_ORDER} processing and ident used for placing/ordering sections
ElfW(Word) is_flags; // Various flags
};
#define FLG_IS_ORDERED 0x0001 // this is a SHF_ORDERED section
#define FLG_IS_KEY 0x0002 // section requires sort keys
#define FLG_IS_DISCARD 0x0004 // section is to be discarded
#define FLG_IS_RELUPD 0x0008 // symbol defined here may have moved
#define FLG_IS_SECTREF 0x0010 // section has been referenced
#define FLG_IS_GDATADEF 0x0020 // section contains global data sym
#define FLG_IS_EXTERNAL 0x0040 // isp from a user file
#define FLG_IS_INSTRMRG 0x0080 // Usable SHF_MERGE|SHF_STRINGS sec
#define FLG_IS_GNSTRMRG 0x0100 // Generated mergeable string section
#define FLG_IS_GROUPS 0x0200 // section has groups to process
#define FLG_IS_PLACE 0x0400 // section requires to be placed
#define FLG_IS_COMDAT 0x0800 // section is COMDAT
#define FLG_IS_EHFRAME 0x1000 // section is .eh_frame
// Output sections contain lists of input sections that are assigned to them.
// These items fall into 4 categories:
// BEFORE - Ordered sections that specify SHN_BEFORE, in input order.
// ORDERED - Ordered sections that are sorted using unsorted sections
// as the sort key.
// DEFAULT - Sections that are placed into the output section
// in input order.
// AFTER - Ordered sections that specify SHN_AFTER, in input order.
#define OS_ISD_BEFORE 0
#define OS_ISD_ORDERED 1
#define OS_ISD_DEFAULT 2
#define OS_ISD_AFTER 3
#define OS_ISD_NUM 4
typedef APlist *os_isdecs_arr[OS_ISD_NUM];
// Convenience macro for traversing every input section associated
// with a given output section. The primary benefit of this macro
// is that it preserves a precious level of code indentation in the
// code that uses it.
#define OS_ISDESCS_TRAVERSE(_list_idx, _osp, _idx, _isp) \
for (_list_idx = 0; _list_idx < OS_ISD_NUM; _list_idx++) \
for (APLIST_TRAVERSE(_osp->os_isdescs[_list_idx], _idx, _isp))
// Map file and output file processing structures
struct output_sd_t { // Output section descriptor
const char *os_name; // the section name
Elf_Scn *os_scn; // the elf section descriptor
ElfW(Shdr) *os_shdr; // the elf section header
output_sd_t *os_relosdesc; // the output relocation section
APlist *os_relisdescs; // reloc input section descriptors for this output section
os_isdecs_arr os_isdescs; // lists of input sections in output
APlist *os_mstrisdescs; // FLG_IS_INSTRMRG input sections
Sg_desc *os_sgdesc; // segment os_desc is placed on
Elf_Data *os_outdata; // output sections raw data
avl_tree_t *os_comdats; // AVL tree of COMDAT input sections associated to output section
ElfW(Word) os_identndx; // section identifier for input section processing, followed by section symbol index
ElfW(Word) os_ordndx; // index for section. Used to decide where to insert section when reordering sections
ElfW(Xword) os_szoutrels; // size of output relocation section
unsigned int os_namehash; // hash on section name
unsigned short os_flags; // various flags
};
#define FLG_OS_KEY 0x01 // section requires sort keys
#define FLG_OS_OUTREL 0x02 // output rel against this section
#define FLG_OS_SECTREF 0x04 // isps are not affected by -zignore
#define FLG_OS_EHFRAME 0x08 // section is .eh_frame
// The sg_id field of the segment descriptor is used to establish the default
// order for program headers and segments in the output object. Segments are
// ordered according to the following SGID values that classify them based on
// their attributes. The initial set of built in segments are in this order,
// and new mapfile defined segments are inserted into these groups. Within a
// given SGID group, the position of new segments depends on the syntax
// version of the mapfile that creates them. Version 1 (original sysv)
// mapfiles place the new segment at the head of their group (reverse creation
// order). The newer syntax places them at the end, following the others
// (creation order).
//
// Note that any new segments must always be added after PT_PHDR and
// PT_INTERP (refer Generic ABI, Page 5-4).
#define SGID_PHDR 0 // PT_PHDR
#define SGID_INTERP 1 // PT_INTERP
#define SGID_SUNWCAP 2 // PT_SUNWCAP
#define SGID_TEXT 3 // PT_LOAD
#define SGID_DATA 4 // PT_LOAD
#define SGID_BSS 5 // PT_LOAD
#if defined(_ELF64)
#define SGID_LRODATA 6 // PT_LOAD (amd64-only)
#define SGID_LDATA 7 // PT_LOAD (amd64-only)
#endif
#define SGID_TEXT_EMPTY 8 // PT_LOAD, reserved (?E in version 1 syntax)
#define SGID_NULL_EMPTY 9 // PT_NULL, reserved (?E in version 1 syntax)
#define SGID_DYN 10 // PT_DYNAMIC
#define SGID_DTRACE 11 // PT_SUNWDTRACE
#define SGID_TLS 12 // PT_TLS
#define SGID_UNWIND 13 // PT_SUNW_UNWIND
#define SGID_SUNWSTACK 14 // PT_SUNWSTACK
#define SGID_NOTE 15 // PT_NOTE
#define SGID_NULL 16 // PT_NULL, mapfile defined empty phdr slots for use by post processors
#define SGID_EXTRA 17 // PT_NULL (final catchall)
typedef ElfW(Half) sg_flags_t;
struct output_sd_t { // Output segment descriptor
ElfW(Word) sg_id; // segment identifier (for sorting)
ElfW(Phdr) sg_phdr; // segment header for output file
const char *sg_name; // segment name for PT_LOAD, PT_NOTE, and PT_NULL, otherwise NULL
ElfW(Xword) sg_round; // data rounding required (mapfile)
ElfW(Xword) sg_length; // maximum segment length; if 0 segment is not specified
APlist *sg_osdescs; // list of output section descriptors
APlist *sg_is_order; // list of entry criteria giving input section order
Alist *sg_os_order; // list specifying output section ordering for the segment
sg_flags_t sg_flags;
APlist *sg_sizesym; // size symbols for this segment
ElfW(Xword) sg_align; // LCM of sh_addralign
Elf_Scn *sg_fscn; // the SCN of the first section.
avl_node_t sg_avlnode; // AVL book-keeping
};
#define FLG_SG_P_VADDR 0x0001 // p_vaddr segment attribute set
#define FLG_SG_P_PADDR 0x0002 // p_paddr segment attribute set
#define FLG_SG_LENGTH 0x0004 // length segment attribute set
#define FLG_SG_P_ALIGN 0x0008 // p_align segment attribute set
#define FLG_SG_ROUND 0x0010 // round segment attribute set
#define FLG_SG_P_FLAGS 0x0020 // p_flags segment attribute set
#define FLG_SG_P_TYPE 0x0040 // p_type segment attribute set
#define FLG_SG_IS_ORDER 0x0080 // input section ordering is required for this segment.
#define FLG_SG_NOHDR 0x0100 // don't map ELF or phdrs into this segment
#define FLG_SG_EMPTY 0x0200 // an empty segment specification no input sections will be associated to this section
#define FLG_SG_KEY 0x0400 // segment requires sort keys
#define FLG_SG_NODISABLE 0x0800 // FLG_SG_DISABLED is not allowed on this segment
#define FLG_SG_DISABLED 0x1000 // this segment is disabled
#define FLG_SG_PHREQ 0x2000 // this segment requires a program header
#define FLG_SG_ORDERED 0x4000 // SEGMENT_ORDER segment
struct sec_order {
const char *sco_secname; // section name to be ordered
ElfW(Half) sco_flags;
};
#define FLG_SGO_USED 0x0001 // was ordering used?
typedef ElfW(Half) ec_flags_t;
struct entrance_descriptor { // input section entrance criteria
const char *ec_name; // entrance criteria name, or NULL
Alist *ec_files; // files from which to accept sections
const char *ec_is_name; // input section name to match (NULL if none)
ElfW(Word) ec_type; // section type
ElfW(Word) ec_attrmask; // section attribute mask (AWX)
ElfW(Word) ec_attrbits; // sections attribute bits
seg_desc *ec_segment; // output segment to enter if matched
ElfW(Word) ec_ordndx; // index to determine where section meeting this criteria should inserted. Used for reordering of sections.
ec_flags_t ec_flags;
avl_node_t ec_avlnode; // AVL book-keeping
};
#define FLG_EC_BUILTIN 0x0001 // built in descriptor
#define FLG_EC_USED 0x0002 // entrance criteria met?
#define FLG_EC_CATCHALL 0x0004 // Catches any section
// Ent_desc_file is the type of element maintained in the ec_files Alist
// of an entrance criteria descriptor. Each item maintains one file
// path, and a set of flags that specify the type of comparison it implies,
// and other information about it. The comparison type is maintained in
// the bottom byte of the flags.
#define TYP_ECF_MASK 0x00ff // Comparison type mask
#define TYP_ECF_PATH 0 // Compare to file path
#define TYP_ECF_BASENAME 1 // Compare to file basename
#define TYP_ECF_OBJNAME 2 // Compare to regular file basename, or to archive member name
#define TYP_ECF_NUM 3
#define FLG_ECF_ARMEMBER 0x0100 // name includes archive member
typedef struct {
ElfW(Word) edf_flags; // Type of comparison
const char *edf_name; // String to compare to
size_t edf_name_len; // strlen(edf_name)
} Ent_desc_file;
// One structure is allocated for a move entry, and associated to the symbol
// against which a move is targeted.
typedef struct {
ElfW(Move) *md_move; // original Move entry
ElfW(Xword) md_start; // start position
ElfW(Xword) md_len; // length of initialization
ElfW(Word) md_oidx; // output Move entry index
} Mv_desc;
// Symbol descriptor.
typedef ElfW(Lword) sd_flag_t;
struct sym_desc { // Symbol Descriptor
Alist *sd_GOTndxs; // list of associated GOT entries
ElfW(Sym) *sd_sym; // pointer to symbol table entry
ElfW(Sym) *sd_osym; // copy of the original symbol entry used only for local partial
Alist *sd_move; // move information associated with a partially initialized symbol
const char *sd_name; // symbols name
Ifl_desc *sd_file; // file where symbol is taken
input_sd_t *sd_isc; // input section of symbol definition
Sym_aux *sd_aux; // auxiliary global symbol info.
ElfW(Word) sd_symndx; // index in output symbol table
ElfW(Word) sd_shndx; // section index symbol is associated with
sd_flag_t sd_flags; // state flags
ElfW(Half) sd_ref; // reference definition of symbol */
};
// The auxiliary symbol descriptor contains the additional information (beyond
// the symbol descriptor) required to process global symbols. These symbols are
// accessed via an internal symbol hash table where locality of reference is
// important for performance.
struct sym_aux {
APlist *sa_dfiles; // files where symbol is defined
ElfW(Sym) sa_sym; // copy of symtab entry
const char *sa_vfile; // first unavailable definition
const char *sa_rfile; // file with first symbol referenced
ElfW(Word) sa_hash; // the pure hash value of symbol
ElfW(Word) sa_PLTndx; // index into PLT for symbol
ElfW(Word) sa_PLTGOTndx; // GOT entry indx for PLT indirection
ElfW(Word) sa_linkndx; // index of associated symbol from ET_DYN file
ElfW(Half) sa_symspec; // special symbol ids
ElfW(Half) sa_overndx; // output file versioning index
ElfW(Half) sa_dverndx; // dependency versioning index
};
// Nodes used to track symbols in the global AVL symbol dictionary.
struct symbol_avlnode {
avl_node_t sav_node; // AVL node
ElfW(Word) sav_hash; // symbol hash value
const char *sav_name; // symbol name
sym_desc *sav_sdp; // symbol descriptor
};
// These are the ids for processing of `Special symbols'. They are used
// to set the sym->sd_aux->sa_symspec field.
#define SDAUX_ID_ETEXT 1 // etext && _etext symbol
#define SDAUX_ID_EDATA 2 // edata && _edata symbol
#define SDAUX_ID_END 3 // end, _end, && _END_ symbol
#define SDAUX_ID_DYN 4 // DYNAMIC && _DYNAMIC symbol
#define SDAUX_ID_PLT 5 // _PROCEDURE_LINKAGE_TABLE_ symbol
#define SDAUX_ID_GOT 6 // _GLOBAL_OFFSET_TABLE_ symbol
#define SDAUX_ID_START 7 // START_ && _START_ symbol
// Flags for sym_desc.sd_flags
#define FLG_SY_MVTOCOMM 0x00000001 // assign symbol to common (.bss) this is a result of a copy reloc against sym
#define FLG_SY_GLOBREF 0x00000002 // a global reference has been seen
#define FLG_SY_WEAKDEF 0x00000004 // a weak definition has been used
#define FLG_SY_CLEAN 0x00000008 // `Sym' entry points to original input file (read-only).
#define FLG_SY_UPREQD 0x00000010 /* symbol value update is required, */
/* either it's used as an entry */
/* point or for relocation, but */
/* it must be updated even if */
/* the -s flag is in effect */
#define FLG_SY_NOTAVAIL 0x00000020 /* symbol is not available to the */
/* application either because it */
/* originates from an implicitly */
/* referenced shared object, or */
/* because it is not part of a */
/* specified version. */
#define FLG_SY_REDUCED 0x00000040 // a global is reduced to local
#define FLG_SY_VERSPROM 0x00000080 // version definition has been promoted to output file
#define FLG_SY_PROT 0x00000100 // stv_protected visibility seen
#define FLG_SY_MAPREF 0x00000200 // symbol reference generated by user from mapfile
#define FLG_SY_REFRSD 0x00000400 // symbols sd_ref has been raised due to a copy-relocs weak-strong pairing
#define FLG_SY_INTPOSE 0x00000800 // symbol defines an interposer
#define FLG_SY_INVALID 0x00001000 // unwanted/erroneous symbol
#define FLG_SY_SMGOT 0x00002000 // small got index assigned to symbol sparc only
#define FLG_SY_PARENT 0x00004000 // symbol to be found in parent only used with direct bindings
#define FLG_SY_LAZYLD 0x00008000 // symbol to cause lazyloading of parent object
#define FLG_SY_ISDISC 0x00010000 // symbol is a member of a DISCARDED section (COMDAT)
#define FLG_SY_PAREXPN 0x00020000 // partially init. symbol to be expanded
#define FLG_SY_PLTPAD 0x00040000 // pltpadding has been allocated for this symbol
#define FLG_SY_REGSYM 0x00080000 // REGISTER symbol (sparc only)
#define FLG_SY_SOFOUND 0x00100000 // compared against an SO definition
#define FLG_SY_EXTERN 0x00200000 // symbol is external, allows -zdefs error suppression
#define FLG_SY_MAPUSED 0x00400000 // mapfile symbol used (occurred within a relocatable object)
#define FLG_SY_COMMEXP 0x00800000 // COMMON symbol which has been allocated
#define FLG_SY_CMDREF 0x01000000 // symbol was referenced from the command line. (ld -u <>, ld -zrtldinfo=<>, ...)
#define FLG_SY_SPECSEC 0x02000000 // section index is reserved value ABS, COMMON, ...
#define FLG_SY_TENTSYM 0x04000000 // tentative symbol
#define FLG_SY_VISIBLE 0x08000000 // symbols visibility determined
#define FLG_SY_STDFLTR 0x10000000 // symbol is a standard filter
#define FLG_SY_AUXFLTR 0x20000000 // symbol is an auxiliary filter
#define FLG_SY_DYNSORT 0x40000000 // req. in dyn[sym|tls]sort section
#define FLG_SY_NODYNSORT 0x80000000 // excluded from dyn[sym_tls]sort sec
#define FLG_SY_DEFAULT 0x0000100000000 // global symbol, default
#define FLG_SY_SINGLE 0x0000200000000 // global symbol, singleton defined
#define FLG_SY_PROTECT 0x0000400000000 // global symbol, protected defined
#define FLG_SY_EXPORT 0x0000800000000 // global symbol, exported defined
#define MSK_SY_GLOBAL (FLG_SY_DEFAULT | FLG_SY_SINGLE | FLG_SY_PROTECT | FLG_SY_EXPORT)
// this mask indicates that the symbol has been explicitly defined within a mapfile
// definition, and is a candidate for versioning
#define FLG_SY_HIDDEN 0x0001000000000 // global symbol, reduce to local
#define FLG_SY_ELIM 0x0002000000000 // global symbol, eliminate
#define FLG_SY_IGNORE 0x0004000000000 // global symbol, ignored
#define MSK_SY_LOCAL (FLG_SY_HIDDEN | FLG_SY_ELIM | FLG_SY_IGNORE)
// this mask allows all local state flags to be removed when the symbol is copy relocated
#define FLG_SY_EXPDEF 0x0008000000000 // symbol visibility defined explicitly
#define MSK_SY_NOAUTO (FLG_SY_SINGLE | FLG_SY_EXPORT | FLG_SY_EXPDEF)
// this mask indicates that the symbol is not a candidate for auto-reduction/elimination
#define FLG_SY_MAPFILE 0x0010000000000 // symbol attribute defined in a mapfile
#define FLG_SY_DIR 0x0020000000000 // global symbol, direct bindings
#define FLG_SY_NDIR 0x0040000000000 // global symbol, nondirect bindings
#define FLG_SY_OVERLAP 0x0080000000000 // move entry overlap detected
#define FLG_SY_CAP 0x0100000000000 // symbol is associated with capabilities
#define FLG_SY_DEFERRED 0x0200000000000 // symbol should not be bound to during BIND_NOW relocations
// A symbol can only be truly hidden if it is not a capabilities symbol.
#define SYM_IS_HIDDEN(_sdp) \
(((_sdp)->sd_flags & (FLG_SY_HIDDEN | FLG_SY_CAP)) == FLG_SY_HIDDEN)
// Create a mask for (sym.st_other & visibility) since the gABI does not yet define a ELF*_ST_OTHER macro.
#define MSK_SYM_VISIBILITY 0x7
// Structure to manage the shared object definition lists. There are two lists
// that use this structure:
//
// - ofl_soneed; maintain the list of implicitly required dependencies
// (ie. shared objects needed by other shared objects). These definitions
// may include RPATH's required to locate the dependencies, and any
// version requirements.
//
// - ofl_socntl; maintains the shared object control definitions. These are
// provided by the user (via a mapfile) and are used to indicate any
// version control requirements.
struct sdf_desc {
const char *sdf_name; // the shared objects file name
char *sdf_rpath; // library search path DT_RPATH
const char *sdf_rfile; // referencing file for diagnostics
input_fd_t *sdf_file; // the final input file descriptor
Alist *sdf_vers; // list of versions that are required from this object
Alist *sdf_verneed; // list of VERNEEDS to create for object via mapfile ADDVERS
ElfW(Word) sdf_flags;
};
#define FLG_SDF_SELECT 0x01 // version control selection required
#define FLG_SDF_VERIFY 0x02 // version definition verification required
#define FLG_SDF_ADDVER 0x04 // add VERNEED references
// Structure to manage shared object version usage requirements.
struct sdv_desc {
const char *sdv_name; // version name
const char *sdv_ref; // versions reference
ElfW(Word) sdv_flags; // flags
};
#define FLG_SDV_MATCHED 0x01 // VERDEF found and matched
// Structures to manage versioning information. Two versioning structures are defined:
//
// - a version descriptor maintains a linked list of versions and their
// associated dependencies. This is used to build the version definitions
// for an image being created (see map_symbol), and to determine the
// version dependency graph for any input files that are versioned.
//
// - a version index array contains each version of an input file that is
// being processed. It informs us which versions are available for
// binding, and is used to generate any version dependency information.
struct version_desc_t {
const char *vd_name; // version name
input_fd_t *vd_file; // file that defined version
ElfW(Word) vd_hash; // hash value of name
ElfW(Half) vd_ndx; // coordinates with symbol index
ElfW(Half) vd_flags; // version information
APlist *vd_deps; // version dependencies
version_desc_t *vd_ref; // dependency's first reference
};
struct VersionIndex {
const char *vi_name; // dependency version name
ElfW(Half) vi_flags; // communicates availability
ElfW(Half) vi_overndx; // index assigned to this version in output object Verneed section
version_desc_t *vi_desc; // cross reference to descriptor
};
// Define any internal version descriptor flags ([vd|vi]_flags). Note that the
// first byte is reserved for user visible flags (refer VER_FLG's in link.h).
#define MSK_VER_USER 0x0f // mask for user visible flags
#define FLG_VER_AVAIL 0x10 // version is available for binding
#define FLG_VER_REFER 0x20 // version has been referenced
#define FLG_VER_CYCLIC 0x40 // a member of cyclic dependency
// isalist(1) descriptor - used to break an isalist string into its component options.
struct isa_opt {
char *isa_name; // individual isa option name
size_t isa_namesz; // and associated size
};
struct isa_desc {
char *isa_list; // sysinfo(SI_ISALIST) list
size_t isa_listsz; // and associated size
Isa_opt *isa_opt; // table of individual isa options
size_t isa_optno; // and associated number
};
// uname(2) descriptor - used to break a utsname structure into its component
// options (at least those that we're interested in).
//
// Note: The acronym 'uts' means Unix Time Sharing and refers to the Solaris kernel.
// Maybe "linux_desc" would be more appropriate?
struct uts_desc {
char *uts_osname; // operating system name
size_t uts_osnamesz; // and associated size
char *uts_osrel; // operating system release
size_t uts_osrelsz; // and associated size
};
// SHT_GROUP descriptor - used to track group sections at the global
// level to resolve conflicts and determine which to keep.
struct group_descriptor {
input_sd_t *gd_isc; // input section descriptor
input_sd_t *gd_oisc; // overriding input section descriptor when discarded
const char *gd_name; // group name (signature symbol)
ElfW(Word) *gd_data; // data for group section
size_t gd_cnt; // number of entries in group data
};
// Indexes into the ld_support_funcs[] table.
typedef enum {
LDS_VERSION = 0, // Must be first and have value 0
LDS_INPUT_DONE,
LDS_START,
LDS_ATEXIT,
LDS_OPEN,
LDS_FILE,
LDS_INSEC,
LDS_SEC,
LDS_NUM
} SupportIndex;
// Structure to manage archive member caching. Each archive has an archive
// descriptor (Ar_desc) associated with it. This contains pointers to the
// archive symbol table (obtained by elf_getarsyms(3e)) and an auxiliary
// structure (Ar_uax[]) that parallels this symbol table. The member element
// of this auxiliary table indicates whether the archive member associated with
// the symbol offset has already been extracted (AREXTRACTED) or partially
// processed (refer process_member()).
typedef struct ar_mem {
Elf *am_elf; // elf descriptor for this member
const char *am_name; // members name
const char *am_path; // path (ie. lib(foo.o))
ElfW(Sym) *am_syms; // start of global symbols
char *am_strs; // associated string table start
ElfW(Xword) am_symn; // no. of global symbols
} ar_member_t;
typedef struct ar_aux {
symbol_desc *au_syms; // internal symbol descriptor
ar_member_t *au_mem; // associated member
} ar_aux_t;
#define FLG_ARMEM_PROC (Ar_mem *)-1
typedef struct ar_desc {
const char *ad_name; // archive file name
Elf *ad_elf; // elf descriptor for the archive
Elf_Arsym *ad_start; // archive symbol table start
Ar_aux *ad_aux; // auxiliary symbol information
dev_t ad_stdev; // device id and inode number for
ino_t ad_stino; // multiple inclusion checks
ofl_flag_t ad_flags; // archive specific cmd line flags
} ar_desc_t;
// Define any archive descriptor flags. NOTE, make sure they do not clash with
// any output file descriptor archive extraction flags, as these are saved in
// the same entry (see MSK_OF1_ARCHIVE).
#define FLG_ARD_EXTRACT 0x00010000 // archive member has been extracted
// Mapfile versions supported by libld
#define MFV_NONE 0 // Not a valid version
#define MFV_SYSV 1 // Original System V syntax
#define MFV_SOLARIS 2 // Solaris mapfile syntax
#define MFV_NUM 3 // # of mapfile versions
extern int ld_getopt(Lm_list *, int, int, char **);
extern int ld_main(int, char **, ElfW(Half));
extern uintptr_t ld_create_outfile(output_fd_t *);
extern uintptr_t ld_ent_setup(output_fd_t *, Xword);
extern uintptr_t ld_init_strings(output_fd_t *);
extern int ld_init_target(Lm_list *, ElfW(Half) mach);
extern uintptr_t ld_make_sections(output_fd_t *);
extern void ld_ofl_cleanup(output_fd_t *);
extern input_fd_t *ld_process_mem(const char *, const char *, char *, size_t, output_fd_t *, Rej_desc *);
extern uintptr_t ld_reloc_init(output_fd_t *);
extern uintptr_t ld_reloc_process(output_fd_t *);
extern uintptr_t ld_sym_validate(output_fd_t *);
extern uintptr_t ld_update_outfile(output_fd_t *);
#ifdef __cplusplus
}
#endif
#endif /* _LIBLD_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment