linker and libraries guide - oraclethe open look and suntm graphical user interface was developed by...

273
Linker and Libraries Guide Sun Microsystems, Inc. 2550 Garcia Avenue Mountain View, CA 94043-1100 U.S.A. Part No: 802-6319 August 1997

Upload: others

Post on 20-Mar-2020

25 views

Category:

Documents


0 download

TRANSCRIPT

Linker and Libraries Guide

Sun Microsystems, Inc.2550 Garcia Avenue

Mountain View, CA 94043-1100U.S.A.

Part No: 802-6319August 1997

Copyright 1997 Sun Microsystems, Inc. 901 San Antonio Road, Palo Alto, California 94303-4900 U.S.A. All rights reserved.This product or document is protected by copyright and distributed under licenses restricting its use, copying, distribution, anddecompilation. No part of this product or document may be reproduced in any form by any means without prior written authorization ofSun and its licensors, if any. Third-party software, including font technology, is copyrighted and licensed from Sun suppliers.Parts of the product may be derived from Berkeley BSD systems, licensed from the University of California. UNIX is a registeredtrademark in the U.S. and other countries, exclusively licensed through X/Open Company, Ltd.Sun, Sun Microsystems, the Sun logo, SunSoft, SunDocs, SunExpress, and Solaris are trademarks, registered trademarks, or service marksof Sun Microsystems, Inc. in the U.S. and other countries. All SPARC trademarks are used under license and are trademarks or registeredtrademarks of SPARC International, Inc. in the U.S. and other countries. Products bearing SPARC trademarks are based upon anarchitecture developed by Sun Microsystems, Inc.The OPEN LOOK and SunTM Graphical User Interface was developed by Sun Microsystems, Inc. for its users and licensees. Sunacknowledges the pioneering efforts of Xerox in researching and developing the concept of visual or graphical user interfaces for thecomputer industry. Sun holds a non-exclusive license from Xerox to the Xerox Graphical User Interface, which license also covers Sun’slicensees who implement OPEN LOOK GUIs and otherwise comply with Sun’s written license agreements.

RESTRICTED RIGHTS: Use, duplication, or disclosure by the U.S. Government is subject to restrictions of FAR 52.227–14(g)(2)(6/87) andFAR 52.227–19(6/87), or DFAR 252.227–7015(b)(6/95) and DFAR 227.7202–3(a).DOCUMENTATION IS PROVIDED “AS IS” AND ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ORNON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD TO BE LEGALLYINVALID.

Copyright 1997 Sun Microsystems, Inc. 901 San Antonio Road, Palo Alto, Californie 94303-4900 Etats-Unis. Tous droits réservés.

Ce produit ou document est protégé par un copyright et distribué avec des licences qui en restreignent l’utilisation, la copie, ladistribution, et la décompilation. Aucune partie de ce produit ou document ne peut être reproduite sous aucune forme, par quelquemoyen que ce soit, sans l’autorisation préalable et écrite de Sun et de ses bailleurs de licence, s’il y en a. Le logiciel détenu par des tiers, etqui comprend la technologie relative aux polices de caractères, est protégé par un copyright et licencié par des fournisseurs de Sun.Des parties de ce produit pourront être dérivées du système Berkeley BSD licenciés par l’Université de Californie. UNIX est une marquedéposée aux Etats-Unis et dans d’autres pays et licenciée exclusivement par X/Open Company, Ltd.Sun, Sun Microsystems, le logo Sun, SunSoft, SunDocs, SunExpress, et Solaris sont des marques de fabrique ou des marques déposées, oumarques de service, de Sun Microsystems, Inc. aux Etats-Unis et dans d’autres pays. Toutes les marques SPARC sont utilisées sous licenceet sont des marques de fabrique ou des marques déposées de SPARC International, Inc. aux Etats-Unis et dans d’autres pays. Les produitsportant les marques SPARC sont basés sur une architecture développée par Sun Microsystems, Inc.L’interface d’utilisation graphique OPEN LOOK et SunTM a été développée par Sun Microsystems, Inc. pour ses utilisateurs et licenciés.Sun reconnaît les efforts de pionniers de Xerox pour la recherche et le développement du concept des interfaces d’utilisation visuelle ougraphique pour l’industrie de l’informatique. Sun détient une licence non exclusive de Xerox sur l’interface d’utilisation graphique Xerox,cette licence couvrant également les licenciés de Sun qui mettent en place l’interface d’utilisation graphique OPEN LOOK et qui en outrese conforment aux licences écrites de Sun.CETTE PUBLICATION EST FOURNIE “EN L’ETAT” ET AUCUNE GARANTIE, EXPRESSE OU IMPLICITE, N’EST ACCORDEE, YCOMPRIS DES GARANTIES CONCERNANT LA VALEUR MARCHANDE, L’APTITUDE DE LA PUBLICATION A REPONDRE A UNEUTILISATION PARTICULIERE, OU LE FAIT QU’ELLE NE SOIT PAS CONTREFAISANTE DE PRODUIT DE TIERS. CE DENI DEGARANTIE NE S’APPLIQUERAIT PAS, DANS LA MESURE OU IL SERAIT TENU JURIDIQUEMENT NUL ET NON AVENU.

PleaseRecycle

Contents

Preface ix

1. Introduction 1

Overview 1

Link-Editing 2

Runtime Linking 3

Dynamic Executables 4

Shared Objects 4

Related Topics 4

Dynamic Linking 4

Application Binary Interfaces 5

Support Tools 5

New Features 5

2. Link-Editor 7

Overview 7

Invoking the Link-Editor 8

Direct Invocation 8

Using a Compiler Driver 9

Specifying the Link-Editor Options 9

Input File Processing 10

Contents iii

Archive Processing 11

Shared Object Processing 12

Linking with Additional Libraries 13

Initialization and Termination Sections 17

Symbol Processing 18

Symbol Resolution 19

Undefined Symbols 24

Tentative Symbol Order Within the Output File 27

Defining Additional Symbols 28

Reducing Symbol Scope 33

Generating the Output Image 37

Debugging Aids 38

3. Runtime Linker 43

Overview 43

Locating Shared Object Dependencies 44

Directories Searched by the Runtime Linker 44

Relocation Processing 46

Symbol Lookup 47

When Relocations are Performed 48

Relocation Errors 49

Loading Additional Objects 51

Initialization and Termination Routines 52

Security 53

Runtime Linking Programming Interface 54

Loading Additional Objects 55

Relocation Processing 57

Obtaining New Symbols 63

Debugging Aids 67

iv Linker and Libraries Guide ♦ August 1997

4. Shared Objects 71

Overview 71

Naming Conventions 72

Recording a Shared Object Name 73

Shared Objects with Dependencies 76

Dependency Ordering 77

Shared Objects as Filters 78

Generating a Standard Filter 78

Generating an Auxiliary Filter 81

Filtee Processing 83

Performance Considerations 83

Useful Tools 83

The Underlying System 86

Position-Independent Code 86

Maximizing Shareability 88

Minimizing Paging Activity 90

Relocations 90

Profiling Shared Objects 95

5. Versioning 97

Overview 97

Interface Compatibility 98

Internal Versioning 99

Creating a Version Definition 99

Binding to a Version Definition 105

Specifying a Version Binding 109

Relocatable Objects 114

External Versioning 114

Coordination of Versioned Filenames 114

Contents v

6. Support Interfaces 117

Overview 117

Link-Editor Support Interface 117

Invoking the Support Interface 118

Support Interface Functions 118

Support Interface Example 120

Runtime Linker Auditing Interface 122

Establishing a Name-space 123

Building an Audit Library 123

Invoking the Auditing Interface 124

Audit Interface Functions 124

Audit Interface Example 128

Audit Interface Demonstrations 128

Audit Interface Limitations 129

Runtime Linker Debugger Interface 130

Interaction Between Controlling and Target Process 130

Debugger Interface Agents 132

Debugger Exported Interface 132

Debugger Import Interface 141

7. Object Files 145

Overview 145

File Format 146

Data Representation 147

ELF Header 148

ELF Identification 152

Sections 155

Special Sections 166

String Table 170

vi Linker and Libraries Guide ♦ August 1997

Symbol Table 171

Relocation 177

Versioning Information 187

Note Section 193

Dynamic Linking 195

Program Header 195

Program Loading (Processor-Specific) 201

Runtime Linker 208

Hash Table 223

Initialization and Termination Functions 224

8. Mapfile Option 225

Overview 225

Using the Mapfile Option 226

Mapfile Structure and Syntax 226

Segment Declarations 227

Mapping Directives 230

Size-Symbol Declarations 232

File Control Directives 233

Mapping Example 233

Mapfile Option Defaults 235

Internal Map Structure 236

Error Messages 238

Warnings 238

Fatal Errors 238

A. Link-Editor Quick Reference 241

Overview 241

Static Mode 241

Building a Relocatable Object 242

Contents vii

Building a Static Executable 242

Dynamic Mode 242

Building a Shared Object 242

Building a Dynamic Executable 244

B. Versioning Quick Reference 245

Overview 245

Naming Conventions 246

Defining a Shared Object’s Interface 247

Versioning a Shared Object 248

Versioning an Existing (Non-versioned) Shared Object 248

Updating a Versioned Shared Object 249

Adding New Symbols 250

Internal Implementation Changes 250

New Symbols and Internal Implementation Changes 251

Migrating Symbols to a Standard Interface 251

Index 255

viii Linker and Libraries Guide ♦ August 1997

Preface

Solaris TM provides an environment in which application developers can buildapplications and libraries using the link-editor ld (1), and execute these utilities withthe aid of the runtime linker ld.so.1 (1). For many application developers, the factthat the link-editor is called via the compilation system, and that the runtime linkermay play a part in the execution of their application, is mildly interesting. Thismanual is for those who wish to understand more fully the concepts involved.

About This ManualThis manual describes the operations of the Solaris link-editor and runtime linker.Special emphasis is placed on the generation and use of shared objects because oftheir importance in a dynamic runtime environment.

Intended AudienceThis manual is intended for a range of programmers who are interested in theSolaris linkers, from the curious beginner to the advanced user:

� Beginners learn the principle operations of the link-editor and runtime linker.

� Intermediate programmers learn to build, and use, efficient custom libraries.

� Advanced programmers, such as language-tools developers, learn how to interpretand generate object files.

Not many programmers should find it necessary to read this manual from cover tocover.

Preface ix

OrganizationChapter 1 gives an overview of the linking processes under Solaris , together withan introduction of new features added with this release. This chapter is intended forall programmers.

Chapter 2 describes the functions of the link-editor, its two modes of linking (staticand dynamic), scope and forms of input, and forms of output. This chapter isintended for all programmers.

Chapter 3 describes the execution environment and program-controlled runtimebinding of code and data. This chapter is intended for all programmers.

Chapter 4 gives definitions of shared objects, describes their mechanisms, andexplains how to build and use them. This chapter is intended for all programmers.

Chapter 5 describes how to manage the evolution of an interface provided by adynamic object. This chapter is intended for all programmers.

Chapter 6 describes interfaces for monitoring, and in some cases modifying,link-editor and runtime linker processing. This chapter is intended for advancedprogrammers.

Chapter 7 is a reference chapter on ELF files. This chapter is intended for advancedprogrammers.

Chapter 8 describes the mapfile directives to the link-editor, which specify the layoutof the output file. This chapter is intended for advanced programmers.

Appendix A gives an overview of the most commonly used link-editor options, andis intended for all programmers.

Appendix B gives naming conventions and guidelines for versioning shared objects,and is intended for all programmers.

Throughout this document, all command-line examples use sh (1) syntax, and allprogramming examples are written in the C language.

Note - The term “x86” refers to the Intel 8086 family of microprocessor chips,including the Pentium and Pentium Pro processors and compatible microprocessorchips made by AMD and Cyrix. In this document, the term “x86” refers to the overallplatform architecture, whereas “Intel Platform Edition” appears in the product name.

Ordering Sun DocumentsThe SunDocsSM program provides more than 250 manuals from Sun Microsystems,Inc. If you live in the United States, Canada, Europe, or Japan, you can purchasedocumentation sets or individual manuals using this program.

x Linker and Libraries Guide ♦ August 1997

For a list of documents and how to order them, see the catalog section of theSunExpressTM Internet site at http://www.sun.com/sunexpress .

xi

xii Linker and Libraries Guide ♦ August 1997

CHAPTER 1

Introduction

OverviewThis manual describes the operations of the Solaris link-editor and runtime linker,together with the objects on which they operate. The basic operation of the Solarislinkers involves the combination of objects and the connection of symbolic referencesfrom one object to the symbolic definitions within another. This operation is oftenreferred to as binding.

The main areas this manual expands upon are:

Link-Editor

The link-editor, ld (1), concatenates one or more input files (either relocatable objects,shared objects, or archive libraries) to produce one output file (either a relocatableobject, an executable application, or a shared object). The link-editor is mostcommonly invoked as part of the compilation environment (see cc (1)).

Runtime Linker

The runtime linker, ld.so.1 (1)1, processes dynamic executables and shared objectsat runtime, and binds them to create a runable process.

1. ld.so.1 is a special case of a shared object and therefore allows itself to be versioned. Here a version number of 1is used, however later releases of Solaris might provide higher version numbers.

1

Shared Objects

Shared objects (sometimes referred to as Shared Libraries) are one form of output fromthe link-edit phase. However, their importance in creating a powerful, flexibleruntime environment warrants a section of its own.

Object Files

The Solaris linkers work with files that conform to the executable and linkingformat (ELF).

These areas, although separable into individual topics, have a great deal of overlap.While explaining each area, this document brings together the connecting principlesand designs.

Link-EditingLink-editing takes a variety of input files, from cc (1), as (1) or ld (1), andconcatenates and interprets the data within these input files to form a single outputfile. Although the link-editor provides numerous options, the output file produced isone of four basic types:

Relocatable object

A concatenation of input relocatable objects, which can be used in subsequentlink-edit phases.

Static executable

A concatenation of input relocatable objects that has all symbolic references bound tothe executable, and thus represents a ready-to-run process.

Dynamic executable

A concatenation of input relocatable objects that requires intervention by the runtimelinker to produce a runable process. Its symbolic references might still need to bebound at runtime, and it might have one or more dependencies in the form of sharedobjects.

2 Linker and Libraries Guide ♦ August 1997

Shared object

A concatenation of input relocatable objects that provides services that might bebound to a dynamic executable at runtime. The shared object might also havedependencies on other shared objects.

These output files, and the key link-editor options used to create them, are shown inFigure 1–1.

Dynamic executables and shared objects, are often referred to jointly as dynamic objects,and are the main focus of this document.

ld

-dn -dy

-r -G

Relocatable object

Static executable

Dynamic executable

Shared object

Figure 1–1 Static or Dynamic Link-editing

Runtime LinkingRuntime linking involves the binding of objects, usually generated from one or moreprevious link-edits, to generate a runable process. During the generation of theseobjects by the link-editor, the binding requirements are verified and appropriatebookkeeping information is added to each object to allow the runtime linker to map,relocate, and complete the binding process.

During the execution of the process, the facilities of the runtime linker are also madeavailable and can be used to extend the process’ address space by adding additionalshared objects on demand. The two most common components involved in runtimelinking are dynamic executables and shared objects.

Introduction 3

Dynamic ExecutablesDynamic executables are applications that are executed under the control of aruntime linker. These applications usually have dependencies in the form of sharedobjects, which are located and bound by the runtime linker to create a runableprocess. Dynamic executables are the default output file generated by the link-editor.

Shared ObjectsShared objects provide the key building block to a dynamically linked system.Basically, a shared object is similar to a dynamic executable, however shared objectshave not yet been assigned a virtual address.

Dynamic executables usually have dependencies on one or more shared objects. Thatis, the shared object(s) must be bound to the dynamic executable to produce arunable process. Because shared objects can be used by many applications, aspects oftheir construction directly affect shareability, versioning and performance.

It is useful to distinguish the processing of shared objects by either the link-editor orthe runtime linker by referring to the environments in which the shared objects arebeing used:

compilation environment

Shared objects are processed by the link-editor to generate dynamic executables orother shared objects. The shared objects become dependencies of the output file beinggenerated.

runtime environment

Shared objects are processed by the runtime linker, together with a dynamicexecutable, to produce a runable process.

Related TopicsDynamic LinkingDynamic linking is a term often used to embrace those portions of the link-editingprocess that generate dynamic executables and shared objects, together with theruntime linking of these objects to generate a runable process. Dynamic linkingallows multiple applications to use the code provided by a shared object by enablingthe application to bind to the shared object at runtime.

4 Linker and Libraries Guide ♦ August 1997

By separating an application from the services of standard libraries, dynamic linkingalso increases the portability and extensibility of an application. This separationbetween the interface of a service and its implementation enables the system to evolvewhile maintaining application stability, and is a crucial factor in providing anapplication binary interface (ABI). Dynamic linking is the preferred compilation methodfor Solaris applications.

Application Binary InterfacesTo enable the asynchronous evolution of system and application components, binaryinterfaces between these facilities are defined. The Solaris linkers operate uponthese interfaces to assemble applications for execution. Although all componentshandled by the Solaris linkers have binary interfaces, one family of such interfacesof particular interest to applications writers is the System V Application BinaryInterface.

The System V Application Binary Interface, or ABI, defines a system interface forcompiled application programs. Its purpose is to document a standard binaryinterface for application programs on systems that implement the System V InterfaceDefinition, Third Edition. Solaris provides for the generation and execution ofABI-conforming applications. On SPARC systems, the ABI is contained as a subset ofthe SPARC ® Compliance Definition (SCD).

Many of the topics covered in the following chapters are influenced by the ABI. Formore detailed information see the appropriate ABI manuals.

Support ToolsTogether with the objects mentioned in the previous sections come several supporttools and libraries. These tools provide for the analysis and inspection of theseobjects and the linking processes. Among these tools are: nm(1), dump(1), ldd (1),pvs (1), elf (3E), and a linker debugging support library. Throughout this documentmany discussions are augmented with examples of these tools use.

New FeaturesThis section gives an overview of new features and/or updates to this document thatare available with the Solaris 2.6 release:

� Weak symbol references can trigger archive member extraction by using thelink-editor −z weakextract option. Extracting all archive members can beachieved using the −z allextract option. See “Archive Processing” on page 11.

Introduction 5

� Shared objects specified as part of a link-edit that are not referenced by the objectbeing built, can be ignored, and hence their dependency recording suppressed,using the −z ignore option. See “Shared Object Processing” on page 12.

� The link-editor generates the reserved symbols _START_and _END_to provide ameans of establishing an objects address range. See “Generating the OutputImage” on page 37.

� Changes have been made to the runtime ordering of initialization and finalizationcode to better accommodate dependency requirements. See “Initialization andTermination Routines” on page 52.

� Symbol resolution semantics have been expanded for dlopen (3X). See “SymbolLookup” on page 57, RTLD_GROUPin “Isolating a Group” on page 62, andRTLD_PARENTin “Object Hierarchies” on page 62.

� Symbol lookup semantics have been expanded with a new dlsym (3X) handleRTLD_DEFAULT. See “Obtaining New Symbols” on page 63.

� Extensions have been made to filter processing that allow more than one filtee to bedefined, and provide for forcibly loading filtees. An example of creating a platformspecific filter is also provided. See “Shared Objects as Filters” on page 78.

� Recording additional version dependencies can be achieved using the mapfilefile control directive $ADDVERS. See “Binding to Additional Version Definitions”on page 111.

� A runtime linker audit interface provides support for monitoring and modifying adynamically linked application from within the process. See “Runtime LinkerAuditing Interface” on page 122.

� A runtime linker debugger interface provides support for monitoring andmodifying a dynamically linked application from an external process. See“Runtime Linker Debugger Interface” on page 130.

� Additional section types are supported. See Table 7–9 for SHN_BEFOREandSHN_AFTER, and see Table 7–12 for SHF_ORDEREDand SHF_EXCLUDE.

� A new dynamic section tag, DT_1_FLAGS, is supported. See Table 7–35 for thevarious flag values.

� A package of demonstration ELF programs is provided. See Chapter 7.

� The link-editors now support internationalized messages. All system errors arereported using strerror (3C).

6 Linker and Libraries Guide ♦ August 1997

CHAPTER 2

Link-Editor

OverviewThe link-editing process builds an output file from one or more input files. Thebuilding of the output file is directed by the options supplied to the link-editortogether with the input sections provided by the input files.

All files are represented in the executable and linking format (ELF). For a completedescription of the ELF format see Chapter 7. For this introduction, however, it is firstnecessary to introduce two ELF structures, sections and segments.

Sections are the smallest indivisible units that can be processed within an ELF file.Segments are a collection of sections that represent the smallest individual units thatcan be mapped to a memory image by exec (2) or by the runtime linkerld.so.1 (1).

Although there are many types of ELF sections, they all fall into two categories withrespect to the link-editing phase:

� Sections that contain program data, whose interpretation is meaningful only to theapplication itself (such as the program instructions .text and the associated data.data and .bss ).

� Sections that contain link-editing information (such as the symbol table informationfound from .symtab and .strtab , and relocation information such as.rela.text ).

Basically, the link-editor concatenates the program data sections into the output file.The link-editing information sections are interpreted by the link-editor to modify othersections or to generate new output information sections used in later processing ofthe output file.

7

The following simple breakdown of link-editor functionality introduces the topicscovered in this chapter:

� It verifies and checks for consistency all the options passed to it.

� It concatenates sections of the same characteristics (for example, type, attributesand name) from the input relocatable objects to form new sections within theoutput file. These concatenated sections can in turn be associated to outputsegments.

� It reads symbol table information from both relocatable objects and shared objectsto verify and unite references with definitions, and usually generates a newsymbol table, or tables, within the output file.

� It reads relocation information from the input relocatable objects and applies thisinformation to the output file by updating other input sections. In addition, outputrelocation sections might be generated for use by the runtime linker.

� It generates program headers that describe any segments created.

� It generates a dynamic linking information section if necessary, which providesinformation such as shared object dependencies to the runtime linker.

The process of concatenating like sections and associating sections to segments iscarried out using default information within the link-editor. The default section andsegment handling provided by the link-editor is usually sufficient for most link-edits.However, these defaults can be manipulated using the −Moption with an associatedmapfile (see Chapter 8 for more details).

Invoking the Link-EditorYou can either run the link-editor directly from the command-line or have a compilerdriver invoke it for you. In the following two sections both methods are expandedupon. However, the latter is the preferred choice, as the compilation environment isoften the consequence of a complex and occasionally changing series of operationsknown only to compiler drivers.

Direct InvocationWhen you invoke the link-editor directly, you have to supply every object file andlibrary required to build the intended output. The link-editor makes no assumptionsabout the object modules or libraries you meant to use in building the output. Forexample, when you issue the command:

$ ld test.o

8 Linker and Libraries Guide ♦ August 1997

the link-editor builds a dynamic executable named a.out using only the input filetest.o . For the a.out to be a useful executable, it should include start-up and exitprocessing code. This code can be language or operating system specific, and isusually provided through files supplied by the compiler drivers.

Additionally, you can also supply your own initialization and termination code. Thiscode must be encapsulated and labeled correctly for it to be correctly recognized andmade available to the runtime linker. This encapsulation and labeling is alsoprovided through files supplied by the compiler drivers.

In practice, when creating runtime objects such as executables and shared objects, itis recommended that a compiler driver be used to invoke the link-editor. Invokingthe link-editor directly is only recommended when creating intermediate relocatableobjects using the −r option.

Using a Compiler DriverThe conventional way to use the link-editor is through a language-specific compilerdriver. You supply the compiler driver, cc (1), f77 (1), etc., with the input files thatmake up your application, and the compiler driver adds additional files and defaultlibraries to complete the link-edit. These additional files can be seen by expandingthe compilation invocation, for example:

$ cc -# -o prog main.o/usr/ccs/bin/ld -dy /opt/COMPILER/crti.o /opt/COMPILER/crt1.o \/usr/ccs/lib/values-Xt.o -o prog main.o \-YP,/opt/COMPILER/lib:/usr/ccs/lib:/usr/lib -Qy -lc \/opt/COMPILER/crtn.o

Note - This is an example; the actual files included by your compiler driver and themechanism used to display the link-editor invocation might differ.

Specifying the Link-Editor OptionsMost options to the link-editor can be passed through the compiler drivercommand-line. For the most part the compiler and the link-editor options do notconflict. Where a conflict arises, the compiler drivers usually provide acommand-line syntax that allows you to pass specific options to the link-editor.However, you can instead provide options to the link-editor by setting theLD_OPTIONSenvironment variable. For example:

Link-Editor 9

$ LD_OPTIONS="-R /home/me/libs -L /home/me/libs" cc -o prog \ main.c -lfoo

Here the −R and −L options will be interpreted by the link-editor and prepended toany command-line options received from the compiler driver.

The link-editor parses the entire option list looking for any invalid options or anyoptions with invalid associated arguments. When either of these cases is found, asuitable error message is generated, and when the error is deemed fatal the link-editterminates. For example:

$ ld -X -z sillydefs main.old: illegal option -- Xld: fatal: option -z has illegal argument ‘sillydefs’

Here the illegal option −X is identified, and the illegal argument to the −z option iscaught by the link-editor’s checking. If an option requiring an associated argument ismistakenly specified twice the link-editor will provide a suitable warning but willcontinue with the link-edit. For example:

$ ld -e foo ...... -e bar main.old: warning: option -e appears more than once, first setting taken

The link-editor also checks the option list for any fatal inconsistencies. For example:

$ ld -dy -a main.old: fatal: option -dy and -a are incompatible

After processing all options, and if no fatal error conditions have been detected, thelink-editor proceeds to process the input files.

See Appendix A for the most commonly used link-editor options, and the ld (1)manual page for a complete description of all link-editor options.

Input File ProcessingThe link-editor reads input files in the order in which they appear on thecommand-line. Each file is opened and inspected to determine its ELF file type andso determine how it must be processed. The file types applicable as input for thelink-edit are determined by the binding mode of the link-edit, either static or dynamic.

10 Linker and Libraries Guide ♦ August 1997

Under static mode the link-editor will accept only relocatable objects or archivelibraries as input files. Under dynamic mode the link-editor will also accept sharedobjects.

Relocatable objects represent the most basic input file type to the link-editing process.The program data sections within these files are concatenated into the output fileimage being generated. The link-edit information sections are organized for later use,but will not become part of the output file image, as new sections will be generatedto take their places. Symbols are gathered into a special internal symbol table thatallows for their verification and resolution, and eventually for the creation of one ormore symbol tables in the output image.

Although any input file can be specified directly on the link-edit command-line,archive libraries and shared objects are commonly specified using the −l option (see“Linking with Additional Libraries” on page 13 for coverage of this mechanism andhow it relates to the two different linking modes). However, even though sharedobjects are often referred to as shared libraries, and both of these objects can bespecified using the same option, the interpretation of shared objects and archivelibraries is quite different. The next two sections expand upon these differences.

Archive ProcessingArchives are built using ar (1), and usually consist of a collection of relocatableobjects with an archive symbol table. This symbol table provides an association ofsymbol definitions with the objects that supply these definitions. By default, thelink-editor provides selective extraction of archive members. When the link-editorreads an archive, it uses information within the internal symbol table it is creating toselect only the objects from the archive it requires to complete the binding process. Itis also possible to explicitly extract all member of an archive.

The link-editor will extract a relocatable object from an archive if:

� The archive contains a symbol definition that satisfies a symbol reference(sometimes referred to as an undefined symbol) presently held in the link-editor’sinternal symbol table.

� The archive contains a data symbol definition that satisfies a tentative symboldefinition presently held in the link-editor’s internal symbol table. An example ofthis is a FORTRAN COMMONblock definition which will cause the extraction of arelocatable object that defines the same DATAsymbol.

� The link-editors −z allextract is in effect. This option suspends selectivearchive extraction and causes all archive members to be extracted from the archivebeing processed.

Under selective archive extraction, a weak symbol reference will not cause theextraction of an object from an archive unless the −z weakextract option is ineffect. Weak symbols are expanded upon in section “Simple Resolutions” on page 20.

Link-Editor 11

Note - The options −z weakextract , −z allextract and −z defaultextractprovide a means to toggle the archive extraction mechanism among multiple archives.

Under selective archive extraction the link-editor will make multiple passes throughan archive extracting relocatable objects as needed to satisfy the symbol informationbeing accumulated in the link-editor internal symbol table. Once the link-editor hasmade a complete pass through the archive without extracting any relocatable objects,it will move on to process the next input file.

This mechanism of extracting from the archive only the relocatable objects needed atthe time the archive was encountered means that the position of the archive withinthe input file list can be significant (see “Position of an Archive on theCommand-Line” on page 14 for more details).

Note - Although the link-editor will make multiple passes through an archive toresolve symbols, this mechanism can be quite costly for large archives containingrandom organizations of relocatable objects. In these cases it is recommended thattools like lorder (1) and tsort (1) be used to order the relocatable objects withinthe archive and so reduce the number of passes the link-editor must carry out.

Shared Object ProcessingShared objects are indivisible, whole units that have been generated by a previouslink-edit of one or more input files. When the link-editor processes a shared objectthe entire contents of the shared object become a logical part of the resulting outputfile image. The shared object is not copied physically during the link-edit as its actualinclusion is deferred until process execution. This logical inclusion means that allsymbol entries defined in the shared object are made available to the link-editingprocess.

The shared object’s program data sections and most of the link-editing informationsections are unused by the link-editor, as these will be interpreted by the runtimelinker when the shared object is bound to generate a runable process. However, theoccurrence of a shared object will be remembered, and information will be stored inthe output file image to indicate that this object is a dependency and must be madeavailable at runtime.

By default, all shared objects specified as part a link-edit are recorded asdependencies in the object being built. This recording is made regardless of whetherthe object being built actually references symbols offered by the shared object. Tominimize runtime linking overhead only those dependencies required to resolvesymbol references from the object being built should be specified as part of thelink-edit. Alternatively, the link-editor’s −z ignore option can be used to suppressthe dependency recording of unused shared objects.

12 Linker and Libraries Guide ♦ August 1997

If a shared object has dependencies on other shared objects, these too will beprocessed. This processing will occur after all command-line input files have beenprocessed. These shared objects will be used to complete the symbol resolutionprocess, however their names will not be recorded as dependencies in the output fileimage being generated.

Although the position of a shared object on the link-edit command-line has lesssignificance than it does for archive processing, it can have a global effect. Multiplesymbols of the same name are allowed to occur between relocatable objects andshared objects, and between multiple shared objects (see “Symbol Resolution” onpage 19 for more details).

The order of shared objects processed by the link-editor is maintained in thedependency information stored in the output file image. As the runtime linker readsthis information it will load the specified shared objects in the same order. Therefore,the link-editor and the runtime linker will select the first occurrence of a symbol of amultiply defined series of symbols.

Note - Multiple symbol definitions, and thus the information to describe theinterposing of one definition of a symbol for another, are reported in the load mapoutput generated using the −moption.

Linking with Additional LibrariesAlthough the compiler drivers will often ensure that appropriate libraries arespecified to the link-editor, it is frequently necessary for you to supply your own.Shared objects and archives can be specified by explicitly naming the input filesrequired to the link-editor, but a more common and more flexible method involvesusing the link-editor’s −l option.

Library Naming ConventionsBy convention, shared objects are usually designated by the prefix lib and the suffix.so , and archives are designated by the prefix lib and the suffix .a . For example,libc.so is the shared object version of the standard C library made available to thecompilation environment, and libc.a is its archive version.

These conventions are recognized by the −l option of the link-editor. This option iscommonly used to supply additional libraries to a link-edit. The following example:

$ cc -o prog file1.c file2.c -lfoo

directs the link-editor to search for libfoo.so , and if it does not find it, to searchfor libfoo.a , before moving on to the next directory to be searched.

Link-Editor 13

Note - There is a naming convention regarding the compilation environment and theruntime environment use of shared objects. The compilation environment uses thesimple .so suffix, whereas the runtime environment commonly uses the suffix withan additional version number. See “Naming Conventions” on page 72 and“Coordination of Versioned Filenames” on page 114 for more details.

When link-editing in dynamic mode, you can choose to link with a mix of sharedobjects and archives. When link-editing in static mode, only archive libraries areacceptable for input.

When in dynamic mode and using the −l option to enable a library search, thelink-editor will first search in a given directory for a shared object that matches thespecified name. If no match is found the link-editor will then look for an archivelibrary in the same directory. When in static mode and using the −l option, onlyarchive libraries will be sought.

Linking with a Mix of Shared Objects and ArchivesAlthough the library search mechanism, in dynamic mode, searches a given directoryfor a shared object, and then an archive library, finer control of the type of searchrequired can be achieved using the −B option.

By specifying the −Bdynamic and −Bstatic options on the command-line, as manytimes as required, the library search can be toggled between shared objects orarchives respectively. For example, to link an application with the archive libfoo.aand the shared object libbar.so , issue the following command:

$ cc -o prog main.o file1.c -Bstatic -lfoo -Bdynamic -lbar

The −Bstatic and −Bdynamic keywords are not exactly symmetrical. When youspecify −Bstatic , the link-editor does not accept shared objects as input until thenext occurrence of −Bdynamic . However, when you specify −Bdynamic , thelink-editor will first look for shared objects and then archives in any given directory.

In the previous example it is more precise to say that the link-editor first searches forlibfoo.a , and then for libbar.so , and if that fails, for libbar.a . Finally, it willsearch for libc.so , and if that fails, libc.a .

Position of an Archive on the Command-LineThe position of an archive on the command-line can affect the output file beingproduced. The link-editor searches an archive only to resolve undefined or tentativeexternal references it has previously seen. Once this search is completed and therequired relocatable objects have been extracted, the archive will not be available to

14 Linker and Libraries Guide ♦ August 1997

resolve any new symbols obtained from the input files that follow the archive on thecommand-line. For example, the command

$ cc -o prog file1.c -Bstatic -lfoo file2.c file3.c -Bdynamic

directs the link-editor to search libfoo.a only to resolved symbol references thathave been obtained from file1.c . libfoo.a will not be available to resolvesymbol references from file2.c or file3.c .

Note - As a rule, it is best to specify any archives at the end of the command-lineunless multiple-definition conflicts require you to do otherwise.

Directories Searched by the Link-EditorAll previous examples assumed that the link-editor knows where to search for thelibraries listed on the command-line. By default the link-editor knows of only twostandard places to look for libraries, /usr/ccs/lib and /usr/lib . All otherdirectories to be searched must be added to the link-editor’s search path explicitly.

There are two ways to change the link-editor search path: using a command-lineoption, or using an environment variable.

Using a Command-Line Option

The −L option can be used to add a new pathname to the library search path. Thisoption affects the search path at the point it is encountered on the command-line. Forexample, the command

$ cc -o prog main.o -Lpath1 file1.c -lfoo file2.c -Lpath2 -lbar

searches path1 (then /usr/ccs/lib and /usr/lib ) to find libfoo , but searchespath1 and then path2 (and then /usr/ccs/lib and /usr/lib ) to find libbar .

Pathnames defined using the −L option are used only by the link-editor. They are notrecorded in the output file image created for use by the runtime linker.

Note - You must specify −L if you want the link-editor to search for libraries in yourcurrent directory. You can use a period (.) to represent the current directory.

The −Y option can be used to change the default directories searched by thelink-editor. The argument supplied with this option takes the form of a colonseparated list of directories. For example, the command

$ cc -o prog main.c -YP,/opt/COMPILER/lib:/home/me/lib -lfoo

Link-Editor 15

searches for libfoo only in the directories /opt/COMPILER/lib and/home/me/lib . The directories specified using the −Y option can be supplementedby using the −L option.

Using an Environment VariableYou can also use the environment variable LD_LIBRARY_PATH, which takes acolon-separated list of directories, to add to the link-editor’s library search path. Inits most general form, LD_LIBRARY_PATHtakes two directory lists separated by asemicolon. The first list is searched before the list(s) supplied on the command-line,and the second list is searched after.

Here is the combined effect of setting LD_LIBRARY_PATHand calling the link-editorwith several −L occurrences:

$ LD_LIBRARY_PATH=dir1:dir2;dir3$ export LD_LIBRARY_PATH$ cc -o prog main.c -Lpath1 ... -Lpath2 ... -Lpathn -lfoo

The effective search path will bedir1:dir2:path1:path2... pathn:dir3:/usr/ccs/lib:/usr/lib .

If no semicolon is specified as part of the LD_LIBRARY_PATHdefinition the specifieddirectory list is interpreted after any −L options. For example:

$ LD_LIBRARY_PATH=dir1:dir2$ export LD_LIBRARY_PATH$ cc -o prog main.c -Lpath1 ... -Lpath2 ... -Lpathn -lfoo

Here the effective search path will bepath1:path2... pathn:dir1:dir2:/usr/ccs/lib:/usr/lib .

Note - This environment variable can also be used to augment the search path of theruntime linker (see “Directories Searched by the Runtime Linker” on page 44 formore details). To prevent this environment variable from influencing the link-editorthe −i option can be used.

Directories Searched by the Runtime LinkerThe runtime linker knows of only one standard place to look for libraries,/usr/lib . All other directories to be searched must be added to the runtime linker’ssearch path explicitly.

16 Linker and Libraries Guide ♦ August 1997

When a dynamic executable or shared object is linked with additional shared objects,these shared objects are recorded as dependencies that must be located again duringprocess execution by the runtime linker. During the link-edit, one or more pathnamescan be recorded in the output file. These pathnames will be used by the runtimelinker to search for any shared object dependencies. These recorded pathnames arereferred to as a runpath.

Note - No matter how you modify the runtime linker’s library search path, its lastelement is always /usr/lib .

The −R option, which takes a colon-separated list of directories, can be used to recorda runpath in a dynamic executable or shared library. For example:

$ cc -o prog main.c -R/home/me/lib:/home/you/lib -Lpath1 \ -Lpath2 file1.c file2.c -lfoo -lbar

will record the runpath /home/me/lib:/home/you/lib in the dynamic executableprog . The runtime linker will use these paths, and then the default location/usr/lib , to locate any shared object dependencies. In this case, this runpath willbe used to locate libfoo.so.1 and libbar.so.1 .

The link-editor accepts multiple −R options and will concatenate each of thesespecifications, separated by a colon. Thus, the previous example can also beexpressed as:

$ cc -o prog main.c -R/home/me/lib -Lpath1 \ -R/home/you/lib -Lpath2 file1.c file2.c -lfoo -lbar

Note - A historic alternative to specifying the −R option is to set the environmentvariable LD_RUN_PATH, and make this available to the link-editor. The scope andfunction of LD_RUN_PATHand −R are identical, but when both are specified, −Rsupersedes LD_RUN_PATH.

Initialization and Termination SectionsThe .init and .fini section types provide for runtime initialization andtermination processing. These section types are concatenated from the inputrelocatable objects like any other sections. However, the compiler drivers can alsosupply .init and .fini sections as part of the additional files they add to thebeginning and end of the your input-file list.

These files have the effect of encapsulating the .init and .fini code intoindividual functions that are identified by the reserved symbol names _init and_fini respectively.

Link-Editor 17

When building a dynamic executable or shared object, the link-editor records thesesymbol addresses in the output file’s image so they can be called by the runtimelinker during initialization and termination processing. See “Initialization andTermination Routines” on page 52 for more details on the runtime processing ofthese sections.

The creation of .init and .fini sections can be carried out directly using anassembler, or some compilers can offer special primitives to simplify theirdeclaration. For example, the following code segments result in a call to the functionfoo being placed in an .init section, and a call to the function bar being placed ina .fini section:

#pragma init (foo)#pragma fini (bar)

foo(){

/* Perform some initialization processing. */......

}

bar(){

/* Perform some termination processing. */.......

}

Care should be taken when designing initialization and termination code that can beincluded in both a shared object and archive library. If this code is spread throughoutseveral relocatable objects within an archive library, then the link-edit of anapplication using this archive can extract only a portion of the modules, andtherefore only a portion of the initialization and termination code. At runtime, onlythis portion of code will be executed.

The same application built against the shared object will have all the accumulatedinitialization and termination code executed at runtime when the shared object ismapped in as one of the application’s dependencies.

It is also recommended that data initialization be idempotent if the .init code isinvolved with a dynamic object whose memory may be dumped using dldump (3X).

Symbol ProcessingDuring input file processing, all local symbols from the input relocatable objects arepassed through to the output file image. All global symbols are accumulatedinternally within the link-editor. This internal symbol table is searched for each new

18 Linker and Libraries Guide ♦ August 1997

global symbol entry processed to determine if a symbol with the same name hasalready been encountered from a previous input file. If so, a symbol resolutionprocess is called to determine which of the two entries is to be kept.

On completion of input file processing, and providing no fatal error conditions havebeen encountered during symbol resolution, the link-editor determines if anyunbound symbol references (undefined symbols) remain that will cause the link-editto fail.

Finally, the link-editor’s internal symbol table is added to the symbol table(s) of theimage being created.

The following sections expand upon symbol resolution and undefined symbolprocessing.

Symbol ResolutionSymbol resolution runs the entire spectrum, from simple and intuitive to complexand perplexing. Resolutions can be carried out silently by the link-editor, beaccompanied by warning diagnostics, or result in a fatal error condition.

The resolution of two symbols depends on the symbols’ attributes, the type of fileproviding the symbol and the type of file being generated. For a completedescription of symbol attributes see “Symbol Table” on page 171. For the followingdiscussions, however, it is worth identifying three basic symbol types:

Undefined

These symbols have been referenced in a file but have not been assigned a storageaddress.

Tentative

These symbols have been created within a file but have not yet been sized orallocated in storage. They appear as uninitialized C symbols, or FORTRAN COMMONblocks within the file.

Defined

These symbols have been created and assigned storage addresses and space withinthe file.

In its simplest form, symbol resolution involves the use of a precedence relationshipthat has defined symbols dominating tentative symbols, which in turn dominateundefined symbols.

Link-Editor 19

The following C code example shows how these symbol types can be generated(undefined symbols are prefixed with u_ , tentative symbols are prefixed with t_ ,and defined symbols are prefixed with d_):

$ cat main.cextern int u_bar;extern int u_foo();

int t_bar;int d_bar = 1;

d_foo(){

return (u_foo(u_bar, t_bar, d_bar));}$ cc -o main.o -c main.c$ nm -x main.o

[Index] Value Size Type Bind Other Shndx Name...............[8] |0x00000000|0x00000000|NOTY |GLOB |0x0 |UNDEF |u_foo[9] |0x00000000|0x00000040|FUNC |GLOB |0x0 |2 |d_foo[10] |0x00000004|0x00000004|OBJT |GLOB |0x0 |COMMON |t_bar[11] |0x00000000|0x00000000|NOTY |GLOB |0x0 |UNDEF |u_bar[12] |0x00000000|0x00000004|OBJT |GLOB |0x0 |3 |d_bar

Simple ResolutionsThese symbol resolutions are by far the most common, and result when two symbolswith similar characteristics are detected, and one symbol takes precedence over theother. This symbol resolution is carried out silently by the link-editor. For example,for symbols with the same binding, a reference to an undefined symbol from one filewill be bound to, or satisfied by, a defined or tentative symbol definition from anotherfile. Or, a tentative symbol definition from one file will be bound to a defined symboldefinition from another file.

Symbols that undergo resolution can have either a global or weak binding. Weakbindings have less precedence than global binding, and so symbols with differentbindings are resolved according to a slight alteration of the basic rules. But first, it isworth introducing how weak symbols can be produced.

Weak symbols can be defined individually or as aliases to global symbols using apragma definition:

$ cat main.c#pragma weak bar#pragma weak foo = _foo

int bar = 1;

(continued)

20 Linker and Libraries Guide ♦ August 1997

(Continuation)

_foo(){

return (bar);}$ cc -o main.o -c main.c$ nm -x main.o

[Index] Value Size Type Bind Other Shndx Name...............[7] |0x00000000|0x00000004|OBJT |WEAK |0x0 |3 |bar[8] |0x00000000|0x00000028|FUNC |WEAK |0x0 |2 |foo[9] |0x00000000|0x00000028|FUNC |GLOB |0x0 |2 |_foo

Notice that the weak alias foo is assigned the same attributes as the global symbol_foo . This relationship will be maintained by the link-editor and will result in thesymbols being assigned the same value in the output image.

In symbol resolution, weak defined symbols will be silently overridden by any globaldefinition of the same name.

Another form of simple symbol resolution occurs between relocatable objects andshared objects, or between multiple shared objects, and is termed interposition. Inthese cases, if a symbol is multiply defined, the relocatable object, or the firstdefinition between multiple shared objects, will be silently taken by the link-editor.The relocatable object’s definition, or the first shared object’s definition, is said tointerpose on all other definitions. This interposition can be used to override thefunctionality provided by one shared object by a dynamic executable or anothershared object.

The combination of weak symbols and interposition provides a very usefulprogramming technique. For example, the standard C library provides severalservices that you are allowed to redefine. However, ANSI C defines a set of standardservices that must be present on the system and cannot be replaced in a strictlyconforming program.

The function fread (3S), for example, is an ANSI C library function, whereas thesystem function read (2) is not. A conforming ANSI C program must be able toredefine read (2), and still use fread (3S) in a predictable way.

The problem here is that read (2) underlies the fread (3S) implementation in thestandard C library, and so it would seem that a program that redefines read (2)might confuse the fread (3S) implementation. To guard against this, ANSI C statesthat an implementation cannot use a name that is not reserved to it, and by using thepragma directive shown below:

#pragma weak read = _read

Link-Editor 21

you can define just such a reserved name, and from it generate an alias for thefunction read (2). Thus, you can quite freely define your own read( ) functionwithout compromising the fread (3S) implementation, which in turn isimplemented to use the _read() function.

The link-editor will not complain of your redefinition of read() , either whenlinking against the shared object or archive version of the standard C library. In theformer case, interposition will take its course, whereas in the latter case, the fact thatthe C library’s definition of read (2) is weak allows it to be quietly overridden.

By using the link-editor’s −moption, a list of all interposed symbol references, alongwith section load address information, is written to the standard output.

Complex ResolutionsComplex resolutions occur when two symbols of the same name are found withdiffering attributes. In these cases the link-editor will select the most appropriatesymbol and will generate a warning message indicating the symbol, the attributesthat conflict, and the identity of the file from which the symbol definition is taken.For example:

$ cat foo.cint array[1];

$ cat bar.cint array[2] = { 1, 2 };

$ cc -dn -r -o temp.o foo.c bar.cld: warning: symbol ‘array’ has differing sizes:

(file foo.o value=0x4; file bar.o value=0x8);bar.o definition taken

Here, two files with a definition of the data item array have different sizerequirements. A similar diagnostic is produced if the symbols’ alignmentrequirements differed. In both of these cases the diagnostic can be suppressed byusing the link-editor’s −t option.

Another form of attribute difference is the symbol’s type. For example:

$ cat foo.cbar(){

return (0);}$ cc -o libfoo.so -G -K pic foo.c$ cat main.cint bar = 1;

(continued)

22 Linker and Libraries Guide ♦ August 1997

(Continuation)

main(){

return (bar);}$ cc -o main main.c -L. -lfoold: warning: symbol ‘bar’ has differing types:

(file main.o type=OBJT; file ./libfoo.so type=FUNC);main.o definition taken

Here the symbol bar has been defined as both a data item and a function.

Note - types in this context are the symbol types that can be expressed in ELF. Theyare not related to the data types as employed by the programming language exceptin the crudest fashion.

In cases like this, the relocatable object definition will be taken when the resolutionoccurs between a relocatable object and a shared object, or, the first definition will betaken when the resolution occurs between two shared objects. When such resolutionsoccur between symbols of different bindings (weak or global), a warning will also beproduced.

Inconsistencies between symbol types are not suppressed by the link-editor’s −toption.

Fatal ResolutionsSymbol conflicts that cannot be resolved result in a fatal error condition. In this casean appropriate error message is provided indicating the symbol name together withthe names of the files that provided the symbols, and no output file will begenerated. Although the fatal condition is sufficient to terminate the link-edit, allinput file processing will first be completed. In this manner all fatal resolution errorscan be identified.

The most common fatal error condition exists when two relocatable objects bothdefine symbols of the same name, and neither symbol is a weak definition:

$ cat foo.cint bar = 1;

$ cat bar.cbar(){

return (0);

(continued)

Link-Editor 23

(Continuation)

}

$ cc -dn -r -o temp.o foo.c bar.cld: fatal: symbol ‘bar’ is multiply defined:

(file foo.o and file bar.o);ld: fatal: File processing errors. No output written to int.o

Here foo.c and bar.c have conflicting definitions for the symbol bar . Since thelink-editor cannot determine which should dominate, it will usually give up.However, the link-editor’s −z muldefs option can be used to suppress this errorcondition, and allows the first symbol definition to be taken.

Undefined SymbolsAfter all input files have been read and all symbol resolution is complete, thelink-editor will search the internal symbol table for any symbol references that havenot been bound to symbol definitions. These symbol references are referred to asundefined symbols. The effect of these undefined symbols on the link-edit process canvary according to the type of output file being generated, and possibly the type ofsymbol.

Generating an ExecutableWhen the link-editor is generating an executable output file, the link-editor’s defaultbehavior is to terminate the link-edit with an appropriate error message should anysymbols remain undefined. A symbol remains undefined when a symbol reference ina relocatable object is never matched to a symbol definition:

$ cat main.cextern int foo();main(){

return (foo());}

$ cc -o prog main.cUndefined first referenced

symbol in filefoo main.old: fatal: Symbol referencing errors. No output written to prog

24 Linker and Libraries Guide ♦ August 1997

In a similar manner, a symbol reference within a shared object that is never matchedto a symbol definition when the shared object is being used to build a dynamicexecutable, will also result in an undefined symbol:

$ cat foo.cextern int bar;foo(){

return (bar);}

$ cc -o libfoo.so -G -K pic foo.c$ cc -o prog main.c -L. -lfooUndefined first referenced

symbol in filebar ./libfoo.sold: fatal: Symbol referencing errors. No output written to prog

If you wish to allow undefined symbols, as in cases like the previous example, thenthe default fatal error condition can be suppressed by using the link-editor’s −znodefs option.

Note - Care should be taken when using the −z nodefs option. If an unavailablesymbol reference is required during the execution of a process, a fatal runtimerelocation error will occur. Although this error can be detected during the initialexecution and testing of an application, more complex execution paths can result inthis error condition taking much longer to detect, which can be time consuming andcostly.

Symbols can also remain undefined when a symbol reference in a relocatable objectis bound to a symbol definition in an implicitly defined shared object. For example,continuing with the files main.c and foo.c used in the previous example:

$ cat bar.cint bar = 1;

$ cc -o libbar.so -R. -G -K pic bar.c -L. -lfoo$ ldd libbar.so

libfoo.so => ./libfoo.so

$ cc -o prog main.c -L. -lbarUndefined first referenced

symbol in filefoo main.o (symbol belongs to implicit \

dependency ./libfoo.so)ld: fatal: Symbol referencing errors. No output written to prog

Link-Editor 25

Here prog is being built with an explicit reference to libbar.so , and becauselibbar.so has a dependency on libfoo.so , an implicit reference to libfoo.sofrom prog is established.

Because main.c made a specific reference to the interface provided by libfoo.so ,then prog really has a dependency on libfoo.so . However, only explicit sharedobject dependencies are recorded in the output file being generated. Thus, prog willfail to run if a new version of libbar.so is developed that no longer has adependency on libfoo.so .

For this reason, bindings of this type are deemed fatal, and the implicit referencemust be made explicit by referencing the library directly during the link-edit of prog(the required reference is hinted at in the fatal error message shown in this example).

Generating a Shared ObjectWhen the link-editor is generating a shared object, it will by default allow undefinedsymbols to remain at the end of the link-edit. This allows the shared object to importsymbols from either relocatable objects or other shared objects when it is used tobuild a dynamic executable. The link-editor’s −z defs option can be used to force afatal error if any undefined symbols remain.

In general a self contained shared object, in which all references to external symbolsare satisfied by named dependencies, provides maximum flexibility. In this case theshared object can be employed by many users, without those users having todetermine and establish dependencies to satisfy the shared objects requirements.

Weak SymbolsWeak symbol references that are not bound during a link-edit will not result in afatal error condition, no matter what output file type is being generated.

If a static executable is being generated, the symbol will be converted to an absolutesymbol and assigned a value of zero.

If a dynamic executable or shared object is being produced, the symbol will be left asan undefined weak reference. During process execution, the runtime linker willsearch for this symbol, and if it does not find a match, will bind the reference to anaddress of zero instead of generating a fatal runtime relocation error.

Historically, these undefined weak referenced symbols have been employed as amechanism for testing for the existence of functionality. For example, the following Ccode fragment may have been used in the shared object libfoo.so.1 :

#pragma weak foo

extern void foo(char *);

(continued)

26 Linker and Libraries Guide ♦ August 1997

(Continuation)

voidbar(char * path){

void (* fptr)();

if ((fptr = foo) != 0)(* fptr)(path);

}

When an application is built that references libfoo.so.1 , the link-edit willsuccessfully complete regardless of whether a definition for the symbol foo is found.If, during execution of the application the function address tests nonzero, thefunction will be called. However, if the symbol definition is not found, the functionaddress will test zero, and so will not be called.

However, compilation systems view this address comparison technique as havingundefined semantics, which can result in the test statement being removed underoptimization. In addition, the runtime symbol binding mechanism places otherrestrictions on the use of this technique which prevents a consistent model frombeing available for all dynamic objects.

Users are discouraged from using undefined weak references in this manner, andinstead are encouraged to use dlsym (3X) with the RTLD_DEFAULTflag as a meansof testing for a symbols existence (see “Testing for Functionality” on page 64).

Tentative Symbol Order Within the Output FileContributions from input files usually appear in the output file in the order of theircontribution. An exception occurs when processing tentative symbols and theirassociated storage. These symbols are not fully defined until their resolution iscomplete. If the resolution occurs as a result of encountering a defined symbol from arelocatable object, then the order of appearance will be that which would haveoccurred for the definition.

If it is desirable to control the ordering of a group of symbols, then any tentativedefinition should be redefined to a zero-initialized data item. For example, thefollowing tentative definitions result in a reordering of the data items within theoutput file compared to the original order described in the source file foo.c :

Link-Editor 27

$ cat foo.cchar A_array[0x10];char B_array[0x20];

char C_array[0x30];$ cc -o prog main.c foo.c$ nm -vx prog | grep array

[32] |0x00020754|0x00000010|OBJT |GLOB |0x0 |15 |A_array[34] |0x00020764|0x00000030|OBJT |GLOB |0x0 |15 |C_array[42] |0x00020794|0x00000020|OBJT |GLOB |0x0 |15 |B_array

By defining these symbols as initialized data items, the relative ordering of thesesymbols within the input file is carried over to the output file:

$ cat foo.cchar A_array[0x10] = { 0 };char B_array[0x20] = { 0 };char C_array[0x30] = { 0 };$ cc -o prog main.c foo.c$ nm -vx prog | grep array[32] |0x000206bc|0x00000010|OBJT |GLOB |0x0 |12 |A_array[42] |0x000206cc|0x00000020|OBJT |GLOB |0x0 |12 |B_array[34] |0x000206ec|0x00000030|OBJT |GLOB |0x0 |12 |C_array

Defining Additional SymbolsBesides the symbols provided from any input files, you can also supply additionalsymbol references or definitions to a link-edit. In the simplest form, symbolreferences can be generated using the link-editor’s −u option. Greater flexibility isprovided with the link-editor’s −Moption and an associated mapfile which allowsyou to define symbol references and a variety of symbol definitions.

The −u option provides a mechanism for generating a symbol reference from thelink-edit command line. This option can be used to perform a link-edit entirely fromarchives, or to provide additional flexibility in selecting the objects to extract frommultiple archives (see section “Archive Processing” on page 11 for an overview ofarchive extraction).

For example, let’s take the generation of a dynamic executable from the relocatableobject main.o which makes reference to the symbols foo and bar . You wish toobtain the symbol definition foo from the relocatable object foo.o contained inlib1.a , and the symbol definition bar from the relocatable object bar.o containedin lib2.a .

However, the archive lib1.a also contains a relocatable object defining the symbolbar (presumably of differing functionality to that provided in lib2.a ). To specifythe required archive extraction, the following link-edit can be used:

$ cc -o prog -L. -u foo -l1 main.o -l2

28 Linker and Libraries Guide ♦ August 1997

Here, the −u option generates a reference to the symbol foo . This reference willcause extraction of the relocatable object foo.o from the archive lib1.a . As thefirst reference to the symbol bar occurs in main.o , which is encountered afterlib1.a has been processed, the relocatable object bar.o will be obtained from thearchive lib2.a .

Note - This simple example assumes that the relocatable object foo.o from lib1.adoes not directly, or indirectly, reference the symbol bar . If it did then the relocatableobject bar.o will also be extracted from lib1.a during its processing (see section“Archive Processing” on page 11 for a discussion of the link-editor’s multi-passprocessing of an archive).

A more extensive set of symbol definitions can be provided using the link-editor’s −Moption and an associated mapfile . The syntax for these mapfile entries is:

[ name ] {scope:

symbol [ = [ type ] [ value ] [ size ] ];} [ dependency ];

name

A label for this set of symbol definitions, and if present, identifies a version definitionwithin the image. See Chapter 5 for more details.

scope

Indicates the visibility of the symbols’ binding within the output file being generated.This can have either the value local or global . All symbols defined with amapfile are treated as global in scope during the link-edit process. That is, they willbe resolved against any other symbols of the same name obtained from any of theinput files. However, symbols defined as local scope will be reduced to symbolswith a local binding within any executable or shared object file being generated.

symbol

The name of the symbol required. If the name is not followed by any symbolattributes then the result will be the creation of a symbol reference. This reference isexactly the same as would be generated using the −u option discussed earlier in thissection. If the symbol name is followed by an optional “=” character then a symboldefinition will be generated using the associated attributes.

When in local scope, this symbol name can be defined as the special auto-reductiondirective “*”. This directive results in all global symbols, not explicitly defined to beglobal in the mapfile , being given a local binding within any executable or sharedobject file being generated.

Link-Editor 29

type

Indicates the symbols’ type attribute and can be either data , function or common.The former two type attributes result in anabsolute symbol definition (see “SymbolTable” on page 171). The latter type attribute results in a tentative symbol definition.

value

Indicates the symbols’ value attribute and takes the form of Vnumber .

size

Indicates the symbols’ size attribute and takes the form of Snumber .

dependency

Represents a version definition that will be inherited by this definition. See Chapter 5for more details.

If either a version definition or the auto-reduction directive is specified, then versioninginformation is recorded in the image created. If this image is an executable or sharedobject, then any symbol reduction is also applied.

If the image being created is a relocatable object, then by default no symbol reductionis applied. In this case, any symbol reductions are recorded as part of the versioninginformation, and these reductions will be applied when the relocatable object isfinally used to generate an executable or shared object. The link-editor’s −B reduceoption can be used to force symbol reduction when generating a relocatable objecr.

A more detailed description of the versioning information is provided in Chapter 5.

Note - To insure interface definition stability, no wildcard expansion is provided fordefining symbol names.

The remainder of this section presents several examples of using this mapfilesyntax.

The following example shows how three symbol references can be defined and usedto extract members of an archive. Although this archive extraction can be achievedby specifying multiple −u options to the link-edit, this example also shows how theeventual scope of a symbol can be reduced to local:

$ cat foo.cfoo(){

(void) printf("foo: called from lib.a\n");}

(continued)

30 Linker and Libraries Guide ♦ August 1997

(Continuation)

$ cat bar.cbar(){

(void) printf("bar: called from lib.a\n");}$ cat main.cextern void foo(), bar();

main(){

foo();bar();

}$ ar -rc lib.a foo.o bar.o main.o$ cat mapfile{

local:foo;bar;

global:main;

};$ cc -o prog -M mapfile lib.a$ progfoo: called from lib.abar: called from lib.a$ nm -x prog | egrep "main$|foo$|bar$"[28] |0x00010604|0x00000024|FUNC |LOCL |0x0 |7 |foo[30] |0x00010628|0x00000024|FUNC |LOCL |0x0 |7 |bar[49] |0x0001064c|0x00000024|FUNC |GLOB |0x0 |7 |main

The significance of reducing symbol scope from global to local is covered in moredetail in the section “Reducing Symbol Scope” on page 33.

The following example shows how two absolute symbol definitions can be definedand used to resolve the references from the input file main.c :

$ cat main.cextern int foo();extern int bar;

main(){

(void) printf("&foo = %x\n", &foo);(void) printf("&bar = %x\n", &bar);

}$ cat mapfile{

global:foo = FUNCTION V0x400;

(continued)

Link-Editor 31

(Continuation)

bar = DATA V0x800;};$ cc -o prog -M mapfile main.c$ prog&foo = 400&bar = 800$ nm -x prog | egrep "foo$|bar$"[37] |0x00000800|0x00000000|OBJT |GLOB |0x0 |ABS |bar[42] |0x00000400|0x00000000|FUNC |GLOB |0x0 |ABS |foo

When obtained from an input file, symbol definitions for functions or data items areusually associated with elements of data storage. As a mapfile definition isinsufficient to be able to construct this data storage, these symbols must remain asabsolute values.

However, a mapfile can also be used to define a common, or tentative, symbol.Unlike other types of symbol definition, tentative symbols do not occupy storagewithin a file, but define storage that must be allocated at runtime. Therefore, symboldefinitions of this kind can contribute to the storage allocation of the output filebeing generated.

A feature of tentative symbols, that differs from other symbol types, is that their valueattribute indicates their alignment requirement. A mapfile definition can thereforebe used to realign tentative definitions obtained from the input files of a link-edit.

The following example shows the definition of two tentative symbols. The symbolfoo defines a new storage region whereas the symbol bar is actually used to changethe alignment of the same tentative definition within the file main.c :

$ cat main.cextern int foo;int bar[0x10];

main(){

(void) printf("&foo = %x\n", &foo);(void) printf("&bar = %x\n", &bar);

}$ cat mapfile{

global:foo = COMMON V0x4 S0x200;bar = COMMON V0x100 S0x40;

};$ cc -o prog -M mapfile main.cld: warning: symbol ‘bar’ has differing alignments:

(file mapfile value=0x100; file main.o value=0x4);largest value applied

(continued)

32 Linker and Libraries Guide ♦ August 1997

(Continuation)

$ prog&foo = 20940&bar = 20900$ nm -x prog | egrep "foo$|bar$"[37] |0x00020900|0x00000040|OBJT |GLOB |0x0 |16 |bar[42] |0x00020940|0x00000200|OBJT |GLOB |0x0 |16 |foo

Note - This symbol resolution diagnostic can be suppressed by using thelink-editor’s −t option.

Reducing Symbol ScopeIn the previous section it was shown how symbol definitions defined to have localscope within a mapfile can be used to reduce the symbol’s eventual binding. Thismechanism can play an important role in reducing the symbol’s visibility to futurelink-edits that use the generated file as part of their input. In fact, this mechanismcan provide for the precise definition of a file’s interface, and so restrict thefunctionality made available to others.

For example, let’s take the generation of a simple shared object from the files foo.cand bar.c . The file foo.c contains the global symbol foo which provides theservice that you wish to make available to others. The file bar.c contains thesymbols bar and str which provide the underlying implementation of the sharedobject. A simple build of the shared object will usually result in all three of thesesymbols having global scope:

$ cat foo.cextern const char * bar();

const char * foo(){

return (bar());}$ cat bar.cconst char * str = "returned from bar.c";

const char * bar(){

return (str);}$ cc -o lib.so.1 -G foo.c bar.c$ nm -x lib.so.1 | egrep "foo$|bar$|str$"

(continued)

Link-Editor 33

(Continuation)

[29] |0x000104d0|0x00000004|OBJT |GLOB |0x0 |12 |str[32] |0x00000418|0x00000028|FUNC |GLOB |0x0 |6 |bar[33] |0x000003f0|0x00000028|FUNC |GLOB |0x0 |6 |foo

You can now use the functionality offered by this shared object as part of thelink-edit of another application. References to the symbol foo will be bound to theimplementation provided by the shared object.

However, because of their global binding, direct reference to the symbols bar andstr is also possible. This can have dangerous consequences, as the you might laterchange the implementation underlying the function foo , and in so doingunintentionally cause an existing application that had bound to bar or str fail ormisbehave.

Another consequence of the global binding of the symbols bar and str is that theycan be interposed upon by symbols of the same name (the interposition of symbolswithin shared objects is covered in section “Simple Resolutions” on page 20). Thisinterposition can be intentional and be used as a means of circumventing theintended functionality offered by the shared object. On the other hand, thisinterposition can be unintentional, being the result of the application and the sharedobject using the same common symbol name.

When developing the shared object you can protect against this type of scenario byreducing the scope of the symbols bar and str to a local binding, for example:

$ cat mapfile{

local:bar;str;

};$ cc -o lib.so.1 -M mapfile -G foo.c bar.c$ nm -x lib.so.1 | egrep "foo$|bar$|str$"[27] |0x000003dc|0x00000028|FUNC |LOCL |0x0 |6 |bar[28] |0x00010494|0x00000004|OBJT |LOCL |0x0 |12 |str[33] |0x000003b4|0x00000028|FUNC |GLOB |0x0 |6 |foo

Here the symbols bar and str are no longer available as part of the shared objectsinterface. Thus these symbols cannot be referenced, or interposed upon, by anexternal object. You have effectively defined an interface for the shared object. Thisinterface can be managed while hiding the details of the underlying implementation.

This symbol scope reduction has an additional performance advantage. The symbolicrelocations against the symbols bar and str that would have been necessary atruntime are now reduced to relative relocations. This reduces the runtime overhead

34 Linker and Libraries Guide ♦ August 1997

of initializing and processing the shared object (see section “When Relocations arePerformed” on page 91 for details of symbolic relocation overhead).

As the number of symbols processed during a link-edit gets large, the ability todefine each local scope reduction within a mapfile becomes harder to maintain. Analternative, and more flexible mechanism, allows you to define the shared objectsinterface in terms of the global symbols that should

be maintained, and instructs the link-editor to reduce all other symbols to localbinding. This mechanism is achieved using the special auto-reduction directive “*”.For example, the previous mapfile definition can be rewritten to define foo as theonly global symbol required in the output file generated:

$ cat mapfilelib.so.1.1 {

global:foo;

local:*;

};$ cc -o lib.so.1 -M mapfile -G foo.c bar.c$ nm -x lib.so.1 | egrep "foo$|bar$|str$"[30] |0x00000370|0x00000028|FUNC |LOCL |0x0 |6 |bar[31] |0x00010428|0x00000004|OBJT |LOCL |0x0 |12 |str[35] |0x00000348|0x00000028|FUNC |GLOB |0x0 |6 |foo

This example also defines a version name, lib.so.1.1 , as part of the mapfiledirective. This version name establishes an internal version definition that defines thefiles symbolic interface. The creation of a version definition is recommended, andforms the foundation of an internal versioning mechanism that can be usedthroughout the evolution of the file. See Chapter 5 for more details on this topic.

Note - If a version name is not supplied the output filename will be used to label theversion definition. The versioning information created within the output file can besuppressed using the link-editors’ −z noversion option.

Whenever a version name is specified, all global symbols must be assigned to aversion definition. If any global symbols remain unassigned to a version definitionthe link-editor will generate a fatal error condition:

$ cat mapfilelib.so.1.1 {

global:foo;

};$ cc -o lib.so.1 -M mapfile -G foo.c bar.cUndefined first referenced

symbol in file

(continued)

Link-Editor 35

(Continuation)

str bar.o (symbol has no version assigned)bar bar.o (symbol has no version assigned)ld: fatal: Symbol referencing errors. No output written \to lib.so.1

When generating an executable or shared object, any symbol reduction results in therecording of version definitions within the output image, together with the reductionof the appropriate symbols. By default, when generating a relocatable object, theversion definitions are created, but the symbol reductions are not processed. Theresult is that the symbol entries for any symbol reductions will still remain global.For example, using the previous mapfile and associated relocatable objects, anintermediate relocatable object is created which shows no symbol reduction:

$ ld -o lib.o -M mapfile -r foo.o bar.o$ nm -x lib.o | egrep "foo$|bar$|str$"[17] |0x00000000|0x00000004|OBJT |GLOB |0x0 |3 |str[19] |0x00000028|0x00000028|FUNC |GLOB |0x0 |1 |bar[20] |0x00000000|0x00000028|FUNC |GLOB |0x0 |1 |foo

However, the version definitions created within this image record the fact that symbolreductions are required. When the relocatable object is eventually used to generate anexecutable or shared object, the symbol reductions will occur. In other words, thelink-editor reads and interprets symbol reduction information contained inrelocatable objects in the same manner as it can process the data from a mapfile .

Thus, the intermediate relocatable object produced in the previous example can nowbe used to generate a shared object:

$ cc -o lib.so.1 -G lib.o$ nm -x lib.so.1 | egrep "foo$|bar$|str$"[22] |0x000104a4|0x00000004|OBJT |LOCL |0x0 |14 |str[24] |0x000003dc|0x00000028|FUNC |LOCL |0x0 |8 |bar[36] |0x000003b4|0x00000028|FUNC |GLOB |0x0 |8 |foo

Symbol reductions can be forced to occur when building a relocatable object by usingthe link-editor’s −B reduce option:

36 Linker and Libraries Guide ♦ August 1997

$ ld -o lib.o -M mapfile -B reduce -r foo.o bar.o$ nm -x lib.o | egrep "foo$|bar$|str$"[15] |0x00000000|0x00000004|OBJT |LOCL |0x0 |3 |str[16] |0x00000028|0x00000028|FUNC |LOCL |0x0 |1 |bar[20] |0x00000000|0x00000028|FUNC |GLOB |0x0 |1 |foo

Generating the Output ImageOnce all input file processing and symbol resolution is completed with no fatalerrors, the link-editor will start generating the output file image.

The link-editor establishes what additional sections must be generated to completethe output file image. These include the symbol tables that contain local symboldefinitions from the input files, together with the global and weak symbolinformation that has been collected in its internal symbol table.

Also included are any output relocation and dynamic information sections requiredby the runtime linker. Once all the output section information has been established,the total output file size is calculated and the output file image is created accordingly.

When building a dynamic executable or shared object, two symbol tables are usuallygenerated. The .dynsym , and its associated string table .dynstr , contain onlyglobal, weak and section symbols. These sections become part of the text segmentwhich is mapped as part of the process image at runtime. This allows the runtimelinker to read these sections and perform any necessary relocations.

The .symtab , and its associated string table .strtab , contain all the symbolscollected from the input file processing. These sections are not mapped as part of theprocess image, and can even be stripped from the image using the link-editor’s −soption, or after the link-edit using strip (1).

During the generation of the symbol tables reserved symbols are created. These havespecial meaning to the linking process and should not be defined in your code:

_etext

The first location after the text segment.

_edata

The first location after initialized data.

_end

The first location after all data.

Link-Editor 37

_DYNAMIC

The address of the dynamic information section (the .dynamic section).

_END_

The same as _end , but the symbol has local scope (see _START_).

_GLOBAL_OFFSET_TABLE_

The position-independent reference to a link-editor supplied table of addresses (the.got section). This table is constructed from position-independent data referencesoccurring in objects that have been compiled with the −K pic option (see“Position-Independent Code” on page 86 for more information).

_PROCEDURE_LINKAGE_TABLE_

The position-independent reference to a link-editor supplied table of addresses (the.plt section). This table is constructed from position-independent function referencesoccurring in objects that have been compiled with the −K pic option (see“Position-Independent Code” on page 86 for more information).

_START_

The first location within the text segment. The symbol has local scope, and togetherwith _END_, provide a means of establishing an objects address range.

If the link-editor is generating an executable, it will look for additional symbols todefine the executable’s entry point. If a symbol was specified using the link-editor’s−e option it will be used. Otherwise the link-editor will look for the reserved symbolnames _start , and then main . If none of these symbols exists, the first address ofthe text segment will be used.

Having created the output file, all data sections from the input files are copied to thenew image. Any relocations specified in the input files are applied to the outputimage. Any new relocation information that must be generated, together with all theother link-editor generated information, is also written to the new image.

Debugging AidsProvided with the Solaris linkers is a debugging library that allows you to tracethe link-editing process in more detail. This library helps you understand, or debug,the link-edit of your own applications or libraries. This is a visual aid, and although

38 Linker and Libraries Guide ♦ August 1997

the type of information displayed using this library is expected to remain constant,the exact format of the information might change slightly from release to release.

Some of the debugging output might be unfamiliar if you do not have an intimateknowledge of ELF. However, many aspects can be of general interest to you.

Debugging is enabled by using the −D option, and all output produced is directed tothe standard error. This option must be augmented with one or more tokens toindicate the type of debugging required. The tokens available can be displayed byusing −Dhelp . For example:

$ ld -Dhelpdebug:debug: For debugging the link-editing of an application:debug: LD_OPTIONS=-Dtoken1,token2 cc -o prog ...debug: or,debug: ld -Dtoken1,token2 -o prog ...debug: where placement of -D on the command line is significantdebug: and options can be switched off by prepending with ‘!’.debug:debug:debug: args display input argument processingdebug: basic provide basic trace information/warningsdebug: detail provide more information in conjunction with otherdebug: optionsdebug: entry display entrance criteria descriptorsdebug: files display input file processing (files and libraries)debug: help display this help messagedebug: libs display library search paths; detail flag shows actualdebug: library lookup (-l) processingdebug: map display map file processingdebug: reloc display relocation processingdebug: sections display input section processingdebug: segments display available output segments and address/offsetdebug: processing; detail flag shows associated sectionsdebug: support display support library processingdebug: symbols display symbol table processing;debug: detail flag shows resolution and linker table additiondebug: versions display version processing

Note - This listing is an example, and shows the options meaningful to thelink-editor. The exact options might differ from release to release.

As most compiler drivers will interpret the −D option during their preprocessingphase, the LD_OPTIONSenvironment variable is a suitable mechanism for passingthis option to the link-editor.

The following example shows how input files can be traced. This can be especiallyuseful in determining what libraries have been located, or what relocatable objectshave been extracted from an archive during a link-edit:

Link-Editor 39

$ LD_OPTIONS=-Dfiles cc -o prog main.o -L. -lfoo............debug: file=main.o [ ET_REL ]debug: file=./libfoo.a [ archive ]debug: file=./libfoo.a(foo.o) [ ET_REL ]debug: file=./libfoo.a [ archive ] (again)............

Here the member foo.o is extracted from the archive library libfoo.a to satisfythe link-edit of prog . Notice that the archive is searched twice (again) to verify thatthe extraction of foo.o did not warrant the extraction of additional relocatableobjects. More than one “(again)” display indicates that the archive is a candidate forordering using lorder (1) and tsort (1).

By using the symbols token you can determine what symbol caused an archivemember to be extracted, and which object made the initial symbol reference:

$ LD_OPTIONS=-Dsymbols cc -o prog main.o -L. -lfoo............debug: symbol table processing; input file=main.o [ ET_REL ]............debug: symbol[7]=foo (global); addingdebug:debug: symbol table processing; input file=./libfoo.a [ archive ]debug: archive[0]=bardebug: archive[1]=foo (foo.o) resolves undefined or tentative symboldebug:debug: symbol table processing; input file=./libfoo(foo.o) [ ET_REL ].............

Here the symbol foo is referenced by main.o and is added to the link-editor’sinternal symbol table. This symbol reference causes the extraction of the relocatableobject foo.o from the archive libfoo.a .

Note - This output has been simplified for this document.

By using the detail token together with the symbols token, the details of symbolresolution during input file processing can be observed:

$ LD_OPTIONS=-Dsymbols,detail cc -o prog main.o -L. -lfoo............debug: symbol table processing; input file=main.o [ ET_REL ]............debug: symbol[7]=foo (global); addingdebug: entered 0x000000 0x000000 NOTY GLOB UNDEF REF_REL_NEEDdebug:debug: symbol table processing; input file=./libfoo.a [ archive ]debug: archive[0]=bar

(continued)

40 Linker and Libraries Guide ♦ August 1997

(Continuation)

debug: archive[1]=foo (foo.o) resolves undefined or tentative symboldebug:debug: symbol table processing; input file=./libfoo.a(foo.o) [ ET_REL ]debug: symbol[1]=foo.c.............debug: symbol[7]=bar (global); addingdebug: entered 0x000000 0x000004 OBJT GLOB 3 REF_REL_NEEDdebug: symbol[8]=foo (global); resolving [7][0]debug: old 0x000000 0x000000 NOTY GLOB UNDEF main.odebug: new 0x000000 0x000024 FUNC GLOB 2 ./libfoo.a(foo.o)debug: resolved 0x000000 0x000024 FUNC GLOB 2 REF_REL_NEED

Here, the original undefined symbol foo from main.o has been overridden with thesymbol definition from the extracted archive member foo.o . The detailed symbolinformation reflects the attributes of each symbol.

From the previous example, it should be apparent that using some of the debuggingtokens can produce a wealth of output. In cases where are interested only in theactivity around a subset of the input files, the −D option can be placed directly in thelink-edit command-line, and toggled on and off. For example:

$ ld .... -o prog main.o -L. -Dsymbols -lbar -D!symbols ....

Here the display of symbol processing will be switched on only during theprocessing of the library libbar .

Note - To obtain the link-edit command-line it might be necessary to expand thecompilation line from any driver being used. See “Using a Compiler Driver” on page9 for more details.

Link-Editor 41

42 Linker and Libraries Guide ♦ August 1997

CHAPTER 3

Runtime Linker

OverviewAs part of the initialization and execution of a dynamic executable, an interpreter iscalled to complete the binding of the application to its dependencies. In Solaristhis interpreter is referred to as the runtime linker.

During the link-editing of a dynamic executable, a special .interp section, togetherwith an associated program header, are created. This section contains a pathnamespecifying the program’s interpreter. The default name supplied by the link-editor isthat of the runtime linker - /usr/lib/ld.so.1 .

During the process of executing a dynamic executable (see exec (2)) the kernel mapsthe file (see mmap(2)), and using the program header information (see “ProgramHeader” on page 195) locates the name of the required interpreter. The kernel mapsthis interpreter and transfers control to it, passing sufficient information to allow theinterpreter to continue binding the application and then run it.

In addition to initializing an application the runtime linker provides services thatallow the application to extend its address space by mapping additional objects andbinding to symbols within them.

The following is a simple breakdown of the runtime linkers functionality, andintroduces the topics covered in this chapter:

� It analyzes the executable’s dynamic information section (.dynamic ) anddetermines what dependencies are required.

� It locates and maps in these dependencies, and analyzes their dynamicinformation sections to determine if any additional dependencies are required.

� Once all dependencies are located and mapped, the runtime linker performs anynecessary relocations to bind these objects in preparation for process execution.

43

� It calls any initialization functions provided by the dependencies.

� It passes control to the application.

� During the application’s execution, the runtime linker can be called upon toperform any delayed function binding.

� The application can also call upon the runtime linker’s services to acquireadditional objects by dlopen (3X), and bind to symbols within these objects withdlsym (3X).

Locating Shared Object DependenciesUsually, during the link-edit of a dynamic executable, one or more shared objects areexplicitly referenced. These objects are recorded as dependencies within the dynamicexecutable (see “Shared Object Processing” on page 12 for more information).

The runtime linker first locates this dependency information and uses it to locate andmap the associated objects. These dependencies are processed in the same order asthey were referenced during the link-edit of the executable.

Once all the dynamic executable’s dependencies are mapped, they too are inspected,in the order they are mapped, to locate any additional dependencies. This processcontinues until all dependencies are located and mapped. This technique results in abreadth-first ordering of all dependencies.

Directories Searched by the Runtime LinkerThe runtime linker knows of only one standard place to look for dependencies,/usr/lib . Any dependency specified as a simple filename will be prefixed with thisdefault directory name and the resulting pathname will be used to locate the actualfile.

The actual dependencies of any dynamic executable or shared object can be displayedusing ldd (1). For example, the file /usr/bin/cat has the following dependencies:

$ ldd /usr/bin/catlibc.so.1 => /usr/lib/libc.so.1libdl.so.1 => /usr/lib/libdl.so.1

Here, the file /usr/bin/cat has a dependency, or needs, the files libc.so.1 andlibdl.so.1 .

44 Linker and Libraries Guide ♦ August 1997

The dependencies actually recorded in a file can be inspected by using the dump(1)command to display the file’s .dynamic section, and referencing any entries thathave a NEEDEDtag. For example:

$ dump -Lvp /usr/bin/cat

/usr/bin/cat:[INDEX] Tag Value[1] NEEDED libc.so.1.........

Notice that the dependency libdl.so.1 , displayed in the previous ldd (1)example, is not recorded in the file /usr/bin/cat . This is because ldd (1) showsthe total dependencies of the specified file, and libdl.so.1 is actually adependency of /usr/lib/libc.so.1 .

In the previous dump(1) example the dependencies are expressed as simple filenames- in other words there is no ‘/’ in the name. The use of a simple filename requiresthe runtime linker to build the required pathname from a set of rules. Filenames thatcontain an embedded ‘/’ will be used as-is.

The simple filename recording is the standard, most flexible mechanism of recordingdependencies, and is provided by using the −h option of the link-editor to record asimple name within the dependency (see “Naming Conventions” on page 72 and“Recording a Shared Object Name” on page 73 for additional information on thistopic).

Frequently, dependencies are distributed in directories other than /usr/lib . If adynamic executable or shared object needs to locate dependencies in anotherdirectory, the runtime linker must explicitly be told to search this directory.

The recommended way to indicate additional search paths to the runtime linker is torecord a runpath during the link-edit of the dynamic executable or shared object (see“Directories Searched by the Runtime Linker” on page 16 for details on recordingthis information).

Any runpath recording can be displayed using dump(1) and referring to the entrythat has the RPATHtag. For example:

$ dump -Lvp prog

prog:[INDEX] Tag Value[1] NEEDED libfoo.so.1[2] NEEDED libc.so.1[3] RPATH /home/me/lib:/home/you/lib.........

Runtime Linker 45

Here, prog has a dependency on libfoo.so.1 and requires the runtime linker tosearch directories /home/me/lib and /home/you/lib before it looks in the defaultlocation /usr/lib .

Another way to add to the runtime linker’s search path is to set the environmentvariable LD_LIBRARY_PATH. This environment variable (which is analyzed once atprocess start-up) can be set to a colon-separated list of directories, and thesedirectories will be searched by the runtime linker before any runpath specification ordefault directory.

This environment variable is well suited for debugging purposes such as forcing anapplication to bind to a local dependency. For example:

$ LD_LIBRARY_PATH=. prog

Here the file prog from the previous example will be bound to libfoo.so.1 foundin the present working directory.

Although useful as a temporary mechanism of influencing the runtime linker’s searchpath, the use of this environment variable is strongly discouraged in productionsoftware. Any dynamic executables that can reference this environment variable willhave their search paths augmented, which can result in an overall degradation inperformance. Also, as pointed out in “Using an Environment Variable” on page 16and “Directories Searched by the Runtime Linker” on page 16, this environmentvariable affects the link-editor.

If a dependency cannot be located, ldd (1) will indicate that the object cannot befound, and any attempt to execute the application will result in an appropriate errormessage from the runtime linker:

$ ldd proglibfoo.so.1 => (file not found)libc.so.1 => /usr/lib/libc.so.1libdl.so.1 => /usr/lib/libdl.so.1

$ progld.so.1: prog: fatal: libfoo.so.1: open failed: No such file or \directory

Relocation ProcessingOnce the runtime linker has located and mapped all the dependencies required by anapplication, it processes each object and performs any necessary relocations.

During the link-editing of an object, any relocation information supplied with theinput relocatable objects is applied to the output file. However, when building a

46 Linker and Libraries Guide ♦ August 1997

dynamic executable or shared object, many of the relocations cannot be completed atlink-edit time because they require logical addresses that are known only when theobjects are mapped into memory. In these cases the link-editor generates newrelocation records as part of the output file image, and it is this information that theruntime linker must now process.

For a more detailed description of the many relocation types, see “Relocation Types(Processor-Specific)” on page 179. However, for the purposes of this discussion it isconvenient to categorize relocations into one of two types:

� Non-symbolic relocations.

� Symbolic relocations.

The relocation records for an object can be displayed by using dump(1). For example:

$ dump -rvp libbar.so.1

libbar.so.1:

.rela.got:Offset Symndx Type Addend

0x10438 0 R_SPARC_RELATIVE 00x1043c foo R_SPARC_GLOB_DAT 0

Here, the file libbar.so.1 contains two relocation records that indicate that theglobal offset table (the .got section) must be updated.

The first relocation is a simple relative relocation that can be seen from its relocationtype and the symbol index (Symndx) field being zero. This relocation needs to usethe base address at which the object was mapped into memory to update theassociated .got offset.

The second relocation requires the address of the symbol foo . To complete thisrelocation the runtime linker must locate this symbol from the dynamic executableand its dependencies that have been mapped so far.

Symbol LookupWhen an object requires a symbol, the runtime linker searches for that symbol basedupon the requesting objects’ symbol search scope, and the symbol visibility offered byeach object within the process. These attributes are applied as defaults to an object atthe time it is loaded, as specific modes to dlopen (3X), and in some cases can berecorded within the object at the time it is built.

Typically, an average user becomes familiar with the default symbol search modelsthat are applied to a dynamic executable and its dependencies, and to objectsobtained through dlopen (3X). The former is outlined in this section and the latter,

Runtime Linker 47

which is also able to exploit the various symbol lookup attributes, is discussed in“Symbol Lookup” on page 57.

A dynamic executable and all the dependencies loaded with it, are assigned worldsearch scope, and global symbol visibility (see “Symbol Lookup” on page 57). Thus,when the runtime linker looks up a symbol for a dynamic executable or for any ofthe dependencies loaded with the executable, it does so by searching each object,starting with the dynamic executable, and progressing through each dependency inthe same order in which the objects were mapped.

As discussed in previous sections, ldd (1) will list the dependencies of a dynamicexecutable in the order in which they are mapped. Therefore, if the shared objectlibbar.so.1 requires the address of symbol foo to complete its relocation, andthis shared object is a dependency of the dynamic executable prog:

$ ldd proglibfoo.so.1 => /home/me/lib/libfoo.so.1libbar.so.1 => /home/me/lib/libbar.so.1

Then, the runtime linker will first look for foo in the dynamic executable prog , thenin the shared object /home/me/lib/libfoo.so.1 , and finally in the shared object/home/me/lib/libbar.so.1 .

Note - Symbol lookup can be an expensive operation, especially as the size ofsymbol names increases, and the number of dependencies increases. This aspect ofperformance is discussed in more detail in“ Performance Considerations” on page 83.

InterpositionThe runtime linkers mechanism of searching for a symbol first in the dynamicexecutable and then in each of the dependencies means that the first occurrence ofthe required symbol will satisfy the search. Therefore, if more than one instance ofthe same symbol exists, the first instance will interpose on all others (see also “SharedObject Processing” on page 12).

When Relocations are PerformedHaving briefly described the relocation process, together with the simplification ofrelocations into the two types, non-symbolic and symbolic, it is also useful todistinguish relocations by when they are performed. This distinction arises due tothe type of reference being made to the relocated offset, and can be either:

� A data reference.

� A function reference.

48 Linker and Libraries Guide ♦ August 1997

A data reference refers to an address that is used as a data item by the applicationcode. The runtime linker has no knowledge of the application code, and so does notknow when this data item will be referenced. Therefore, all data relocations must becarried out during process initialization, before the application gains control.

A function reference refers to the address of a function that will be called by theapplication code. During the compilation and link-editing of any dynamic module,calls to global functions are relocated to become calls to a procedure linkage table entry(these entries make up the .plt section).

Procedure linkage table entries are constructed so that when first called control ispassed to the runtime linker (see “Procedure Linkage Table (Processor-Specific)” onpage 219). The runtime linker will look up the required symbol and rewriteinformation in the application so that any future calls to this .plt entry will godirectly to the function. This mechanism allows relocations of this type to be deferreduntil the first instance of a function being called, a process that is sometimes referredto as lazy binding.

The runtime linker’s default mode of performing lazy binding can be overridden bysetting the environment variable LD_BIND_NOWto any non-null value. Thisenvironment variable setting causes the runtime linker to perform both datareference and function reference relocations during process initialization, beforetransferring control to the application. For example:

$ LD_BIND_NOW=yes prog

Here, all relocations within the file prog and within its dependencies will beprocessed before control is transferred to the application.

Individual objects can also be built using the link-editors’ −z now option to indicatethat they require complete relocation processing at the time they are loaded. Thisrelocation requirement is also propagated to any dependencies of the marked objectat runtime.

Relocation ErrorsThe most common relocation error occurs when a symbol cannot be found. Thiscondition will result in an appropriate runtime linker error message and thetermination of the application. For example:

$ ldd proglibfoo.so.1 => ./libfoo.so.1libc.so.1 => /usr/lib/libc.so.1libbar.so.1 => ./libbar.so.1libdl.so.1 => /usr/lib/libdl.so.1

$ prog

(continued)

Runtime Linker 49

(Continuation)

ld.so.1: prog: fatal: relocation error: file ./libfoo.so.1: \symbol bar: referenced symbol not found

Here the symbol bar , which is referenced in the file libfoo.so.1 , cannot belocated.

Note - During the link-edit of a dynamic executable any potential relocation errorsof this sort will be flagged as fatal undefined symbols (see “Generating anExecutable” on page 24 for examples). This runtime relocation error can occur if thelink-edit of main used a different version of the shared object libbar.so.1 thatcontained a symbol definition for bar , or if the −z nodefs option was used as partof the link-edit.

If a relocation error of this type occurs because a symbol used as a data referencecannot be located, the error condition will occur immediately during processinitialization. However, because of the default mode of lazy binding, if a symbolused as a function reference cannot be found, the error condition will occur after theapplication has gained control.

This latter case can take minutes or months, or might never occur, depending on theexecution paths exercised throughout the code. To guard against errors of this kind,the relocation requirements of any dynamic executable or shared object can bevalidated using ldd (1).

When the −d option is specified with ldd (1), all dependencies will be printed andall data reference relocations will be processed. If a data reference cannot be resolved,a diagnostic message will be produced. From the previous example this reveals:

$ ldd -d proglibfoo.so.1 => ./libfoo.so.1libc.so.1 => /usr/lib/libc.so.1libbar.so.1 => ./libbar.so.1libdl.so.1 => /usr/lib/libdl.so.1symbol not found: bar (./libfoo.so.1)

When the −r option is specified with ldd (1), all data and function referencerelocations will be processed, and if either cannot be resolved a diagnostic messagewill be produced.

50 Linker and Libraries Guide ♦ August 1997

Loading Additional ObjectsThe previous sections have described how the runtime linker initializes a processfrom the dynamic executable and its dependencies as they were defined during thelink-editing of each module. The runtime linker also provides an additional level offlexibility by allowing you to introduce new objects during process initialization.

The environment variable LD_PRELOADcan be initialized to a shared object orrelocatable object filename, or a string of filenames separated by white space. Theseobjects are mapped after the dynamic executable and before any dependencies, andare assigned world search scope, and global symbol visibility (see “Symbol Lookup”on page 57). For example:

$ LD_PRELOAD=./newstuff.so.1 prog

Here the dynamic executable prog will be mapped, followed by the shared objectnewstuff.so.1 , and then by the dependencies defined within prog . The order inwhich these objects are processed can be displayed using ldd (1):

$ LD_PRELOAD=./newstuff.so.1 ldd prog./newstuff.so.1 => ./newstuff.solibc.so.1 => /usr/lib/libc.so.1

Another example is:

$ LD_PRELOAD="./foo.o ./bar.o" prog

Here the preloading is a little more complex and time consuming. The runtime linkerfirst link-edits the relocatable objects foo.o and bar.o to generate a shared objectthat is maintained in memory. This memory image is then inserted between thedynamic executable and its dependencies in exactly the same manner as the sharedobject newstuff.so.1 was preloaded in the previous example. Again, the order inwhich these objects are processed can be displayed with ldd (1):

$ LD_PRELOAD="./foo.o ./bar.o" ldd prog./foo.o => ./foo.o./bar.o => ./bar.olibc.so.1 => /usr/lib/libc.so.1

These mechanisms of inserting an object after a dynamic executable take the conceptof interposition introduced in “Interposition” on page 48 to another level. Using thesemechanisms, it is possible to experiment with a new implementation of a functionthat resides in a standard shared object. By preloading an object containing this

Runtime Linker 51

function it will interpose on the original. Thus the old functionality can becompletely hidden with the new preloaded version.

Another use of preloading is to augment a function that resides in a standard sharedobject. Here the intention is to have the new symbol interpose on the original,allowing the new function to carry out some additional processing, while still havingit call through to the original function. This mechanism requires either a symbol aliasto be associated with the original function (see “Simple Resolutions” on page 20) orthe ability to look up the original symbol’s address (see “Using Interposition” onpage 65).

Initialization and Termination RoutinesBefore transferring control to the application, the runtime linker processes anyinitialization (.init ) and termination (.fini ) sections found in the applicationsdependencies. These sections, and the symbols that describe them, are created duringthe link-editing of the dependencies (see “Initialization and Termination Sections” onpage 17).

Prior to the Solaris 2.6 release, any initialization routines from dependencies werecalled in reverse load order - in other words, the reverse order of the dependenciesdisplayed with ldd (1).

Starting with the Solaris 2.6 release, the runtime linker constructs a dependencyordered list of initialization routines from the dependencies that have been loaded.This list is built from the dependency relationships expressed by each object, inaddition to any bindings that occur outside of the expressed dependencies.

The .init sections are executed in the reverse topological order of thedependencies. If any cyclic dependencies are found, the objects that form the cyclecannot be topologically sorted, and thus their .init sections will be executed in theorder they are loaded.

ldd (1) with the −i option can be used to display the initialization order of anobjects’ dependencies. For example, the following dynamic executable and itsdependencies exhibit a cyclic dependency:

$ dump -Lv B.so.1 | grep NEEDED[1] NEEDED C.so.1$ dump -Lv C.so.1 | grep NEEDED[1] NEEDED B.so.1$ dump -Lv main | grep NEEDED[1] NEEDED A.so.1[2] NEEDED B.so.1[3] NEEDED libc.so.1$ ldd -i main

(continued)

52 Linker and Libraries Guide ♦ August 1997

(Continuation)

A.so.1 => ./A.so.1B.so.1 => ./B.so.1libc.so.1 => /usr/lib/libc.so.1C.so.1 => ./C.so.1libdl.so.1 => /usr/lib/libdl.so.1

init library=./A.so.1init library=./C.so.1 (cyclic dependency on ./B.so.1)init library=./B.so.1 (cyclic dependency on ./C.so.1)init library=/usr/lib/libc.so.1

The environment variable LD_BREADTHcan be set to a non-null value to force theruntime linker to execute .init sections in pre-2.6 order.

Initialization processing is repeated for any objects added to the running processwith dlopen (3X).

Any termination routines for an applications dependencies are organized such thatthey can be recorded by atexit (3C). These routines are called when the processcalls exit (2), or when objects are removed from the running process withdlclose (3X).

Starting with the Solaris 2.6 release, termination routines are called in thetopological order of dependencies. Prior to the Solaris 2.6 release, or when theLD_BREADTHenvironment variable is in effect, termination routines were called inload order.

Although this initialization and termination calling sequence seems quitestraightforward, be careful about placing too much emphasis on this sequence, as theordering of objects can be affected by both shared object and applicationdevelopment (see “Dependency Ordering” on page 77 for more details).

Note - Any .init or .fini sections within the dynamic executable are called fromthe application itself by the process start-up and termination mechanism supplied bythe compiler driver. The dynamic executable’s .init section is called last, after allits dependencies .init sections are executed. The dynamic executable’s .finisection is called first, before its dependencies .fini sections are executed.

SecuritySecure processes have some restrictions applied to the evaluation of theirdependencies to prevent malicious dependency substitution or symbol interposition.

Runtime Linker 53

The runtime linker categorizes a process as secure if the user is not the root, andeither the real users and effective users identifiers are not equal (see getuid (2) andgeteuid (2)), or the real group and effective group identifiers are not equal (seegetgid (2) and getegid (2)).

If an LD_LIBRARY_PATHenvironment variable is in effect (see “Directories Searchedby the Runtime Linker” on page 44) for a secure process, then only the trusteddirectories specified by this variable will be used to augment the runtime linker’ssearch rules. Presently, the only trusted directory known to the runtime linker is/usr/lib .

In a secure process, any runpath specifications provided by the application or any ofit’s dependencies (see “Directories Searched by the Runtime Linker” on page 44) willbe used provided they are full pathnames - in other words the pathname starts witha ‘/’.

Additional objects may be loaded with a secure process using the LD_PRELOADenvironment variable (see “Loading Additional Objects” on page 55) provided theobjects are specified as simple filenames - in other words there is no ‘/’ in the name.These objects will be located subject to the search path restrictions previouslydescribed.

In a secure process, any dependencies that consist of simple filenames will beprocessed using the pathname restrictions outlined. Dependencies that are expressedas full or relative pathnames will be used as is. Therefore, the developer of a secureprocess should insure that the target directory referenced as a full or relativepathname dependency is suitably protected from malicious intrusion.

When creating a secure process, it is recommended that relative pathnames not beused to express dependencies or to construct dlopen (3X) pathnames. Thisrestriction should be applied to the application and to all dependencies.

Runtime Linking Programming InterfaceThe previous discussions described how the dependencies specified during thelink-edit of an application are processed by the runtime linker during processinitialization. In addition to this mechanism, the application can extend its addressspace during its execution by binding to additional objects. This extensibility isprovided by allowing the application to request the same services of the runtimelinker as used to process the dependencies specified during the link-edit of theapplication.

This delayed object binding has several advantages:

� By processing an object when it is required rather than during the initialization ofan application, start-up time can be greatly reduced. In fact, the object might not

54 Linker and Libraries Guide ♦ August 1997

be required if its services are not needed during a particular run of the application,such as for help or debugging information.

� The application can choose between several different objects depending on theexact services required, such as for a networking protocol.

� Any objects added to the process address space during execution can be freedafter use.

The following is a typical scenario that an application can perform to access anadditional shared object, and introduces the topics covered in the next sections:

� A shared object is located and added to the address space of a running applicationusing dlopen (3X). Any dependencies this shared object has are located andadded at this time.

� The added shared object and its dependencies are relocated, and any initializationsections within these objects are called.

� The application locates symbols within the added objects using dlsym (3X). Theapplication can then reference the data or call the functions defined by these newsymbols.

� After the application has finished with the objects, the address space can be freedusing dlclose (3X). Any termination sections within the objects being freed willbe called at this time.

� Any error conditions that occur as a result of using these runtime linker interfaceroutines can be displayed using dlerror (3X).

The services of the runtime linker are defined in the header file dlfcn.h and aremade available to an application by the shared object libdl.so.1 . For example:

$ cc -o prog main.c -ldl

Here the file main.c can make reference to any of the dlopen (3X) family ofroutines, and the application prog can bind to these routines at runtime.

Loading Additional ObjectsAdditional objects can be added to a running process’s address space usingdlopen (3X). This function takes a filename and a binding mode as arguments, andreturns a handle to the application. This handle can be used to locate symbols for useby the application using dlsym (3X).

If the filename is specified as a simple filename - in other words, there is no ‘/’ in thename, then the runtime linker will use a set of rules to build an appropriatepathname. Filenames that contain a ‘/’ will be used as-is.

These search path rules are exactly the same as are used to locate any initialdependencies (see “Directories Searched by the Runtime Linker” on page 44). Forexample, if the file main.c contains the following code fragment:

Runtime Linker 55

#include <stdio.h>#include <dlfcn.h>

main(int argc, char ** argv){

void * handle;.....

if ((handle = dlopen("foo.so.1", RTLD_LAZY)) == NULL) {(void) printf("dlopen: %s\n", dlerror());exit (1);

}.....

then to locate the shared object foo.so.1 , the runtime linker will use anyLD_LIBRARY_PATHdefinition present at process initialization, followed by anyrunpath specified during the link-edit of prog , and finally the default location/usr/lib .

If the filename is specified as:

if ((handle = dlopen("./foo.so.1", RTLD_LAZY)) == NULL) {

then the runtime linker will search for the file only in the current working directoryof the process.

Note - It is recommended that any shared object specified using dlopen (3X) bereferenced by its versioned filename (for more information on versioning see“Coordination of Versioned Filenames” on page 114).

If the required object cannot be located, dlopen (3X) will return a NULL handle. Inthis case dlerror (3X) can be used to display the true reason for the failure. Forexample:

$ cc -o prog main.c -ldl$ progdlopen: ld.so.1: prog: fatal: foo.so.1: open failed: No such \file or directory

If the object being added by dlopen (3X) has dependencies on other objects, theytoo will be brought into the process’s address space. This process will continue untilall the dependencies of the specified object are loaded. This dependency tree isreferred to as a group.

If the object specified by dlopen (3X), or any of its dependencies, are already part ofthe process image, then the objects will not be processed any further, but a validhandle will still be returned to the application. This mechanism prevents the sameobject from being mapped more than once, and allows an application to obtain a

56 Linker and Libraries Guide ♦ August 1997

handle to itself. For example, if the previous main.c example contained thefollowing dlopen() call:

if ((handle = dlopen((const char *)0, RTLD_LAZY)) == NULL) {

then the handle returned from dlopen (3X) can be used to locate symbols within theapplication itself, within any of the dependencies loaded as part of the process’sinitialization, or within any objects added to the process’s address space using adlopen (3X) that specified the RTLD_GLOBALflag.

Relocation ProcessingAs described in “Relocation Processing” on page 46, after locating and mapping anyobjects, the runtime linker must process each object and perform any necessaryrelocations. Any objects brought into the process’s address space with dlopen (3X)must also be relocated in the same manner.

For simple applications this process might be quite uninteresting. However, for userswho have more complex applications with many dlopen (3X) calls involving manyobjects, possibly with common dependencies, this topic can be quite important.

Relocations can be categorized according to when they occur. The default behavior ofthe runtime linker is to process all data reference relocations at initialization and allfunction references during process execution, a mechanism commonly referred to aslazy binding.

This same mechanism is applied to any objects added with dlopen (3X) when themode is defined as RTLD_LAZY. An alternative is to require all relocations of an objectto be performed immediately when the object is added. This can be achieved byusing a mode of RTLD_NOW, or by recording this requirement in the object when itwas built using the link-editors’ −z now option. This relocation requirement ispropagated to any dependencies of the object being opened.

Relocations can also be categorized into non-symbolic and symbolic. The remainderof this section covers issues regarding symbolic relocations, regardless of when theserelocations occur, with a focus on some of the subtleties of symbol lookup.

Symbol LookupIf an object acquired by dlopen (3X) refers to a global symbol, the runtime linkermust locate this symbol from the pool of objects that makeup the process. A defaultsymbol search model is applied to objects obtained by dlopen (3X), and this isdescribed in the following sections. However, the mode of a dlopen (3X), combinedwith the attributes of the objects that makeup the process, provide for alternativesymbol search models.

Runtime Linker 57

Two attributes of an object effect symbol lookup. The first is the requesting objectssymbol search scope, and the second is the symbol visibility offered by each objectwithin the process. An objects’ search scope can be:

world

The object can look in any other global object within the process.

group

The object can only look in an object of the same group. The dependency tree createdfrom an object obtained with dlopen (3X), or from an object built using thelink-editors’ −B group option, forms a unique group.

The visibility of a symbol from an object can be:

global

The objects symbols can be referenced from any object having world search scope.

local

The objects symbols can only be referenced from other objects that comprise the samegroup.

By default, objects obtained with dlopen (3X) are assigned world symbol searchscope, and local symbol visibility. The following section “Default Symbol LookupModel” on page 58, uses this default model to illustrate typical object groupinteractions. Sections “Defining a Global Object” on page 61, “Isolating a Group” onpage 62 and “Object Hierarchies” on page 62 show examples of using dlopen (3X)modes and file attributes to extend the default symbol lookup model.

Default Symbol Lookup ModelFor each object added by dlopen (3X) the runtime linker will first look for thesymbol in the dynamic executable, and then look in each of the objects providedduring the initialization of the process. However, if the symbol is still not found, theruntime linker will continue the search, looking in the object acquired through thedlopen (3X) and in any of its dependencies.

For example, let’s take the dynamic executable prog , and the shared object B.so.1 ,each of which has the following (simplified) dependencies:

58 Linker and Libraries Guide ♦ August 1997

$ ldd progA.so.1 => ./A.so.1

$ ldd B.so.1C.so.1 => ./C.so.1

If prog acquires the shared object B.so.1 by dlopen (3X), then any symbolrequired to relocate the shared objects B.so.1 and C.so.1 will first be looked for inprog , followed by A.so.1 , followed by B.so.1 , and finally in C.so.1 . In thissimple case, it might be easier to think of the shared objects acquired through thedlopen (3X) as if they had been added to the end of the original link-edit of theapplication. For example, the objects referenced in the previous listing can beexpressed diagrammatically:

prog A.so.1 B.so.1 C.so.1

Figure 3–1 A Single dlopen(3X) Request

Any symbol lookup required by the objects acquired from the dlopen (3X), shownas shaded blocks, will proceed from the dynamic executable prog through to thefinal shared object C.so.1 .

This symbol lookup is established by the attributes assigned to the objects as theywere loaded. Recall that the dynamic executable and all the dependencies loadedwith it, are assigned global symbol visibility, and that the new objects are assignedworld symbol search scope. Therefore, the new objects are able to look for symbols inthe original objects. The new objects also form a unique group in which each objecthas local symbol visibility. Therefore, each object within the group can look forsymbols within the other group members.

These new objects do not affect the normal symbol lookup required by either theapplication or its initial object dependencies. For example, if A.so.1 requires afunction relocation after the above dlopen (3X) has occurred, the runtime linker’snormal search for the relocation symbol will be to look in prog and then A.so.1 ,but not to follow through and look in B.so.1 or C.so.1 .

This symbol lookup is again a result of the attributes assigned to the objects as theywere loaded. The world symbol search scope assigned the dynamic executable and allthe dependencies loaded with it, does not allow them to look for symbols in the newobjects that only offer local symbol visibility.

These symbol search and symbol visibility attributes thus maintain associationsbetween objects based on their introduction into the process address space, and onany dependency relationships between the objects. Assigning the objects associatedwith a given dlopen (3X) a unique group insures that only objects associated with

Runtime Linker 59

the same dlopen (3X) are allowed to look up symbols within themselves and theirrelated dependencies.

This concept of defining associations between objects becomes more clear inapplications that carry out more than one dlopen (3X). For example, if the sharedobject D.so.1 has the following dependency:

$ ldd D.so.1E.so.1 => ./E.so.1

and the prog application was to dlopen (3X) this shared object in addition to theshared object B.so.1 , then diagrammatically the symbol lookup relationshipbetween the objects can be represented as:

prog A.so.1

C.so.1B.so.1

D.so.1 E.so.1

Figure 3–2 Multiple dlopen(3X) Requests

If both B.so.1 and D.so.1 contain a definition for the symbol foo , and bothC.so.1 and E.so.1 contain a relocation that requires this symbol, then because ofthe association of objects to a unique group, C.so.1 will be bound to the definitionin B.so.1 , and E.so.1 will be bound to the definition in D.so.1 . This mechanismis intended to provide the most intuitive binding of objects obtained from multiplecalls to dlopen (3X).

When objects are used in the scenarios that have so far been described, the order inwhich each dlopen (3X) occurs has no effect on the resulting symbol binding.However, when objects have common dependencies the resultant bindings can beaffected by the order in which the dlopen (3X) calls are made.

Take for example the shared objects O.so.1 and P.so.1 , which have the samecommon dependency:

60 Linker and Libraries Guide ♦ August 1997

$ ldd O.so.1Z.so.1 => ./Z.so.1

$ ldd P.so.1Z.so.1 => ./Z.so.1

In this example, the prog application will dlopen (3X) each of these shared objects.Because the shared object Z.so.1 is a common dependency of both O.so.1 andP.so.1 , it will be assigned to both of the groups that are associated with the twodlopen (3X) calls. Diagrammatically this can be represented as:

prog A.so.1

O.so.1

P.so.1

Z.so.1

Figure 3–3 Multiple dlopen(3X) Requests With A Common Dependency

The result is that Z.so.1 will be available for both O.so.1 and P.so.1 to look upsymbols, but more importantly, as far as dlopen (3X) ordering is concerned, Z.so.1will also be able to look up symbols in both O.so.1 and P.so.1 .

Therefore, if both O.so.1 and P.so.1 contain a definition for the symbol foowhich is required for a Z.so.1 relocation, the actual binding that occurs isunpredictable because it will be affected by the order of the dlopen (3X) calls. If thefunctionality of symbol foo differs between the two shared objects in which it isdefined, the overall outcome of executing code within Z.so.1 might varydepending on the application’s dlopen (3X) ordering.

Defining a Global ObjectThe default assignment of local symbol visibility to the objects obtained by adlopen (3X) can be promoted to global by augmenting the mode argument with theRTLD_GLOBALflag. Under this mode, any objects obtained through a dlopen (3X)can be used by any other objects with world symbol search scope to locate symbols.

In addition, any object obtained by dlopen (3X) with the RTLD_GLOBALflag willalso be available for symbol lookup using dlopen(0) (see “Loading AdditionalObjects” on page 55).

Runtime Linker 61

Note - If a member of a group, having local symbol visibility, is referenced byanother group requiring global symbol visibility, the objects visibility will become aconcatenation of both local and global. This promotion of attributes will remain, evenif the global group reference is later removed.

Isolating a GroupThe default assignment of world symbol search scope to the objects obtained by adlopen (3X) can be reduced to group by augmenting the mode argument with theRTLD_GROUPflag. Under this mode, any objects obtained through a dlopen (3X)will only be allowed to look for symbols within their own group.

Objects can have the group symbol search scope assigned to them when they are builtby using the link-editors’ −B group option.

Note - If a member of a group, having group search capability, is referenced byanother group requiring world search capability, the objects search capability willbecome a concatenation of both group and world. This promotion of attributes willremain, even if the world group reference is later removed.

Object HierarchiesIf an initial object, obtained from a dlopen (3X), was to dlopen (3X) a secondaryobject, both objects would be assigned to a unique group. This situation can preventeither object from locating symbols from one-another.

In some implementations it is necessary for the initial object to export symbols forthe relocation of the secondary object. This requirement can be satisfied by one oftwo mechanisms:

� Making the initial object an explicit dependency of the second object.

� Use of the RTLD_PARENTmode flag to dlopen (3X) the secondary object.

If the initial object is an explicit dependency of the secondary object, it will also beassigned to the secondary objects’ group, and thus will be able to provide symbolsfor the secondary objects’ relocation.

However, if many objects can dlopen (3X) the secondary object, and each of theseinitial objects must export the same symbols to satisfy the secondary objects’relocation, then the secondary object cannot be assigned an explicit dependency. Inthis case, the dlopen (3X) mode of the secondary object can be augmented with theRTLD_PARENTflag. This flag causes the propagation of the secondary objects’ groupto the initial object in the same manner as an explicit dependency would do.

There is one small difference between these two techniques. In the case of specifyingan explicit dependency, the dependency itself becomes part of the secondary objects’

62 Linker and Libraries Guide ♦ August 1997

dlopen (3X) dependency tree, and thus becomes available for symbol lookup withdlopen (3X). In the case of obtaining the secondary object with RTLD_PARENT, theinitial object does not become available for symbol lookup with dlopen (3X).

Note - In the case where a secondary object is obtained by dlopen (3X) from aninitial object with global symbol visibility, the RTLD_PARENTmode is both redundantand harmless. This case commonly occurs when dlopen (3X) is called from anapplication or from one of the dependencies of the application.

Obtaining New SymbolsA process can obtain the address of a specific symbol using dlsym (3X). Thisfunction takes a handle and a symbol name, and returns the address of the symbol tothe caller. The handle directs the search for the symbol in the following manner:

� The handle returned from a dlopen (3X) of a named object will allow symbols to beobtained from that objects dependency tree.

� The handle returned from a dlopen (3X) of a file whose value is 0 will allowsymbols to be obtained from the dynamic executable, from any of its initializationdependencies, or from any object obtained by a dlopen (3X) with theRTLD_GLOBALmode.

� The special handle RTLD_DEFAULTwill allow symbols to be obtained from thedynamic executable, from any of its initialization dependencies, or from any objectobtained by a dlopen (3X) that belongs to the same group as the caller (see“Testing for Functionality” on page 64).

� The special handle RTLD_NEXTwill allow symbols to be obtained from the nextassociated object (see “Using Interposition” on page 65).

The first example is probably the most common. Here an application will addadditional objects to its address space and use dlsym (3X) to locate function or datasymbols. The application then uses these symbols to call upon services provided inthese new objects. For example, let’s take the file main.c that contains the followingcode:

#include <stdio.h>#include <dlfcn.h>

main(){

void * handle;int * dptr, (* fptr)();

if ((handle = dlopen("foo.so.1", RTLD_LAZY)) == NULL) {(void) printf("dlopen: %s\n", dlerror());exit (1);

(continued)

Runtime Linker 63

(Continuation)

}

if (((fptr = (int (*)())dlsym(handle, "foo")) == NULL) ||((dptr = (int *)dlsym(handle, "bar")) == NULL)) {

(void) printf("dlsym: %s\n", dlerror());exit (1);

}

return ((*fptr)(*dptr));}

Here the symbols foo and bar will be searched for in the file foo.so.1 followedby any dependencies that are associated with this file. The function foo is thencalled with the single argument bar as part of the return( ) statement.

If the application prog is built using the above file main.c , and its initialdependencies are:

$ ldd proglibdl.so.1 => /usr/lib/libdl.so.1libc.so.1 => /usr/lib/libc.so.1

then if the filename specified in the dlopen (3X) had the value 0, the symbols fooand bar will be searched for in prog , followed by /usr/lib/libdl.so.1 , andfinally /usr/lib/libc.so.1 .

Once the handle has indicated the root at which to start a symbol search, the searchmechanism follows the same model as was described in “Symbol Lookup” on page47.

If the required symbol cannot be located, dlsym (3X) will return a NULL value. Inthis case dlerror (3X) can be used to indicate the true reason for the failure. Forexample;

$ progdlsym: ld.so.1: main: fatal: bar: can’t find symbol

Here the application prog was unable to locate the symbol bar .

Testing for FunctionalityThe special handle RTLD_DEFAULTallows an application to test for the existence ofanother symbol. The symbol search follows the same model as used to relocate the

64 Linker and Libraries Guide ♦ August 1997

calling object (see “Relocation Processing” on page 57). For example, if theapplication prog contained the following code fragment:

if ((fptr = (int (*)())dlsym(RTLD_DEFAULT, "foo")) != NULL)(*fptr)();

then foo will be searched for in prog , followed by /usr/lib/libdl.so.1 , andthen /usr/lib/libc.so.1 . If this code fragment was contained in the file B.so.1from the example shown in Figure 3–2, then the search for foo will continue intoB.so.1 and then C.so.1 .

This mechanism provides a robust and flexible alternative to the use of undefinedweak references discussed in “Weak Symbols” on page 26.

Using InterpositionThe special handle RTLD_NEXTallows an application to locate the next symbol in asymbol scope. For example, if the application prog contained the following codefragment:

if ((fptr = (int (*)())dlsym(RTLD_NEXT, "foo")) == NULL) {(void) printf("dlsym: %s\n", dlerror());exit (1);

}

return ((*fptr)());

then foo will be searched for in the shared objects associated with prog , in this case,/usr/lib/libdl.so.1 and then /usr/lib/libc.so.1 . If this code fragmentwas contained in the file B.so.1 from the example shown in Figure 3–2, then foowill be searched for in the associated shared object C.so.1 only.

Using RTLD_NEXTprovides a means to exploit symbol interposition. For example, anobject function can be interposed upon by a preceding object, which can thenaugment the processing of the original function. If the following code fragment isplaced in the shared object malloc.so.1 :

#include <sys/types.h>#include <dlfcn.h>#include <stdio.h>

void *malloc(size_t size){

static void * (* fptr)() = 0;char buffer[50];

(continued)

Runtime Linker 65

(Continuation)

if (fptr == 0) {fptr = (void * (*)())dlsym(RTLD_NEXT, "malloc");if (fptr == NULL) {

(void) printf("dlopen: %s\n", dlerror());return (0);

}}

(void) sprintf(buffer, "malloc: %#x bytes\n", size);(void) write(1, buffer, strlen(buffer));return ((*fptr)(size));

}

Then by interposing this shared object between the system library/usr/lib/libc.so.1 where malloc (3C) usually resides, any calls to this functionwill be interposed on before the original function is called to complete the allocation:

$ cc -o malloc.so.1 -G -K pic malloc.c$ cc -o prog file1.o file2.o ..... -R. malloc.so.1$ progmalloc: 0x32 bytesmalloc: 0x14 bytes..........

Alternatively, this same interposition can be achieved by:

$ cc -o malloc.so.1 -G -K pic malloc.c$ cc -o prog main.c$ LD_PRELOAD=./malloc.so.1 progmalloc: 0x32 bytesmalloc: 0x14 bytes..........

Note - Users of any interposition technique must be careful to handle any possibilityof recursion. The previous example formats the diagnostic message usingsprintf (3S), instead of using printf (3S) directly, to avoid any recursion causedby printf (3S)’s use of malloc (3C).

The use of RTLD_NEXTwithin a dynamic executable or preloaded object provides apredictable and useful interpositioning technique. However, care should be takenwhen using this technique in a generic object dependency, as the actual load order ofobjects is not always predictable (see “Dependency Ordering” on page 77).

66 Linker and Libraries Guide ♦ August 1997

Debugging AidsProvided with the Solaris linkers is a debugging library that allows you to trace theruntime linking process in more detail. This library helps you understand, or debug,the execution of applications and dependencies. This is a visual aid, and although thetype of information displayed using this library is expected to remain constant, theexact format of the information might change slightly from release to release.

Some of the debugging output might be unfamiliar to those who do not have anintimate knowledge of the runtime linker. However, many aspects can be of generalinterest to you.

Debugging is enabled by using the environment variable LD_DEBUG. All debuggingoutput is prefixed with the process identifier and by default is directed to thestandard error. This environment variable must be augmented with one or moretokens to indicate the type of debugging required.

The tokens available with this debugging option can be displayed by usingLD_DEBUG=help. Any dynamic executable can be used to solicit this information, asthe process itself will terminate following the display of the information. For example:

$ LD_DEBUG=help prog11693:11693: For debugging the runtime linking of an application:11693: LD_DEBUG=token1,token2 prog11693: enables diagnostics to the stderr. The additional11693: option:11693: LD_DEBUG_OUTPUT=file11693: redirects the diagnostics to an output file created11593: using the specified name and the process id as a11693: suffix. All diagnostics are prepended with the11693: process id.11693:11693:11693: basic provide basic trace information/warnings11693: bindings display symbol binding; detail flag shows11693: absolute:relative addresses11693: detail provide more information in conjunction with other11693: options11693: files display input file processing (files and libraries)11693: help display this help message11693: libs display library search paths11693: reloc display relocation processing11693: symbols display symbol table processing;11693: detail flag shows resolution and linker table addition11693: versions display version processing$

Runtime Linker 67

Note - This is an example, and shows the options meaningful to the runtime linker.The exact options might differ from release to release.

The environment variable LD_DEBUG_OUTPUTcan be used to specify an output filefor use instead of the standard error. The output file name will be suffixed with theprocess identifier.

Debugging of secure applications is not allowed.

One of the most useful debugging options is to display the symbol bindings thatoccur at runtime. For example, let’s take a very trivial dynamic executable that has adependency on two local shared objects:

$ cat bar.cint bar = 10;$ cc -o bar.so.1 -Kpic -G bar.c

$ cat foo.cfoo(int data){

return (data);}$ cc -o foo.so.1 -Kpic -G foo.c

$ cat main.cextern int foo();extern int bar;

main(){

return (foo(bar));}$ cc -o prog main.c -R/tmp:. foo.so.1 bar.so.1

The runtime symbol bindings can be displayed by setting LD_DEBUG=bindings :

$ LD_DEBUG=bindings prog11753: .......11753: binding file=prog to file=./bar.so.1: symbol bar11753: .......11753: transferring control: prog11753: .......11753: binding file=prog to file=./foo.so.1: symbol foo11753: .......

Here, the symbol bar , which is required by a data relocation, is bound before theapplication gains control. Whereas the symbol foo , which is required by a functionrelocation, is bound after the application gains control when the function is first

68 Linker and Libraries Guide ♦ August 1997

called. This demonstrates the default mode of lazy binding. If the environmentvariable LD_BIND_NOWis set, all symbol bindings will occur before the applicationgains control.

Additional information regarding the real, and relative addresses of the actualbinding locations can be obtained by setting LD_DEBUG=bindings,detail .

When the runtime linker performs a function relocation it rewrites data associatedwith the functions .plt so that any subsequent calls will go directly to the function.The environment variable LD_BIND_NOTcan be set to any value to prevent this dataupdate. By using this variable together with the debugging request for detailedbindings, you can get a complete runtime account of all function binding. The outputfrom this combination can be excessive, and the performance of the application willbe degraded.

Another aspect of the runtime environment that can be displayed involves thevarious search paths used. For example, the search path mechanism used to locateany dependencies can be displayed by setting LD_DEBUG=libs :

$ LD_DEBUG=libs prog11775:11775: find library=foo.so.1; searching11775: search path=/tmp:. (RPATH from file prog)11775: trying path=/tmp/foo.so.111775: trying path=./foo.so.111775:11775: find library=bar.so.1; searching11775: search path=/tmp:. (RPATH from file prog)11775: trying path=/tmp/bar.so.111775: trying path=./bar.so.111775: .......

Here, the runpath recorded in the application prog affects the search for the twodependencies foo.so.1 and bar.so.1 .

In a similar manner, the search paths of each symbol lookup can be displayed bysetting LD_DEBUG=symbols. If this is combined with a bindings request, acomplete picture of the symbol relocation process can be obtained:

$ LD_DEBUG=bindings,symbols11782: .......11782: symbol=bar; lookup in file=./foo.so.1 [ ELF ]11782: symbol=bar; lookup in file=./bar.so.1 [ ELF ]11782: binding file=prog to file=./bar.so.1: symbol bar11782: .......11782: transferring control: prog11782: .......11782: symbol=foo; lookup in file=prog [ ELF ]11782: symbol=foo; lookup in file=./foo.so.1 [ ELF ]11782: binding file=prog to file=./foo.so.1: symbol foo

(continued)

Runtime Linker 69

(Continuation)

11782: .......

Note - In the previous example the symbol bar is not searched for in the applicationprog . This is due to an optimization used when processing copy relocations (see“Copy Relocations” on page 91 for more details of this relocation type).

70 Linker and Libraries Guide ♦ August 1997

CHAPTER 4

Shared Objects

OverviewShared objects are one form of output created by the link-editor, and are generatedby specifying the −G option. For example:

$ cc -o libfoo.so.1 -G -K pic foo.c

Here the shared object libfoo.so.1 is generated from the input file foo.c .

Note - This is a simplified example of generating a shared object. Usually, additionaloptions are recommended, and these will be discussed in subsequent sections of thischapter.

A shared object is an indivisible unit generated from one or more relocatable objects.Shared objects can be bound with dynamic executables to form a runable process. Astheir name implies, shared objects can be shared by more than one application.Because of this potentially far-reaching effect, this chapter describes this form oflink-editor output in greater depth than has been covered in previous chapters.

For a shared object to be bound to a dynamic executable or another shared object, itmust first be available to the link-edit of the required output file. During thislink-edit, any input shared objects are interpreted as if they had been added to thelogical address space of the output file being produced. That is, all the functionalityof the shared object is made available to the output file.

These shared objects become dependencies of this output file. A small amount ofbookkeeping information is maintained within the output file to describe these

71

dependencies. The runtime linker interprets this information and completes theprocessing of these shared objects as part of creating a runable process.

The following sections expand upon the use of shared objects within the compilationand runtime environments (these environments are introduced in “Shared Objects”on page 4). Issues that complement and help coordinate the use of shared objectswithin these environments are covered, together with techniques that maximize theefficiency of shared objects.

Naming ConventionsNeither the link-editor, nor the runtime linker, interprets any file by virtue of itsfilename. All files are inspected to determine their ELF type (see “ELF Header” onpage 148). From this information the processing requirements of the file are deduced.However, shared objects usually follow one of two naming conventions dependingon whether they are being used as part of the compilation environment or theruntime environment.

When used as part of the compilation environment, shared objects are read andprocessed by the link-editor. Although these shared objects can be specified byexplicit filenames as part of the command-line passed to the link-editor, it is morecommon that the −l option be used to take advantage of the link-editor’s librarysearch capabilities (see “Shared Object Processing” on page 12).

For a shared object to be applicable to this link-editor processing it should bedesignated with the prefix lib and the suffix .so . For example,/usr/lib/libc.so is the shared object representation of the standard C librarymade available to the compilation environment.

When used as part of the runtime environment, shared objects are read andprocessed by the runtime linker. Here it might be necessary to allow for change inthe exported interface of the shared object over a series of software releases. Thisinterface change can be anticipated and supported by providing the shared object asa versioned filename.

A versioned filename commonly takes the form of a .so suffix followed by a versionnumber. For example, /usr/lib/libc.so.1 is the shared object representation ofversion one of the standard C library made available to the runtime environment.

If a shared object is never intended for use within a compilation environment itsname might drop the conventional lib prefix. Examples of shared objects that fallinto this category are those used solely with dlopen (3X). A suffix of .so is stillrecommended to indicate the actual file type, and a version number is stronglyrecommended to provide for the correct binding of the shared object across a seriesof software releases.

72 Linker and Libraries Guide ♦ August 1997

Note - The shared object name used in a dlopen (3X) is usually represented as asimple filename - in other words there is no ‘/’ in the name. This convention providesflexibility by allowing the runtime linker to use a set of rules to locate the actual file(see “Loading Additional Objects” on page 51 for more details).

In Chapter 5 the concept of versioning a shared objects interface over a series ofsoftware releases is described in more detail. In addition, a mechanism forcoordinating the naming conventions between shared objects used in both thecompilation and runtime environments is presented. But first, a mechanism thatallows a shared object to record its own runtime name is described.

Recording a Shared Object NameThe recording of a dependency in a dynamic executable or shared object will, bydefault, be the filename of the associated shared object as it is referenced by thelink-editor. For example, the following dynamic executables, built against the sameshared object libfoo.so , result in different interpretations of the same dependency:

$ cc -o ../tmp/libfoo.so -G foo.o$ cc -o prog main.o -L../tmp -lfoo$ dump -Lv prog | grep NEEDED[1] NEEDED libfoo.so

$ cc -o prog main.o ../tmp/libfoo.so$ dump -Lv prog | grep NEEDED[1] NEEDED ../tmp/libfoo.so

$ cc -o prog main.o /usr/tmp/libfoo.so$ dump -Lv prog | grep NEEDED[1] NEEDED /usr/tmp/libfoo.so

As these examples show, this mechanism of recording dependencies can result ininconsistencies due to different compilation techniques. Also, the location of a sharedobject as referenced during the link-edit might differ from the eventual location ofthe shared object on an installed system.

To provide a more consistent means of specifying dependencies, shared objects canrecord within themselves the filename by which they should be referenced at runtime.

During the link-edit of a shared object, its runtime name can be recorded within theshared object itself by using the −h option. For example:

$ cc -o ../tmp/libfoo.so -G -K pic -h libfoo.so.1 foo.c

Shared Objects 73

Here, the shared object’s runtime name libfoo.so.1 , is recorded within the fileitself. This identification is known as an soname, and its recording can be displayedusing dump(1) and referring to the entry that has the SONAMEtag. For example:

$ dump -Lvp ../tmp/libfoo.so

../tmp/libfoo.so:[INDEX] Tag Value[1] SONAME libfoo.so.1.........

When the link-editor processes a shared object that contains an soname, it is thisname that is recorded as a dependency within the output file being generated.

Therefore, if this new version of libfoo.so is used during the creation of thedynamic executable prog from the previous example, all three methods of buildingthe executable result in the same dependency recording:

$ cc -o prog main.o -L../tmp -lfoo$ dump -Lv prog | grep NEEDED[1] NEEDED libfoo.so.1

$ cc -o prog main.o ../tmp/libfoo.so$ dump -Lv prog | grep NEEDED[1] NEEDED libfoo.so.1

$ cc -o prog main.o /usr/tmp/libfoo.so$ dump -Lv prog | grep NEEDED[1] NEEDED libfoo.so.1

In the examples shown above, the −h option is used to specify a simple filename - inother words there is no ‘/’ in the name. This convention is recommended, as itprovides flexibility by allowing the runtime linker to use a set of rules to locate theactual file (see “Locating Shared Object Dependencies” on page 44 for more details).

Inclusion of Shared Objects in ArchivesThe mechanism of recording an soname within a shared object is essential if theshared object is ever processed from an archive library.

An archive can be built from one or more shared objects and then used to generate adynamic executable or shared object. Shared objects can be extracted from the archiveto satisfy the requirements of the link-edit (see “Archive Processing” on page 11 formore details on the criteria for archive extraction). However, unlike the processing ofrelocatable objects, which are concatenated to the output file being created, anyshared objects extracted from the archive will be recorded as dependencies.

74 Linker and Libraries Guide ♦ August 1997

The name of an archive member is constructed by the link-editor and is aconcatenation of the archive name and the object within the archive. For example:

$ cc -o libfoo.so.1 -G -K pic foo.c$ ar -r libfoo.a libfoo.so.1$ cc -o main main.o libfoo.a$ dump -Lv main | grep NEEDED[1] NEEDED libfoo.a(libfoo.so.1)

As it is highly unlikely that a file with this concatenated name will exist at runtime,providing an soname within the shared object is the only means of generating ameaningful runtime filename for the dependency.

Note - The runtime linker does not extract objects from archives. Therefore, in theabove example it will be necessary for the required shared object dependencies to beextracted from the archive and made available to the runtime environment.

Recorded Name ConflictsWhen shared objects are used to build a dynamic executable or another sharedobject, the link-editor performs several consistency checks to insure that anydependency names that will be recorded in the output file are unique.

Conflicts in dependency names can occur if two shared objects used as input files toa link-edit both contain the same soname. For example:

$ cc -o libfoo.so -G -K pic -h libsame.so.1 foo.c$ cc -o libbar.so -G -K pic -h libsame.so.1 bar.c$ cc -o prog main.o -L. -lfoo -lbarld: fatal: file ./libbar.so: recording name ‘libsame.so.1’ \

matches that provided by file ./libfoo.sold: fatal: File processing errors. No output written to prog

A similar error condition will occur if the filename of a shared object that does nothave a recorded soname matches the soname of another shared object used during thesame link-edit.

If the runtime name of a shared object being generated matches one of itsdependencies the link-editor will also report a name conflict. For example:

Shared Objects 75

$ cc -o libbar.so -G -K pic -h libsame.so.1 bar.c -L. -lfoold: fatal: file ./libfoo.so: recording name ‘libsame.so.1’ \

matches that supplied with -h optionld: fatal: File processing errors. No output written to libfoo.so

Shared Objects with DependenciesAlthough most of the examples presented in this chapter so far have shown howshared object dependencies are maintained in dynamic executables, it is quitecommon for shared objects to have their own dependencies (this was introduced in“Shared Object Processing” on page 12).

In “Directories Searched by the Runtime Linker” on page 44 the search rules used bythe runtime linker to locate shared object dependencies are covered. If a sharedobject does not reside in the default directory /usr/lib , then the runtime linkermust explicitly be told where to look. The preferred mechanism of indicating anyrequirement of this kind is to record a runpath in the object that has the dependenciesby using the link-editor’s −R option. For example:

$ cc -o libbar.so -G -K pic bar.c$ cc -o libfoo.so -G -K pic foo.c -R/home/me/lib -L. -lbar$ dump -Lv libfoo.so

libfoo.so:

**** DYNAMIC SECTION INFORMATION ****.dynamic:[INDEX] Tag Value[1] NEEDED libbar.so[2] RPATH /home/me/lib.........

Here, the shared object libfoo.so has a dependency on libbar.so , which isexpected to reside in the directory /home/me/lib at runtime.

It is the responsibility of the shared object to specify any runpath required to locateits dependencies. Any runpath specified in the dynamic executable will only be usedto locate the dependencies of the dynamic executable, it will not be used to locateany dependencies of the shared objects.

However, the environment variable LD_LIBRARY_PATHhas a more global scope, andany pathnames specified using this variable will be used by the runtime linker tosearch for any shared object dependencies. Although useful as a temporary mechanismof influencing the runtime linker’s search path, the use of this environment variableis strongly discouraged in production software (see “Directories Searched by theRuntime Linker” on page 44 for a more extensive discussion).

76 Linker and Libraries Guide ♦ August 1997

Dependency OrderingIn most of the examples in this document, dependencies of dynamic executables andshared objects are portrayed as unique and relatively simple (the breadth-firstordering of dependent shared objects is described in “Locating Shared ObjectDependencies” on page 44). From these examples, the ordering of shared objects asthey are brought into the process address space might seem very intuitive andpredictable.

However, when dynamic executables and shared objects have dependencies on thesame common shared objects, the order in which the objects are processed canbecome less predictable.

For example, assume a shared object developer generates libfoo.so.1 with thefollowing dependencies:

$ ldd libfoo.so.1libA.so.1 => ./libA.so.1libB.so.1 => ./libB.so.1libC.so.1 => ./libC.so.1

If you create a dynamic executable, prog , using this shared object, and also define anexplicit dependency on libC.so.1 , then the resulting shared object order will be:

$ cc -o prog main.c -R. -L. -lC -lfoo$ ldd prog

libC.so.1 => ./libC.so.1libfoo.so.1 => ./libfoo.so.1libA.so.1 => ./libA.so.1libB.so.1 => ./libB.so.1

Therefore, had the developer of the shared object libfoo.so.1 placed arequirement on the order of processing of its dependencies, this requirement will becompromised by the construction of the dynamic executable prog .

Developers who place special emphasis on symbol interposition (see “SymbolLookup” on page 47, “Symbol Lookup” on page 57 and “Using Interposition” onpage 65) and .init section processing (see “Initialization and TerminationRoutines” on page 52) should be aware of this potential change in shared objectprocessing order.

Shared Objects 77

Shared Objects as FiltersA filter is a special form of shared object used to provide indirection to an alternativeshared object. Two forms of shared object filter exist:

� a standard filter

� an auxiliary filter

A standard filter, in essence, consists solely of a symbol table, and provides amechanism of abstracting the compilation environment from the runtimeenvironment. A link-edit using the filter will reference the symbols provided by thefilter itself, however the implementation of the symbol reference is provided from analternative source at runtime.

Standard filters are identified using the link-editor’s −F flag. This flag takes anassociated filename indicating the shared object that will supply symbol references atruntime. This shared object is referred to as the filtee. Multiple use of the −F flagallows multiple filtees to be recorded.

If the filtee cannot be processed at runtime, or any symbol defined by the filtercannot be located within the filtee, the filter is ignored and symbol resolutioncontinues to the next associated dependency.

An auxiliary filter has a similar mechanism, however the filter itself contains animplementation corresponding to its symbols. A link-edit using the filter willreference the symbols provided by the filter itself, however the implementation ofthe symbol reference can be provided from an alternative source at runtime.

Auxiliary filters are identified using the link-editor’s −f flag. This flag takes anassociated filename indicating the shared object that can be used to supply symbolsat runtime. This shared object is referred to as the filtee. Multiple use of the −f flagallows multiple filtees to be recorded.

If the filtee cannot be processed at runtime, or any symbol defined by the filtercannot be located within the filtee, the implementation of the symbol within the filterwill be used.

Generating a Standard FilterFirst let’s define a filtee, libbar.so.1 , on which this filter technology will beapplied. This filtee might be built from several relocatable objects. One of theseobjects originates from the file bar.c , and supplies the symbols foo and bar :

$ cat bar.cchar * bar = "bar";

(continued)

78 Linker and Libraries Guide ♦ August 1997

(Continuation)

char * foo(){

return("defined in bar.c");}$ cc -o libbar.so.1 -G -K pic .... bar.c ....

A standard filter, libfoo.so.1 , is generated for the symbols foo and bar , andindicates the association to the filtee libbar.so.1 . For example:

$ cat foo.cchar * bar = 0;

char * foo(){}

$ LD_OPTIONS=’-F libbar.so.1’ \cc -o libfoo.so.1 -G -K pic -h libfoo.so.1 -R. foo.c$ ln -s libfoo.so.1 libfoo.so$ dump -Lv libfoo.so.1 | egrep "SONAME|FILTER"[1] SONAME libfoo.so.1[2] FILTER libbar.so.1

Note - Here the environment variable LD_OPTIONSis used to circumvent thiscompiler driver from interpreting the −F option as one of its own.

If the link-editor references the standard filter libfoo.so.1 to build a dynamicexecutable or shared object, it will use the information from the filters symbol tableduring symbol resolution (see “Symbol Resolution” on page 19 for more details).

At runtime, any reference to the symbols of the filter will result in the additionalloading of the filtee libbar.so.1 . The runtime linker will use this filtee to resolveany symbols defined by libfoo.so.1 .

For example, the following dynamic executable, prog , references the symbols fooand bar which are resolved during link-edit from the filter libfoo.so.1 :

$ cat main.cextern char * bar, * foo();

main(){(void) printf("foo() is %s: bar=%s\n", foo(), bar);

}$ cc -o prog main.c -R. -L. -lfoo$ prog

Shared Objects 79

(Continuation)

foo() is defined in bar.c: bar=bar

The execution of the dynamic executable prog results in the function foo() , andthe data item bar , being obtained from the filtee libbar.so.1 , not from the filterlibfoo.so.1 .

Note - In this example, the filtee libbar.so.1 is uniquely associated to the filterlibfoo.so.1 and is not available to satisfy symbol lookup from any other objectsthat might be loaded as a consequence of executing prog .

Standard filters provide a mechanism for defining a subset interface of an existingshared object, or an interface group spanning a number of existing shared objects.Two filters used in Solaris are /usr/lib/libsys.so.1 and/usr/lib/libdl.so.1 .

The former provides a subset of the standard C library /usr/lib/libc.so.1 . Thissubset represents the ABI-conforming functions and data items that reside in the Clibrary that must be imported by a conforming application.

The latter defines the user interface to the runtime linker itself. This interfaceprovides an abstraction between the symbols referenced in a compilationenvironment (from libdl.so.1 ) and the actual implementation binding producedwithin the runtime environment (from ld.so.1 ).

An example of a filter that uses mutiple filtees is /usr/lib/libxnet.so.1 . Thislibrary provides socket and XTI interfaces from /usr/lib/libsocket.so.1 ,/usr/lib/libnsl.so.1 , and /usr/lib/libc.so.1 .

As any code in a standard filter is never referenced at runtime, there is no point inadding content to any functions defined within the filter. Any filter code mightrequire relocation, which will result in an unnecessary overhead when processing thefilter at runtime. Functions are best defined as empty routines.

Care should also be taken when generating the data symbols within a filter. Dataitems should always be initialized to insure that they result in references fromdynamic executables.

Some of the more complex symbol resolutions carried out by the link-editor requireknowledge of a symbol’s attributes, including the symbols size (see “SymbolResolution” on page 19 for more details). Therefore, it is recommended that thesymbols in the filter be generated so that their attributes match those of the symbolsin the filtee. This insures that the link-editing process will analyze the filter in amanner compatible with the symbol definitions used at runtime.

80 Linker and Libraries Guide ♦ August 1997

Generating an Auxiliary FilterThe creation of an auxiliary filter is essentially the same as for a standard filter (see“Generating a Standard Filter” on page 78 for more details). First let’s define a filtee,libbar.so.1 , on which this filter technology will be applied. This filtee might bebuilt from several relocatable objects. One of these objects originates from the filebar.c , and supplies the symbol foo :

$ cat bar.cchar * foo(){

return("defined in bar.c");}$ cc -o libbar.so.1 -G -K pic .... bar.c ....

An auxiliary filter, libfoo.so.1 , is generated for the symbols foo and bar , andindicates the association to the filtee libbar.so.1 . For example:

$ cat foo.cchar * bar = "foo";

char * foo(){

return ("defined in foo.c");}$ LD_OPTIONS=’-f libbar.so.1’ \cc -o libfoo.so.1 -G -K pic -h libfoo.so.1 -R. foo.c$ ln -s libfoo.so.1 libfoo.so$ dump -Lv libfoo.so.1 | egrep "SONAME|AUXILIARY"[1] SONAME libfoo.so.1[2] AUXILIARY libbar.so.1

Note - Here the environment variable LD_OPTIONSis used to circumvent thiscompiler driver from interpreting the −f option as one of its own.

If the link-editor references the auxiliary filter libfoo.so.1 to build a dynamicexecutable or shared object, it will use the information from the filters symbol tableduring symbol resolution (see “Symbol Resolution” on page 19 for more details).

At runtime, any reference to the symbols of the filter will result in a search for thefiltee libbar.so.1 . If this filtee is found the runtime linker will use this filtee toresolve any symbols defined by libfoo.so.1 . If the filtee is not found, or a symbolfrom the filter is not found in the filtee, then the original value of the symbol withinthe filter is used.

For example, the following dynamic executable, prog , references the symbols fooand bar which are resolved during link-edit from the filter libfoo.so.1 :

Shared Objects 81

$ cat main.cextern char * bar, * foo();

main(){(void) printf("foo() is %s: bar=%s\n", foo(), bar);

}$ cc -o prog main.c -R. -L. -lfoo$ progfoo() is defined in bar.c: bar=foo

The execution of the dynamic executable prog results in the function foo() beingobtained from the filtee libbar.so.1 , not from the filter libfoo.so.1 . However,the data item bar is obtained from the filter libfoo.so.1 , as this symbol has noalternative definition in the filtee libbar.so.1 .

Auxiliary filters provide a mechanism for defining an alternative interface of anexisting shared object. This mechanism is used in Solaris to provide optimizedfunctionality within platform specific shared objects.

Note - The environment variable LD_NOAUXFLTRcan be set to disable the runtimelinkers auxiliary filter processing. This may be useful in evaluating a filtees use andperformance impact.

Platform Specific Shared ObjectsAn extension to the auxiliary filter naming mechanism provides for the use of thereserved token $PLATFORM. This token is expanded at runtime to reflect theunderlying hardware implementation as displayed by the utility uname(1) with the−i option.

The following example shows how the auxiliary filter libfoo.so.1 can bedesigned to access a platform specific filtee libbar.so.1 :

$ LD_OPTIONS=’-f /usr/platform/$PLATFORM/lib/libbar.so.1’ \cc -o libfoo.so.1 -G -K pic -h libfoo.so.1 -R. foo.c$ dump -Lv libfoo.so.1 | egrep "SONAME|AUXILIARY"[1] SONAME libfoo.so.1[2] AUXILIARY /usr/platform/$PLATFORM/lib/libbar.so.1

This mechanism is used on Solaris to provide platform specific extensions to theshared object /usr/lib/libc.so.1 .

82 Linker and Libraries Guide ♦ August 1997

Filtee ProcessingThe runtime linkers processing of a filter defers the loading of a filtee until areference to a symbol within the filter has occurred. This implementation isanalogous to the filter performing a dlopen (3X) on each of its filtees as they arerequired. This implementation accounts for differences in dependency reporting thatcan be produced by tools such as ldd (1).

By default, ldd (1) lists the dependencies of a dynamic object, and thus reports afilter as it would any other dependency. However, use of the −d or −r options mayresult in relocation processing that will cause a symbol lookup in the filter. In thiscase filtee processing will be triggered which can result in additional dependenciesbeing reported by ldd (1). To insure immediate processing of any filtee the −l optioncan be used.

The link-editors’ −z loadfltr option can be used when creating a filter to causethe immediate processing of its filtees at runtime. In addition, the immediateprocessing of any filtees within a process can be triggered by setting theLD_LOADFLTRenvironment variable.

Performance ConsiderationsA shared object can be used by multiple applications within the same system. Theperformance of a shared object therefore can have far reaching effects, not only onthe applications that use it, but on the system as a whole.

Although the actual code within a shared object will directly affect the performanceof a running process, the performance issues focused upon here target the runtimeprocessing of the shared object itself. The following sections investigate thisprocessing in more detail by looking at aspects such as text size and purity, togetherwith relocation overhead.

Useful ToolsBefore discussing performance it is useful to be aware of some available tools andtheir use in analyzing the contents of an ELF file.

Frequently reference is made to the size of either the sections or the segments that aredefined within an ELF file (for a complete description of the ELF format see Chapter7). The size of a file can be displayed using the size (1) command. For example:

$ size -x libfoo.so.159c + 10c + 20 = 0x6c8

(continued)

Shared Objects 83

(Continuation)

$ size -xf libfoo.so.1..... + 1c(.init) + ac(.text) + c(.fini) + 4(.rodata) + \..... + 18(.data) + 20(.bss) .....

The first example indicates the size of the shared objects text, data and bss, acategorization that has traditionally been used throughout previous releases of theSunOS operating system. The ELF format provides a finer granularity for expressingdata within a file by organizing the data into sections. The second example displaysthe size of each of the file’s loadable sections.

Sections are allocated to units known as segments, some of which describe howportions of a file will be mapped into memory. These loadable segments can bedisplayed by using the dump(1) command and examining the LOADentries. Forexample:

$ dump -ov libfoo.so.1

libfoo.so.1:***** PROGRAM EXECUTION HEADER *****

Type Offset Vaddr PaddrFilesz Memsz Flags Align

LOAD 0x94 0x94 0x00x59c 0x59c r-x 0x10000

LOAD 0x630 0x10630 0x00x10c 0x12c rwx 0x10000

Here, there are two segments in the shared object libfoo.so.1 , commonly referredto as the text and data segments. The text segment is mapped to allow reading andexecution of its contents (r-x ), whereas the data segment is mapped to allow itscontents to be modified (rwx ). Notice that the memory size (Memsz) of the datasegment differs from the file size (Filesz). This difference accounts for the .bsssection, which is actually part of the data segment.

Programmers however, usually think of a file in terms of the symbols that define thefunctions and data elements within their code. These symbols can be displayed usingnm(1). For example:

84 Linker and Libraries Guide ♦ August 1997

$ nm -x libfoo.so.1

[Index] Value Size Type Bind Other Shndx Name.........[39] |0x00000538|0x00000000|FUNC |GLOB |0x0 |7 |_init[40] |0x00000588|0x00000034|FUNC |GLOB |0x0 |8 |foo[41] |0x00000600|0x00000000|FUNC |GLOB |0x0 |9 |_fini

[42] |0x00010688|0x00000010|OBJT |GLOB |0x0 |13 |data[43] |0x0001073c|0x00000020|OBJT |GLOB |0x0 |16 |bss.........

The section that contains a symbol can be determined by referencing the sectionindex (Shndx) field from the symbol table and by using dump(1) to display thesections within the file. For example:

$ dump -hv libfoo.so.1

libfoo.so.1:**** SECTION HEADER TABLE ****

[No] Type Flags Addr Offset Size Name.........[7] PBIT -AI 0x538 0x538 0x1c .init

[8] PBIT -AI 0x554 0x554 0xac .text

[9] PBIT -AI 0x600 0x600 0xc .fini.........[13] PBIT WA- 0x10688 0x688 0x18 .data

[16] NOBI WA- 0x1073c 0x73c 0x20 .bss.........

Using the output from both the previous nm(1) and dump(1) examples, theassociation of the functions _init , foo and _fini to the sections .init , .textand .fini can be seen. These sections, because of their read-only nature, are part ofthe text segment.

Similarly, it can be seen that the data arrays data and bss are associated with thesections .data and .bss respectively. These sections, because of their writablenature, are part of the data segment.

Note - The previous dump(1) display has been simplified for this example.

Armed with this tool information, you can analyze the location of code and datawithin any ELF file you generate. This knowledge will be useful when following thediscussions in later sections.

Shared Objects 85

The Underlying SystemWhen an application is built using a shared object, the entire loadable contents of theobject are mapped into the virtual address space of that process at run time. Eachprocess that uses a shared object starts by referencing a single copy of the sharedobject in memory.

Relocations within the shared object are processed to bind symbolic references totheir appropriate definitions. This results in the calculation of true virtual addresseswhich could not be derived at the time the shared object was generated by thelink-editor. These relocations usually result in updates to entries within the process’sdata segment(s).

The memory management scheme underlying the dynamic linking of shared object’sshare memory among processes at the granularity of a page. Memory pages can beshared as long as they are not modified at runtime. If a process writes to a page of ashared object when writing a data item, or relocating a reference to a shared object, itgenerates a private copy of that page. This private copy will have no effect on otherusers of the shared object, however, this page will have lost any benefit of sharingbetween other processes. Text pages that become modified in this manner arereferred to as impure.

The segments of a shared object that are mapped into memory fall into two basiccategories; the text segment, which is read-only, and the data segment which isread-write (see “Useful Tools” on page 83 on how to obtain this information from anELF file). An overriding goal when developing a shared object is to maximize the textsegment and minimize the data segment. This optimizes the amount of code sharingwhile reducing the amount of processing needed to initialize and use a shared object.The following sections present mechanisms that can help achieve this goal.

Position-Independent CodeTo create programs that require the smallest amount of page modification at run time,the compiler will generate position-independent code under the −K pic option.Whereas the code within a dynamic executable is usually tied to a fixed address inmemory, position-independent code can be loaded anywhere in the address space ofa process. Because the code is not tied to a specific address, it will execute correctlywithout page modification at a different address in each process that uses it.

When you use position-independent code, relocatable references are generated in theform of an indirection which will use data in the shared object’s data segment. Theresult is that the text segment code will remain read-only, and all relocation updateswill be applied to corresponding entries within the data segment. See “Global OffsetTable (Processor-Specific)” on page 218 and “Procedure Linkage Table(Processor-Specific)” on page 219 for more details on the use of these two sections.

If a shared object is built from code that is not position-independent, the textsegment will usually require a large number of relocations to be performed at

86 Linker and Libraries Guide ♦ August 1997

runtime. Although the runtime linker is equipped to handle this, the systemoverhead this creates can cause serious performance degradation.

A shared object that requires relocations against its text segment can be identified byusing dump(1) and inspecting the output for any TEXTRELentry. For example:

$ cc -o libfoo.so.1 -G -R. foo.c$ dump -Lv libfoo.so.1 | grep TEXTREL[9] TEXTREL 0

Note - The value of the TEXTRELentry is irrelevant, its presence in a shared objectindicates that text relocations exist.

A recommended practice to prevent the creation of a shared object that contains textrelocations is to use the link-editor’s −z text flag. This flag causes the link-editor togenerate diagnostics indicating the source of any non position-independent code usedas input, and results in a failure to generate the intended shared object. For example:

$ cc -o libfoo.so.1 -z text -G -R. foo.cText relocation remains referenced

against symbol offset in filefoo 0x0 foo.obar 0x8 foo.old: fatal: relocations remain against allocatable but \non-writable sections

Here, two relocations are generated against the text segment because of thenon-position-independent code generated from the file foo.o . Where possible, thesediagnostics will indicate any symbolic references that are required to carry out therelocations. In this case the relocations are against the symbols foo and bar .

Besides not using the −K pic option, the most common cause of creating textrelocations when generating a shared object is by including hand written assemblercode that has not been coded with the appropriate position-independent prototypes.

Note - By using the compiler’s ability to generate an intermediate assembler file, thecoding techniques used to enable position-independence can usually be revealed byexperimenting with some simple test case source files.

A second form of the position-independence flag, −K PIC, is also available on someprocessors, and provides for a larger number of relocations to be processed at thecost of some additional code overhead (see cc (1) for more details).

Shared Objects 87

Maximizing ShareabilityAs mentioned in “The Underlying System” on page 86 only a shared object’s textsegment is shared by all processes that use it, its data segment typically is not. Eachprocess that uses a shared object usually generates a private memory copy of itsentire data segment as data items within the segment are written to. A goal is toreduce the data segment, either by moving data elements that will never be writtento the text segment, or by removing the data items completely.

The following sections cover several mechanisms that can be used to reduce the sizeof the data segment.

Move Read-Only Data to Text

Any data elements that are read-only should be moved into the text segment. Thiscan be achieved using const declarations. For example, the following characterstring will reside in the .data section, which is part of the writable data segment:

char * rdstr = "this is a read-only string";

whereas, the following character string will reside in the .rodata section, which isthe read-only data section contained within the text segment:

const char * rdstr = "this is a read-only string";

Although reducing the data segment by moving read-only elements into the textsegment is an admirable goal, moving data elements that require relocations can becounter productive. For example, given the array of strings:

char * rdstrs[] = { "this is a read-only string","this is another read-only string" };

it might at first seem that a better definition is:

const char * const rdstrs[] = { ..... };

thereby insuring that the strings and the array of pointers to these strings are placedin a .rodata section. The problem with this definition is that even though the userperceives the array of addresses as read-only, these addresses must be relocated atruntime. This definition will therefore result in the creation of text relocations. Thisdefinition is best represented as:

const char * rdstrs[] = { ..... };

so that the array strings are maintained in the read-only text segment, but the arraypointers are maintained in the writable data segment where they can be safelyrelocated.

88 Linker and Libraries Guide ♦ August 1997

Note - Some compilers, when generating position-independent code, can detectread-only assignments that will result in runtime relocations, and will arrange forplacing such items in writable segments (for example .picdata ).

Collapse Multiply-Defined DataData can be reduced by collapsing multiply-defined data. A program with multipleoccurrences of the same error messages can be better off by defining one globaldatum, and have all other instances reference this. For example:

const char * Errmsg = "prog: error encountered: %d";

foo(){

......(void) fprintf(stderr, Errmsg, error);......

The main candidates for this sort of data reduction are strings. String usage in ashared object can be investigated using strings (1). For example:

$ strings -10 libfoo.so.1 | sort | uniq -c | sort -rn

will generate a sorted list of the data strings within the file libfoo.so.1 . Eachentry in the list is prefixed with the number of occurrences of the string.

Use Automatic VariablesPermanent storage for data items can be removed entirely if the associatedfunctionality can be designed to use automatic (stack) variables. Any removal ofpermanent storage will usually result in a corresponding reduction in the number ofruntime relocations required.

Allocate Buffers DynamicallyLarge data buffers should usually be allocated dynamically rather than being definedusing permanent storage. Often this will result in an overall saving in memory, asonly those buffers needed by the present invocation of an application will beallocated. Dynamic allocation also provides greater flexibility by allowing the buffer’ssize to change without effecting compatibility.

Shared Objects 89

Minimizing Paging ActivityMany of the mechanisms discussed in the previous section “MaximizingShareability” on page 88 will help reduce the amount of paging encountered whenusing shared objects. Here some additional generic software performanceconsiderations are covered.

Any process that accesses a new page will cause a page fault. As this is an expensiveoperation, and because shared objects can be used by many processes, any reductionin the number of page faults generated by accessing a shared object will benefit theprocess and the system as a whole.

Organizing frequently used routines and their data to an adjacent set of pages willfrequently improve performance because it improves the locality of reference. Whena process calls one of these functions it might already be in memory because of itsproximity to the other frequently used functions. Similarly, grouping interrelatedfunctions will improve locality of references. For example, if every call to thefunction foo() results in a call to the function bar() , place these functions on thesame page. Tools like cflow (1), tcov (1), prof (1) and gprof (1) are useful indetermining code coverage and profiling.

It is also advisable to isolate related functionality to its own shared object. Thestandard C library has historically been built containing many unrelated functions,and only rarely, for example, will any single executable use everything in this library.Because of its widespread use, it is also somewhat difficult to determine what set offunctions are really the most frequently used. In contrast, when designing a sharedobject from scratch it is better to maintain only related functions within the sharedobject. This will improve locality of reference and usually has the side effect ofreducing the object’s overall size.

RelocationsIn “Relocation Processing” on page 46 the mechanisms by which the runtime linkerrelocates dynamic executables and shared objects to create a runable process wascovered. “Symbol Lookup” on page 47 and “When Relocations are Performed” onpage 48 categorized this relocation processing into two areas to simplify and helpillustrate the mechanisms involved. These same two categorizations are also ideallysuited for considering the performance impact of relocations.

Symbol LookupWhen the runtime linker needs to look up a symbol, it does so by searching in eachobject, starting with the dynamic executable, and progressing through each sharedobject in the same order that the objects are mapped. In many instances the sharedobject that requires a symbolic relocation will turn out to be the provider of thesymbol definition.

90 Linker and Libraries Guide ♦ August 1997

If this is the case, and the symbol used for this relocation is not required as part ofthe shared object’s interface, then this symbol is a strong candidate for conversion toa static or automatic variable. A symbol reduction can also be applied to removedsymbols from a shared objects interface (see “Reducing Symbol Scope” on page 33for more details). By making these conversions the link-editor will incur the expenseof processing any symbolic relocation against these symbols during the sharedobject’s creation.

The only global data items that should be visible from a shared object are those thatcontribute to its user interface. However, frequently this is a hard goal to accomplish,as global data are often defined to allow reference from two or more functionslocated in different source files. Nevertheless, any reduction in the number of globalsymbols exported from a shared object will result in lower relocation costs and anoverall performance improvement.

When Relocations are PerformedAll data reference relocations must be carried out during process initialization beforethe application gains control, whereas any function reference relocations can bedeferred until the first instance of a function being called. By reducing the number ofdata relocations, the runtime initialization of a process will be reduced.

Initialization relocation costs can also be deferred by converting data relocations intofunction relocations, for example, by returning data items by a functional interface.This conversion usually results in a perceived performance improvement as theinitialization relocation costs are effectively spread throughout the process’s lifetime.It is also possible that some of the functional interfaces will never be called by aparticular invocation of a process, thus removing their relocation overhead altogether.

The advantage of using a functional interface can be seen in the next section “CopyRelocations” on page 91. This section examines a special, and somewhat expensive,relocation mechanism employed between dynamic executables and shared objects,and provides an example of how this relocation overhead can be avoided.

Copy RelocationsShared objects are usually built with position-independent code. References toexternal data items from code of this type employs indirect addressing through a setof tables (see “Position-Independent Code” on page 86 for more details). These tablesare updated at runtime with the real address of the data items, which allows accessto the data without the code itself being modified.

Dynamic executables however, are generally not created from position-independentcode. Therefore it would seem that any references to external data they make canonly be achieved at runtime by modifying the code that makes the reference.Modifying any text segment is something to be avoided, and so a relocationtechnique is employed to solve this reference which is known as a copy relocation.

Shared Objects 91

When the link-editor is used to build a dynamic executable, and a reference to a dataitem is found to reside in one of the dependent shared objects, space is allocated inthe dynamic executable’s .bss , equivalent in size to the data item found in theshared object. This space is also assigned the same symbolic name as defined in theshared object. Along with this data allocation, the link-editor generates a special copyrelocation record that will instruct the runtime linker to copy the data from theshared object to this allocated space within the dynamic executable.

Because the symbol assigned to this space is global, it will be used to satisfy anyreferences from any shared objects. The effect of this is that the dynamic executableinherits the data item, and any other objects within the process that make referenceto this item will be bound to this copy. The original data from which the copy ismade effectively becomes unused.

This mechanism is best explained with an example. This example uses an array ofsystem error messages that is maintained within the standard C library. In previousSunOS operating system releases, the interface to this information was provided bytwo global variables, sys_errlist[] , and sys_nerr . The first variable providedthe array of error message strings, while the second conveyed the size of the arrayitself. These variables were commonly used within an application in the followingmanner:

$ cat foo.cextern int sys_nerr;extern char * sys_errlist[];

char *error(int errnumb){

if ((errnumb < 0) || (errnumb >= sys_nerr))return (0);

return (sys_errlist[errnumb]);}

Here the application is using the function error to provide a focal point to obtainthe system error message associated with the number errnumb .

Examining a dynamic executable built using this code shows the implementation ofthe copy relocation in more detail:

$ cc -o prog main.c foo.c$ nm -x prog | grep sys_[36] |0x00020910|0x00000260|OBJT |WEAK |0x0 |16 |sys_errlist[37] |0x0002090c|0x00000004|OBJT |WEAK |0x0 |16 |sys_nerr$ dump -hv prog | grep bss[16] NOBI WA- 0x20908 0x908 0x268 .bss$ dump -rv prog

**** RELOCATION INFORMATION ****

(continued)

92 Linker and Libraries Guide ♦ August 1997

(Continuation)

.rela.bss:Offset Symndx Type Addend

0x2090c sys_nerr R_SPARC_COPY 00x20910 sys_errlist R_SPARC_COPY 0..........

Here the link-editor has allocated space in the dynamic executable’s .bss to receivethe data represented by sys_errlist and sys_nerr . These data will be copiedfrom the C library by the runtime linker at process initialization. Thus, eachapplication that uses these data will get a private copy of the data in its own datasegment.

There are actually two downsides to this technique. First, each application pays aperformance penalty for the overhead of copying the data at run time. Secondly, thesize of the data array sys_errlist has now become part of the C library’s interface.If the size of this array were to change, presumably as new error messages are added,any dynamic executables that reference this array have to undergo a new link-edit tobe able to access any of the new error messages. Without this new link-edit, theallocated space within the dynamic executable is insufficient to hold the new data.

These drawbacks can be eliminated if the data required by a dynamic executable areprovided by a functional interface. The ANSI C function strerror (3C) illustratesthis point. This function is implemented such that it will return a pointer to theappropriate error string based on the error number supplied to it. Oneimplementation of this function might be:

$ cat strerror.cstatic const char * sys_errlist[] = {

"Error 0","Not owner","No such file or directory",......

};static const int sys_nerr =

sizeof (sys_errlist) / sizeof (char *);

char *strerror(int errnum){

if ((errnum < 0) || (errnum >= sys_nerr))return (0);

return ((char *)sys_errlist[errnum]);}

Shared Objects 93

The error routine in foo.c can now be simplified to use this functional interface,which in turn will remove any need to perform the original copy relocations atprocess initialization.

Additionally, because the data are now local to the shared object the data are nolonger part of its interface, which allows the shared object the flexibility of changingthe data without adversely effecting any dynamic executables that use it. Eliminatingdata items from a shared object’s interface will generally improve performance whilemaking the shared object’s interface and code easier to maintain.

Although copy relocations should be avoided, ldd (1), when used with either the −dor −r options, can be used to verify any that exist within a dynamic executable.

For example, if the dynamic executable prog had originally been built against theshared object libfoo.so.1 such that the following two copy relocations had beenrecorded:

$ nm -x prog | grep _size_[36] |0x000207d8|0x40|OBJT |GLOB |15 |_size_gets_smaller[39] |0x00020818|0x40|OBJT |GLOB |15 |_size_gets_larger$ dump -rv size | grep _size_0x207d8 _size_gets_smaller R_SPARC_COPY 00x20818 _size_gets_larger R_SPARC_COPY 0

and a new version of this shared object is supplied which contains different datasizes for these symbols:

$ nm -x libfoo.so.1 | grep _size_[26] |0x00010378|0x10|OBJT |GLOB |8 |_size_gets_smaller[28] |0x00010388|0x80|OBJT |GLOB |8 |_size_gets_larger

then running ldd (1) against the dynamic executable will reveal:

$ ldd -d proglibfoo.so.1 => ./libfoo.so.1...........copy relocation sizes differ: _size_gets_smaller

(file prog size=40; file ./libfoo.so.1 size=10);./libfoo.so.1 size used; possible insufficient data copied

copy relocation sizes differ: _size_gets_larger(file prog size=40; file ./libfoo.so.1 size=80);./prog size used; possible data truncation

Here ldd (1) informs us that the dynamic executable will copy as much data as theshared object has to offer, but only accepts as much as its allocated space allows.

94 Linker and Libraries Guide ♦ August 1997

Profiling Shared ObjectsThe runtime linker is capable of generating profiling information for any sharedobjects processed during the running of an application. This is possible because theruntime linker is responsible for binding shared objects to an application and istherefore able to intercept any global function bindings (these bindings take placethrough .plt entries - see “When Relocations are Performed” on page 48 for detailsof this mechanism).

The profiling of a shared object is enabled by specifying its name with theLD_PROFILE environment variable. You can analyze one shared object at a timeusing this environment variable. However, the setting of the environment variablecan be used to analyze one or more applications use of the shared object. In thefollowing example the use of libc by the single invocation of the command ls (1) isanalyzed:

$ LD_PROFILE=libc.so.1 ls -l

In the following example the environment variable setting will cause anyapplications use of libc to accumulate the analyzed information for the durationthat the environment variable is set:

$ LD_PROFILE=libc.so.1; export LD_PROFILE$ ls -l$ make$ ...

When profiling is enabled, a profile data file is created, if it doesn’t already exist, andis mapped by the runtime linker. In the above examples this data file is/var/tmp/libc.so.1.profile . You can also specify an alternative directory tostore the profile data using the LD_PROFILE_OUTPUTenvironment variable.

This profile data file is used to deposit profil (2) data and call count informationrelated to the specified shared objects use. This profiled data can be directlyexamined with gprof (1).

Note - gprof (1) is most commonly used to analyze the gmon.out profile datacreated by an executable that has been compiled with the −xpg option of cc (1). Theruntime linkers profile analysis does not require any code to be compiled with thisoption. Applications whose dependent shared objects are being profiled should notmake calls to profil (2), because this system call does not provide for multipleinvocations within the same process. For the same reason, these applications mustnot be compiled with the −xpg option of cc (1), as this compiler generatedmechanism of profiling is also built on top of profil (2).

Shared Objects 95

One of the most powerful features of this profiling mechanism is to allow theanalysis of a shared object as used by multiple applications. Frequently profilinganalysis is carried out using one or two applications. However, a shared object, by itsvery nature, can be used by a multitude of applications. Analyzing how theseapplications use the shared object can offer insights into where energy might bespent to improvement the overall performance of the shared object.

The following example shows a performance analysis of libc over a build of severalapplications within a source hierarchy:

$ LD_PROFILE=libc.so.1 ; export LD_PROFILE$ make$ gprof -b /usr/lib/libc.so.1 /var/tmp/libc.so.1.profile.....

granularity: each sample hit covers 4 byte(s) ....

called/total parentsindex %time self descendents called+self name index

called/total children.....-----------------------------------------------

0.33 0.00 52/29381 _gettxt [96]1.12 0.00 174/29381 _tzload [54]

10.50 0.00 1634/29381 <external>16.14 0.00 2512/29381 _opendir [15]

160.65 0.00 25009/29381 _endopen [3][2] 35.0 188.74 0.00 29381 _open [2]-----------------------------------------------.....granularity: each sample hit covers 4 byte(s) ....

% cumulative self self totaltime seconds seconds calls ms/call ms/call name35.0 188.74 188.74 29381 6.42 6.42 _open [2]13.0 258.80 70.06 12094 5.79 5.79 _write [4]

9.9 312.32 53.52 34303 1.56 1.56 _read [6]7.1 350.53 38.21 1177 32.46 32.46 _fork [9]

....

The special name <external> indicates a reference from outside of the address rangeof the shared object being profiled. Thus, in the above example, 1634 calls to thefunction open (2) within libc occurred from the dynamic executables, or from othershared objects, bound with libc while the profiling analysis was in progress.

Note - The profiling of shared objects is multi-threaded safe except in the case whereone thread calls fork (2) while another thread is updating the profile datainformation. The use of fork (2) removes this restriction.

96 Linker and Libraries Guide ♦ August 1997

CHAPTER 5

Versioning

OverviewELF objects processed by the link-editors provide many global symbols to whichother objects can bind. These symbols describe the object’s application binary interface(ABI). During the evolution of an object this interface can change due to the additionor deletion of global symbols. In addition, the objects evolution can involve internalimplementation changes.

Versioning refers to several techniques that can be applied to an object to indicateinterface and implementation changes. These techniques provide for the objectscontrolled evolution while maintaining backward compatibility.

This chapter describes how an object’s ABI can be defined, classifies how changes tothis interface can affect backward compatibility, and presents models by whichinterface and implementation changes can be incorporated into new releases of theobject.

The focus of this chapter is the runtime interfaces of dynamic executables and sharedobjects. The techniques used to describe and manage changes within these dynamicobjects are presented in generic terms. A common set of naming conventions andversioning scenarios, as applied to shared objects, can be found in Appendix B.

It is important that developers of dynamic objects be aware of the ramifications of aninterface change, and understand how such changes can be managed, especially inregards to maintaining backward compatibility with previously shipped objects.

The global symbols made available by any dynamic object represent the object’spublic interface. Frequently, the number of global symbols remaining in an object atthe end of a link-edit are more than you would like to make public. These global

97

symbols derive from the interrelationships required between the relocatable objectsused to build the object, and represent private interfaces within the object itself.

A precursor to defining an object’s binary interface is to first define only those globalsymbols you wish to make publicly available from the object being created. Thesepublic symbols can be established using the link-editor’s −Moption and an associatedmapfile as part of the final link-edit. This technique is introduced in “ReducingSymbol Scope” on page 33. This public interface establishes one or more versiondefinitions within the object being created, and forms the foundation for the additionof new interfaces as the object evolves.

The following sections build upon this initial public interface. First though, it isuseful to understand how various changes to an interface can be categorized so thatthey can be managed appropriately.

Interface CompatibilityThere are many types of change that can be made to an object. In their simplestterms these changes can be categorized into one of two groups:

� compatible updates. These updates are additive, in that all previously availableinterfaces remain intact.

� incompatible updates. These updates have changed the existing interface in such away that existing users of the interface can fail or behave incorrectly.

The following list attempts to clarify some common object changes into one of theabove categorizations:

� the addition of a symbol - a compatible update.

� the removal of a symbol - an incompatible update.

� the addition of an argument to a non- varargs (5) function - an incompatiblechange.

� the removal of an argument from a function - an incompatible update.

� the change of size, or content, of a data item to a function or as an externaldefinition - an incompatible change.

� a bug fix, or internal enhancement to a function - a compatible change providingthe semantic properties of the object remain unchanged, otherwise, this is anincompatible change.

Note - It is possible, because of interposition, that the addition of a symbol canconstitute an incompatible update, such that the new symbol might conflict with anapplications use of that symbol. However, this does seem rare in practice as sourcelevel name space management is commonly used.

98 Linker and Libraries Guide ♦ August 1997

Compatible updates can be accommodated by maintaining version definitionsinternal to the object being generated. Incompatible updates can be accommodated byproducing a new object with a new external versioned name. Both of these versioningtechniques allow for the selective binding of applications as well as verification ofcorrect version binding at runtime. These two techniques are explored in more detailin the following sections.

Internal VersioningA dynamic object can have associated with it one or more internal version definitions.Each version definition is commonly associated with one or more symbol names. Asymbol name can only be associated with one version definition, however a versiondefinition can inherit the symbols from other version definitions. Thus, a structureexists to define one or more independent, or related, version definitions within theobject being created. As new changes are made to the object, new version definitionscan be added to express these changes.

There are two consequences of providing version definitions within a shared object:

� Dynamic objects that are built against this shared object can record theirdependency on the version definitions they bind to. These version dependencieswill be verified at runtime to insure that the appropriate interfaces, orfunctionality, are available for the correct execution of an application.

� Dynamic objects can select only those version definitions of a shared object thatthey wish to bind to during their link-edit. This mechanism allows developers tocontrol their dependency on a shared object to the interfaces, or functionality, thatprovide the most flexibility.

Creating a Version DefinitionVersion definitions commonly consist of an association of symbol names to a uniqueversion name. These associations are established within a mapfile and supplied tothe final link-edit of an object using the link-editor’s −Moption (this technique wasintroduced in the section “Reducing Symbol Scope” on page 33).

A version definition is established whenever a version name is specified as part of themapfile directive. In the following example two source files are combined, togetherwith mapfile directives, to produce an object with a defined public interface:

$ cat foo.cextern const char * _foo1;

(continued)

Versioning 99

(Continuation)

void foo1(){

(void) printf(_foo1);}

$ cat data.cconst char * _foo1 = "string used by foo1()\n";

$ cat mapfileSUNW_1.1 { # Release X

global:foo1;

local:*;

};$ cc -o libfoo.so.1 -M mapfile -G foo.o data.o$ nm -x libfoo.so.1 | grep "foo.$"[33] |0x0001058c|0x00000004|OBJT |LOCL |0x0 |17 |_foo1[35] |0x00000454|0x00000034|FUNC |GLOB |0x0 |9 |foo1

Here, the symbol foo1 is the only global symbol defined to provide the sharedobject’s public interface. The special auto-reduction directive “*” causes the reductionof all other global symbols to have local binding within the object being generated(this directive is introduced in “Defining Additional Symbols” on page 28). Theassociated version name, SUNW_1.1, causes the generation of a version definition.Thus, the shared object’s public interface consists of the internal version definitionSUNW_1.1, associated with the global symbol foo1 .

Whenever a version definition, or the auto-reduction directive, are used to generate anobject, a base version definition is also created. This base version is defined using thename of the file itself, and is used to associate any reserved symbols generated bythe link-editor (see “Generating the Output Image” on page 37 for a list of thesereserved symbols).

The version definitions contained within an object can be displayed using pvs (1)with the −d option:

$ pvs -d libfoo.so.1libfoo.so.1;SUNW_1.1;

Here, the object libfoo.so.1 has an internal version definition named SUNW_1.1,together with a base version definition libfoo.so.1 .

Note - The link-editor’s −z noversion option allows mapfile directed symbolreduction to be performed but suppresses the creation of version definitions.

100 Linker and Libraries Guide ♦ August 1997

Starting with this initial version definition, it is possible for the object to evolve byadding new interfaces and updated functionality. For example, a new function, foo2 ,together with its supporting data structures, can be added to the object by updatingthe source files foo.c and data.c :

$ cat foo.cextern const char * _foo1;extern const char * _foo2;

void foo1(){

(void) printf(_foo1);}

void foo2(){

(void) printf(_foo2);}

$ cat data.cconst char * _foo1 = "string used by foo1()\n";const char * _foo2 = "string used by foo2()\n";

A new version definition, SUNW_1.2, can be created to define a new interfacerepresenting the symbol foo2 . In addition, this new interface can be defined toinherit the original version definition SUNW_1.1.

The creation of this new interface is important as it identifies the evolution of theobject and enables users to verify and select the interfaces to which they bind. Theseconcepts are covered in more detail in “Binding to a Version Definition” on page 105and in “Specifying a Version Binding” on page 109.

The following example shows the mapfile directives that create these two interfaces:

$ cat mapfileSUNW_1.1 { # Release X

global:foo1;

local:*;

};

SUNW_1.2 { # Release X+1global:

foo2;} SUNW_1.1;

$ cc -o libfoo.so.1 -M mapfile -G foo.o data.o$ nm -x libfoo.so.1 | grep "foo.$"[33] |0x00010644|0x00000004|OBJT |LOCL |0x0 |17 |_foo1[34] |0x00010648|0x00000004|OBJT |LOCL |0x0 |17 |_foo2[36] |0x000004bc|0x00000034|FUNC |GLOB |0x0 |9 |foo1

(continued)

Versioning 101

(Continuation)

[37] |0x000004f0|0x00000034|FUNC |GLOB |0x0 |9 |foo2

Here, the symbols foo1 and foo2 are both defined to be part of the shared object’spublic interface. However, each of these symbols is assigned to a different versiondefinition; foo1 is assigned to SUNW_1.1, and foo2 is assigned to SUNW_1.2.

These version definitions, their inheritance, and their symbol association can bedisplayed using pvs (1) together with the −d, −v and −s options:

$ pvs -dsv libfoo.so.1libfoo.so.1:

_end;_GLOBAL_OFFSET_TABLE_;_DYNAMIC;_edata;_PROCEDURE_LINKAGE_TABLE_;_etext;

SUNW_1.1:foo1;SUNW_1.1;

SUNW_1.2: {SUNW_1.1}:foo2;SUNW_1.2

Here, the version definition SUNW_1.2 has a dependency on the version definitionSUNW_1.1.

The inheritance of one version definition by another is a useful technique thatreduces the version information that will eventually be recorded by any object thatbinds to a version dependency. Version inheritance is covered in more detail in thesection “Binding to a Version Definition” on page 105.

Any internal version definition will have an associated version definition symbolcreated. As shown in the previous pvs (1) example, these symbols are displayedwhen using the −v option.

Creating a Weak Version Definition

Internal changes to an object that do not require the introduction of a new interfacedefinition, can be defined by creating a weak version definition. Examples of suchchanges are bug fixes or performance improvements.

Such a version definition is empty, in that it has no global interface symbolsassociated with it.

102 Linker and Libraries Guide ♦ August 1997

For example, if the data file data.c , used in the previous examples, is updated toprovide more detailed string definitions:

$ cat data.cconst char * _foo1 = "string used by function foo1()\n";const char * _foo2 = "string used by function foo2()\n";

then a weak version definition can be introduced to identify this change:

$ cat mapfileSUNW_1.1 { # Release X

global:foo1;

local:*;

};

SUNW_1.2 { # Release X+1global:

foo2;} SUNW_1.1;

SUNW_1.2.1 { } SUNW_1.2; # Release X+2

$ cc -o libfoo.so.1 -M mapfile -G foo.o data.o$ pvs -dv libfoo.so.1

libfoo.so.1;SUNW_1.1;SUNW_1.2: {SUNW_1.1};SUNW_1.2.1 [WEAK]: {SUNW_1.2};

Here, the empty version definition is signified by the weak label. These weak versiondefinitions allow applications to verify the existence of a particular implementationby binding to the version definition associated with that functionality. The section“Binding to a Version Definition” on page 105 illustrates how these definitions can beused in more detail.

Defining Unrelated InterfacesThe previous examples have shown how new version definitions added to an objecthave inherited any existing version definitions. It is also possible to create versiondefinitions that are unique and independent. In the following example, two newfiles, bar1.c and bar2.c , are added to the object libfoo.so.1 . These filescontribute two new symbols, bar1 and bar2 , respectively:

Versioning 103

$ cat bar1.cextern void foo1();

void bar1()

{foo1();

}$ cat bar2.cextern void foo2();

void bar2(){

foo2();}

These two symbols are intended to define two new public interfaces. Neither of thesenew interfaces are related to each other, however each expresses a dependency onthe original SUNW_1.2 interface.

The following mapfile definition creates this required association:

$ cat mapfileSUNW_1.1 { # Release X

global:foo1;

local:*;

};

SUNW_1.2 { # Release X+1global:

foo2;} SUNW_1.1;

SUNW_1.2.1 { } SUNW_1.2; # Release X+2

SUNW_1.3a { # Release X+3global:

bar1;} SUNW_1.2;

SUNW_1.3b { # Release X+3global:

bar2;} SUNW_1.2;

Again, the version definitions created in libfoo.so.1 using this mapfile , andtheir related dependencies, can be inspected using pvs (1):

104 Linker and Libraries Guide ♦ August 1997

$ cc -o libfoo.so.1 -M mapfile -G foo.o bar.o data.o$ pvs -dv libfoo.so.1

libfoo.so.1;SUNW_1.1;

SUNW_1.2: {SUNW_1.1};SUNW_1.2.1 [WEAK]: {SUNW_1.2};SUNW_1.3a: {SUNW_1.2};SUNW_1.3b: {SUNW_1.2};

The following sections explore how these version definition recordings can be usedto verify runtime binding requirements and control the binding requirements of anobject during its creation.

Binding to a Version DefinitionWhen a dynamic executable or shared object is built against other shared objects,these dependencies are recorded in the resulting object (see “Shared ObjectProcessing” on page 12 and “Recording a Shared Object Name” on page 73 for moredetails). If these shared object dependencies also contain version definitions then anassociated version dependency will be recorded in the resulting object.

The following example takes the data files from the previous section and generates ashared object suitable for a compile time environment. This shared object,libfoo.so.1 , will be used in following binding examples:

$ cc -o libfoo.so.1 -h libfoo.so.1 -M mapfile -G foo.o bar.o \ data.o$ ln -s libfoo.so.1 libfoo.so$ pvs -dsv libfoo.so.1

libfoo.so.1:_end;_GLOBAL_OFFSET_TABLE_;_DYNAMIC;_edata;_PROCEDURE_LINKAGE_TABLE_;_etext;

SUNW_1.1:foo1;SUNW_1.1;

SUNW_1.2: {SUNW_1.1}:foo2;SUNW_1.2;

SUNW_1.2.1 [WEAK]: {SUNW_1.2}:SUNW_1.2.1;

SUNW_1.3a: {SUNW_1.2}:bar1;SUNW_1.3a;

SUNW_1.3b: {SUNW_1.2}:bar2;

(continued)

Versioning 105

(Continuation)

SUNW_1.3b

In effect, there are six public interfaces being offered by this shared object. Four ofthese interfaces (SUNW_1.1, SUNW_1.2, SUNW_1.3a and SUNW_1.3b) define a set offunctions, one interface (SUNW_1.2.1 ) describes an internal implementation changeto the shared object, and one interface (libfoo.so.1 ) defines several reservedlabels. Dynamic objects that build with this object will record which of theseinterfaces they bind to.

The following example builds an application that references both symbols foo1 andfoo2 . The versioning dependency information recorded in the application can beexamined using pvs (1) with the −r option:

$ cat prog.cextern void foo1();extern void foo2();

main(){

foo1();foo2();

}$ cc -o prog prog.c -L. -R. -lfoo$ pvs -r prog

libfoo.so.1 (SUNW_1.2, SUNW_1.2.1);

In this example, the application prog has really bound to the two interfacesSUNW_1.1and SUNW_1.2, as these interfaces have provided the global symbolsfoo1 and foo2 respectively.

However, since version definition SUNW_1.1 is defined within libfoo.so.1 asbeing inherited by the version definition SUNW_1.2, it is only necessary to record thelatter version dependency. This normalization of version definition dependenciesreduces the amount of version information that must be maintained within an objectand processed at runtime.

Since the application prog was built against the shared object’s implementationcontaining the weak version definition SUNW_1.2.1 , this dependency is alsorecorded. Even though this version definition is defined to inherit the versiondefinition SUNW_1.2, the version’s weak nature precludes its normalization withSUNW_1.1, and results in a separate dependency recording.

Had there been multiple weak version definitions that inherit from each other thenthese definitions will be normalized in the same manner as non-weak versiondefinitions are.

106 Linker and Libraries Guide ♦ August 1997

Note - The recording of a version dependency can be suppressed by the link-editor’s−z noversion option.

Having recorded these version definition dependencies, the runtime linker validatesthe existence of the required version definitions in the objects bound to when theapplication is executed. This validation can be displayed using ldd (1) with the −voption. For example, by running ldd (1) on the application prog , the versiondefinition dependencies are shown to be found correctly in the shared objectlibfoo.so.1 :

$ ldd -v prog

find library=libfoo.so.1; required by proglibfoo.so.1 => ./libfoo.so.1

find version=libfoo.so.1;libfoo.so.1 (SUNW_1.2) => ./libfoo.so.1libfoo.so.1 (SUNW_1.2.1) => ./libfoo.so.1

....

Note - ldd (1) with the −v option implies verbose output, in that a recursive list of alldependencies, together with all versioning requirements, will be generated.

If a non-weak version definition dependency cannot be found, a fatal error will occurduring application initialization. Any weak version definition dependency thatcannot be found is silently ignored. For example, if the application prog was run inan environment in which libfoo.so.1 only contained the version definitionSUNW_1.1, then the following fatal error will occur:

$ pvs -dv libfoo.so.1libfoo.so.1;SUNW_1.1;

$ progld.so.1: prog: fatal: libfoo.so.1: version ‘SUNW_1.2’ not \found (required by file prog)

Had the application prog not recorded any version definition dependencies, thenonexistence of the required interface symbol foo2 will have manifested itselfsometime during the execution of the application as a fatal relocation error (see“Relocation Errors” on page 49). This relocation error might occur at processinitialization, during process execution, or might not occur at all if the execution pathof the application did not call the function foo2 .

Recording version definition dependencies provides an alternative, and immediateindication of the availability of the interfaces required by the application.

Versioning 107

If the application prog was run in an environment in which libfoo.so.1 onlycontained the version definitions SUNW_1.1 and SUNW_1.2, then all non-weakversion definition requirements will be satisfied. The absence of the weak versiondefinition SUNW_1.2.1 is deemed nonfatal, and so no runtime error condition willbe generated. However, ldd (1) can be used to display all version definitions thatcannot be found:

$ pvs -dv libfoo.so.1libfoo.so.1;SUNW_1.1;SUNW_1.2: {SUNW_1.1};

$ progstring used by foo1()string used by foo2()$ ldd prog

libfoo.so.1 => ./libfoo.so.1libfoo.so.1 (SUNW_1.2.1) => (version not found)...........

Note - If an object requires a version definition from a given dependency, and atruntime an implementation of that dependency is found that contains no versiondefinition information, the version verification of the dependency will be silentlyignored. This policy provides a level of backward compatibility as the transition fromnon-versioned to versioned shared objects is taken. ldd (1) however, can still be usedto display any version requirement discrepancies.

Verifying Versions in Additional ObjectsVersion definition symbols also provide a mechanism for verifying the versionrequirements of an object obtained by dlopen (3X). Any object added to the process’saddress space using this function will have no automatic version dependencyverification carried out by the runtime linker. Thus, it is the responsibility of thecaller of this function to verify that any versioning requirements are met.

The presence of a required version definition can be verified by looking up theassociated version definition symbol using dlsym (3X). The following exampleshows the shared object libfoo.so.1 being added to a process by dlopen (3X)and verified to insure that the interface SUNW_1.2 is available:

#include <stdio.h>#include <dlfcn.h>

main(){

void * handle;

(continued)

108 Linker and Libraries Guide ♦ August 1997

(Continuation)

const char * file = "libfoo.so.1";const char * vers = "SUNW_1.2";....

if ((handle = dlopen(file, RTLD_LAZY)) == NULL) {(void) printf("dlopen: %s\n", dlerror());exit (1);

}

if (dlsym(handle, vers) == NULL) {(void) printf("fatal: %s: version ‘%s’ not found\n",

file, vers);exit (1);

}....

Specifying a Version BindingWhen building a dynamic object against a shared object containing versiondefinitions, it is possible to instruct the link-editor to limit the binding to specificversion definitions. Effectively, the link-editor allows you to control an object’sbinding to specific interfaces.

An object’s binding requirements can be controlled using a file control directive. Thisdirective is supplied using the link-editor’s −Moption and an associated mapfile .The syntax for these file control mapfile directives is shown below:

name - version [ version ... ] [ $ADDVERS=version ];

� name - represents the name of the shared object dependency. This name shouldmatch the shared object’s compilation environment name as used by thelink-editor (see “Library Naming Conventions” on page 13).

� version - represents the version definition name within the shared object thatshould be made available for binding. Multiple version definitions can bespecified.

� $ADDVERS - allows for additional version definitions to be recorded.

There are a couple of scenarios where this binding control can be useful:

� If a shared object has been versioned to define unique and independent versions,possibly defining different standards interfaces, then the application can insurethat its bindings meet the requirements of a specific interface.

� If a shared object has been versioned over several software releases, applicationdevelopers can restrict themselves to the interfaces that were available in aprevious software release. Thus, an application can be built using the latest release

Versioning 109

of the shared object in the knowledge that the application’s interface requirementscan be met by a previous release of the shared object.

The following is an example of using the version control mechanism. This exampleuses the shared object libfoo.so.1 containing the following version interfacedefinitions:

$ pvs -dsv libfoo.so.1libfoo.so.1:

_end;_GLOBAL_OFFSET_TABLE_;_DYNAMIC;_edata;_PROCEDURE_LINKAGE_TABLE_;_etext;

SUNW_1.1:foo1;foo2;SUNW_1.1;

SUNW_1.2: {SUNW_1.1}:bar;

The version definitions SUNW_1.1and SUNW_1.2 represent interfaces withinlibfoo.so.1 that were made available in software Release X and Release X+1respectively.

An application can be built to bind only to the interfaces available in Release X byusing the following version control mapfile directive:

$ cat mapfilelibfoo.so - SUNW_1.1;

For example, if you develop an application, prog , and wish to insure that theapplication will run on Release X , then the application can only use the interfacesavailable in that release. If the application mistakenly references the symbol bar ,then the application’s noncompliance to the required interface will be signalled bythe link-editor as an undefined symbol error:

$ cat prog.cextern void foo1();extern void bar();

main(){

foo1();bar();

}$ cc -o prog prog.c -M mapfile -L. -R. -lfoo

(continued)

110 Linker and Libraries Guide ♦ August 1997

(Continuation)

Undefined first referencedsymbol in file

bar prog.o (symbol belongs to unavailable \version ./libfoo.so (SUNW_1.2))

ld: fatal: Symbol referencing errors. No output written to prog

To be compliant with the SUNW_1.1 interface, you must remove the reference to bar .This can be achieved either by reworking the application to remove the requirementon bar , or by adding an implementation of bar to the build of the application.

Binding to Additional Version Definitions

Sometimes it is desirable to record additional version dependencies than would beproduced from the normal symbol binding of an object. This can be achieved usingthe $ADDVERSfile control directive. This section describes a couple of scenarioswhere this additional binding may be useful.

Continuing with the libfoo.so.1 example, assume that in Release X+2 theversion definition SUNW_1.1 is subdivided into two standard releases STAND_AandSTAND_B. To preserve compatibility, the SUNW_1.1version definition must bemaintained, but now it is expressed as inheriting the two standard definitions:

$ pvs -dsv libfoo.so.1libfoo.so.1:

_end;_GLOBAL_OFFSET_TABLE_;_DYNAMIC;_edata;_PROCEDURE_LINKAGE_TABLE_;_etext;

SUNW_1.1: {STAND_A, STAND_B}:SUNW_1.1;

SUNW_1.2: {SUNW_1.1}:bar;

STAND_A:foo1;STAND_A;

STAND_B:foo2;STAND_B;

If we continued to build our application prog so that its only requirement is theinterface symbol foo1 it will have a single dependency on the version definitionSTAND_A. This precludes running prog on a system where libfoo.so.1 is less

Versioning 111

than Release X+2 as the version definition STAND_Adid not exist in previousreleases, even though the interface foo1 did.

Therefore, the application prog can be built to align its requirement with previousreleases by creating a dependency on SUNW_1.1by using the following file controldirective:

$ cat mapfilelibfoo.so - SUNW_1.1 $ADDVERS=SUNW_1.1;$ cat progextern void foo1();

main(){

foo1();}$ cc -M mapfile -o prog prog.c -L. -R. -lfoo$ pvs -r prog

libfoo.so.1 (SUNW_1.1);

This explicit dependency is sufficient to encapsulate the true dependencyrequirements and satisfy compatibility with older releases.

In “Creating a Weak Version Definition” on page 102 it was described how weakversion definitions can be used to mark an internal implementation change. Theseversion definitions are well suited to indicate bug fixes and performanceimprovements made to an object. If the existence of a weak version is required for thecorrect execution of an application, then an explicit dependency on this versiondefinition can be generated.

Establishing such a dependency can be important when a bug fix, or performanceimprovement, is critical for the application to function correctly.

Continuing with the libfoo.so.1 example, assume a bug fix is incorporated as theweak version definition SUNW_1.2.1 in software Release X+3 :

$ pvs -dsv libfoo.so.1libfoo.so.1:

_end;_GLOBAL_OFFSET_TABLE_;_DYNAMIC;_edata;_PROCEDURE_LINKAGE_TABLE_;_etext;

SUNW_1.1: {STAND_A, STAND_B}:SUNW_1.1;

SUNW_1.2: {SUNW_1.1}:bar;

STAND_A:foo1;STAND_A;

(continued)

112 Linker and Libraries Guide ♦ August 1997

(Continuation)

STAND_B:foo2;STAND_B;

SUNW_1.2.1 [WEAK]: {SUNW_1.2}:SUNW_1.2.1;

Normally, if an application is built against this shared object, it will record a weakdependency on the version definition SUNW_1.2.1 . This dependency isinformational only, in that it will not cause termination of the application should theversion definition not be found in the libfoo.so.1 used at runtime.

The file control directive $ADDVERScan be used to generate an explicit dependencyon a version definition. If this definition is weak, then this explicit reference alsocauses the version definition to be promoted to a strong dependency.

Therefore, the application prog can be built to enforce the requirement that theSUNW_1.2.1 interface be available at runtime by using the following file controldirective:

$ cat mapfilelibfoo.so - SUNW_1.1 $ADDVERS=SUNW_1.2.1;$ cat progextern void foo1();

main(){

foo1();}$ cc -M mapfile -o prog prog.c -L. -R. -lfoo$ pvs -r prog

libfoo.so.1 (SUNW_1.2.1);

Here, prog has been built with an explicit dependency on the interface STAND_A.Because the version definition SUNW_1.2.1 is promoted to a strong version, it isalso normalized with the dependency STAND_A. At runtime, if the version definitionSUNW_1.2.1 cannot be found, a fatal error will be generated.

Note - When working with one or two dependencies, explicit binding to a versiondefinition can also be achieved by referencing the version definition symbol. This ismost easily achieved by using the link-editors −u option. However, a symbolreference is nonselective, and when working with multiple dependencies, which maycontain similarly named version definitions, this technique is insufficient to createexplicit bindings.

Versioning 113

Relocatable ObjectsThe preceding sections have described how version information can be recorded andused within dynamic objects. Relocatable objects can maintain versioninginformation in a similar manner, however there are one or two subtle differences inhow this information is used.

Any version definitions supplied to the link-edit of a relocatable object are recordedin exactly the same format as has been described in previous examples. However, bydefault, symbol reduction is not carried out on the object being created. Instead, whenthe relocatable object is finally used as input to the generation of a dynamic object,the version recording itself will be used to determine the symbol reductions to apply.

In addition, any version definitions found in relocatable objects will be propagated tothe dynamic object. For an example of version processing in relocatable objects see“Reducing Symbol Scope” on page 33.

External VersioningRuntime references to a shared object should always refer to the files versionfilename. Commonly this is expressed as a filename suffixed with a version number.When a shared object’s interface changes in an incompatible manner - such that it willbreak old applications - a new shared object should be distributed with a newversioned filename. In addition, the original versioned filename must still bedistributed to provide the interfaces required by the old applications.

By providing shared objects as separate versioned filenames within the runtimeenvironment, applications built over a series of software releases can be guaranteedthat the interface against which they were built is available for them to bind duringtheir execution.

The following section describes how to coordinate the binding of an interfacebetween the compilation and runtime environments.

Coordination of Versioned FilenamesIn the section “Naming Conventions” on page 72 it was stated that during a link-editthe most common method to input shared objects was to use the −l option. Thisoption will use the link-editor’s library search mechanism to locate shared objectsthat are prefixed with lib and suffixed with .so .

However, at runtime any shared object dependencies should exist in their versionedname form. Instead of maintaining two distinct shared objects that follow thesenaming conventions, the most common mechanism of coordinating these objectsinvolves creating file system links between the two filenames.

114 Linker and Libraries Guide ♦ August 1997

To make the runtime shared object libfoo.so.1 available to the compilationenvironment it is necessary to provide a symbolic link from the compilation filenameto the runtime filename. For example:

$ cc -o libfoo.so.1 -G -K pic foo.c$ ln -s libfoo.so.1 libfoo.so$ ls -l libfoo*lrwxrwxrwx 1 usr grp 11 1991 libfoo.so -> libfoo.so.1-rwxrwxr-x 1 usr grp 3136 1991 libfoo.so.1

Note - Either a symbolic or hard link can be used. However, as a documentation anddiagnostic aid, symbolic links are more useful.

Here, the shared object libfoo.so.1 has been generated for the runtimeenvironment. Generating a symbolic link libfoo.so , has also enabled this file’s usein a compilation environment. For example:

$ cc -o prog main.o -L. -lfoo

Here the link-editor will process the relocatable object main.o with the interfacedescribed by the shared object libfoo.so.1 which it will find by following thesymbolic link libfoo.so .

If over a series of software releases, new versions of this shared object are distributedwith changed interfaces, the compilation environment can be constructed to use theinterface that is applicable by changing the symbolic link. For example:

$ ls -l libfoo*lrwxrwxrwx 1 usr grp 11 1993 libfoo.so -> libfoo.so.3-rwxrwxr-x 1 usr grp 3136 1991 libfoo.so.1-rwxrwxr-x 1 usr grp 3237 1992 libfoo.so.2-rwxrwxr-x 1 usr grp 3554 1993 libfoo.so.3

Here, three major versions of the shared object are available. Two of these sharedobjects, libfoo.so.1 and libfoo.so.2 , provide the dependencies for existingapplications. libfoo.so.3 offers the latest major release for building and runningnew applications.

Using this symbolic link mechanism itself is insufficient to coordinate the correctbinding of a shared object from its use in the compilation environment to itsrequirement in the runtime environment. As the example presently stands, thelink-editor will record in the dynamic executable prog the filename of the sharedobject it has processed, which in this case will be the compilation environmentfilename:

Versioning 115

$ dump -Lv prog

prog:**** DYNAMIC SECTION INFORMATION ****

.dynamic:[INDEX] Tag Value[1] NEEDED libfoo.so.........

This means that when the application prog is executed, the runtime linker willsearch for the dependency libfoo.so , and consequently this will bind to whicheverfile this symbolic link is pointing.

To provide the correct runtime name to be recorded as a dependency, the sharedobject libfoo.so.1 should be built with an soname definition. This definitionidentifies the shared objects runtime name, and is used as the dependency name byany object that links against this shared object. This definition can be provided usingthe −h option during the link-edit of the shared object itself. For example:

$ cc -o libfoo.so.1 -G -K pic -h libfoo.so.1 foo.c$ ln -s libfoo.so.1 libfoo.so$ cc -o prog main.o -L. -lfoo$ dump -Lv prog

prog:**** DYNAMIC SECTION INFORMATION ****

.dynamic:[INDEX] Tag Value[1] NEEDED libfoo.so.1.........

This symbolic link and the soname mechanism has established a robust coordinationbetween the shared object naming conventions of the compilation and runtimeenvironments, one in which the interface processed during the link-edit is accuratelyrecorded in the output file generated. This recording ensures that the intendedinterface will be furnished at runtime.

116 Linker and Libraries Guide ♦ August 1997

CHAPTER 6

Support Interfaces

OverviewThe link-editors provide a number of support interfaces that allow for themonitoring, and in some cases modification, of link-editor and runtime linkerprocessing. These interfaces typically require a more advanced understanding oflink-editing concepts than has been described in previous chapters. The followinginterfaces are described in this chapter:

� Link-editor support interface (ld-support).

� Runtime linker auditing interface (rtld-audit).

� Runtime linker debugger interface (rtld-debugger).

Link-Editor Support InterfaceAs described in Chapter 2 the link-editor performs many operations including theopening of files and the concatenation of sections from these files. Monitoring, andsometimes modifying these operations can often be beneficial to components of acompilation system.

This section describes the supported interface for input file inspection, and to somedegree, input file data modification of those files that compose a link-edit. Thisinterface is referred to as the ld-support interface. Two applications that employ thisinterface are the link-editor itself which uses it to process debugging informationwithin relocatable objects, and the make(1) utility which uses it to save stateinformation.

117

The ld-support interface is composed of a support library that offers one or moresupport interface routines. This library is loaded as part of the link-edit process, andany support routines found are called at various stages of link-editing.

You should be familiar with the elf (3E) structures and file format when using thisinterface.

Invoking the Support InterfaceThe link-editor accepts one or more support libraries provided by either theSGS_SUPPORTenvironment variable or with the link-editors’ −S option. Theenvironment variable consists of a colon separated list of support libraries:

$ SGS_SUPPORT=./support.so.1:libldstab.so.1 cc ...

The −S option specifies a single support library. Multiple −S options can be specified:

$ ld -S ./support.so.1 -S libldstab.so.1 ...

A support library is a shared object. The link-editor performs a dlopen (3X) on eachshared object, in the order they are specified. If both the environment variable and−S option are encountered, then the shared objects specified with the environmentvariable are processed first. Each support library is then searched, using dlsym (3X),for any support interface routines. These support routines are then called at variousstages of link-editing.

Note - By default, the Solaris support library libldstab.so.1 is used by thelink-editor to process, and compact, compiler generated debugging informationsupplied within input relocatable objects. This default processing is suppressed ifyou invoke the link-editor with any support libraries specified using the −S option. Ifthe default processing of libldstab.so.1 is required in addition to your supportlibrary services, then libldstab.so.1 should be explicitly added to the list ofsupport libraries supplied to the link-editor.

Support Interface FunctionsAll ld-support interfaces are defined in the header file link.h . All interfacearguments are basic C types or ELF types. The ELF data types can be examined withthe ELF access library libelf (see elf (3E) for a description of libelf contents).The following interface functions are provided by the ld-support interface, and aredescribed in their expected order of use:

118 Linker and Libraries Guide ♦ August 1997

void ld_start(const char * name, const Elf32_Half type,const char * caller);

ld_start( )

This function is called after initial validation of the link-editor command line, andindicates the start of input file processing.

name is the output filename being created. type is the output file type, which is eitherET_DYN, ET_REL, or ET_EXEC(as defined in sys/elf.h ). caller is the applicationcalling the interface, which is normally /usr/ccs/bin/ld .

void ld_file(const char * name, const Elf_Kind kind, int flags,Elf * elf);

ld_file()

This function is called for each input file before any processing of the files data iscarried out.

name is the input file about to be processed. kind indicates the input file type, whichis either ELF_K_AR, or ELF_K_ELF (as defined in libelf.h ). flags indicates how thelink-editor obtained the file, and can be one or more of the following definitions:

� LD_SUP_DERIVED- the file name was not explicitly named on the command-line.It was either derived from a −l expansion or it identifies an extracted archivemember.

� LD_SUP_INHERITED- the file was obtained as a dependency of a command-lineshared object.

� LD_SUP_EXTRACTED- the file was extracted from an archive.

If no flags values are specified then the input file has been explicitly named on thecommand-line. elf is a pointer to the files ELF descriptor.

void ld_section(const char * name, Elf32_Shdr * shdr,Elf32_Word sndx, Elf_Data * data, Elf * elf);

ld_section()

This function is called for each section of the input file before any processing of thesection data is carried out.

Support Interfaces 119

name is the input section name. shdr is a pointer to the associated section header. sndxis the section index within the input file. data is a pointer to the associated databuffer. elf is a pointer to the files ELF descriptor.

Modification of the data is permitted by reallocating the data itself and reassigningthe Elf_Data buffers d_buf pointer. Any modification to the data should insure thecorrect setting of the Elf_Data buffers d_size element. For input sections that willbecome part of the output image, setting the d_size element to zero will effectivelyremove the data from the output image.

Note - Any sections that are stripped by use of the link-editors −s option are notreported to ld_section() .

void ld_atexit(int status);

ld_atexit( )

This function is called on completion of the link-edit.

status is the exit (2) code that will be returned by the link-editor and is eitherEXIT_FAILURE or EXIT_SUCCESS(as defined in stdlib.h ).

Support Interface ExampleThe following example creates a support library that prints the section name (seeTable 7–14) of any relocatable object file processed as part of a link-edit.

$ cat support.c#include <link.h>

static int indent = 0;

voidld_start(const char * name, const Elf32_Half type,

const char * caller){

(void) printf("output image: %s\n", name);}

voidld_file(const char * name, const Elf_Kind kind, int flags,

Elf * elf){

if (flags & LD_SUP_EXTRACTED)indent = 4;

elseindent = 2;

(continued)

120 Linker and Libraries Guide ♦ August 1997

(Continuation)

(void) printf("%*sfile: %s\n", indent, "", name);}

voidld_section(const char * name, Elf32_Shdr * shdr, Elf32_Word sndx,

Elf_Data * data, Elf * elf){

Elf32_Ehdr * ehdr = elf32_getehdr(elf);

if (ehdr->e_type == ET_REL)(void) printf("%*s section [%ld]: %s\n", indent,

"", sndx, name);}

This support library is dependent upon libelf to provide the ELF access functionelf32_getehdr (3E) used to determine the input file type. The support library isbuilt using:

$ cc -o support.so.1 -G -K pic support.c -lelf -lc

The following example shows the section diagnostics resulting from the constructionof a trivial application from a relocatable object and a local archive library. Theinvocation of the support library, in addition to default debugging informationprocessing, is brought about by the −S option usage:

$ LD_OPTIONS=-S./support.so.1:libldstab.so.1 cc -o prog \ main.c -L. -lfoooutput image: prog

file: /opt/COMPILER/crti.osection [1]: .shstrtabsection [2]: .text.......

file: /opt/COMPILER/crt1.osection [1]: .shstrtabsection [2]: .text.......

file: /opt/COMPILER/values-xt.osection [1]: .shstrtabsection [2]: .text.......

file: main.osection [1]: .shstrtabsection [2]: .text.......

file: ./libfoo.afile: ./libfoo.a(foo.o)

section [1]: .shstrtabsection [2]: .text.......

(continued)

Support Interfaces 121

(Continuation)

file: /usr/lib/libc.sofile: /opt/COMPILER/crtn.o

section [1]: .shstrtabsection [2]: .text.......

file: /usr/lib/libdl.so.1

Note - The number of sections displayed in this example have been reduced tosimplify the output. Also, the files included by the compiler driver can vary.

Runtime Linker Auditing InterfaceAs described in Chapter 3 the runtime linker performs many operations includingthe mapping of objects into memory and the binding of symbols. Monitoring, andsometimes modifying these operations from within the same process, can enablepowerful process monitoring tools.

This section describes the supported interface for a process to access runtime linkinginformation regarding itself. This interface is referred to as the rtld-audit interface.One example of the use of this mechanism is the runtime profiling of shared objectsdescribed in “Profiling Shared Objects” on page 95.

The rtld-audit interface is implemented as an audit library that offers one or moreauditing interface routines. If this library is loaded as part of a process, then theaudit routines are called by the runtime linker at various stages of process execution.These interfaces allow the audit library to access:

� Information regarding loaded objects.

� Symbol bindings that occur between these loaded objects. These bindings may bealtered by the audit library.

� Exploitation of the lazy binding mechanism provided by procedure linker tableentries (see “Procedure Linkage Table (Processor-Specific)” on page 219), to allowauditing of function calls and their return values. The arguments to a function andits return value may be modified by the audit library.

Some of these facilities can be achieved by preloading specialized shared objects (see“Loading Additional Objects” on page 55). However, a preloaded object exists withinthe same name-space as the objects of a process, and this often restricts, or complicatesthe implementation of the preloaded shared object. The rtld-audit interface offers theuser a unique name-space in which to execute their audit library, that insures the

122 Linker and Libraries Guide ♦ August 1997

audit library does not intrude upon the normal bindings that occur within theprocess.

Establishing a Name-spaceWhen the runtime linker binds a dynamic executable with its dependencies it buildsa linked list of link-maps to describe the process. The link-map structure describeseach object within the process and is defined in/usr/include/sys/link.h . Thesymbol search mechanism required to bind objects of an application traverses this listof link-maps. This link-map list is said to provide the name-space for process symbolresolution.

The runtime linker itself is also described by a link-map, and this link-map ismaintained on a different list from that of the application objects. This results in theruntime linker residing in its own unique name-space, which prevents any directbinding of the application to services within the runtime linker. (An application canonly call upon the public services of the runtime linker via the filter libdl.so.1 ).

The rtld-audit interface employs its own link-map list on which it maintains anyaudit libraries. This results in the audit libraries being isolated from the symbolbinding requirements of the application. Inspection of the application link-map list ispossible with dlmopen (3X), which when used with the RTLD_NOLOADflag allowsthe audit library to query an objects existence without causing its loading.

Two identifiers are defined in /usr/include/link.h to define the application andruntime linker link-map lists:

#define LM_ID_BASE 0 /* application link-map list */#define LM_ID_LDSO 1 /* runtime linker link-map list */

Each rtld-audit support library is assigned a unique free link-map identifier.

Building an Audit LibraryAn audit library is built like any other shared object, however its unique name-spacewithin a process requires some additional care:

� It must provide all dependency requirements.

� It should not use system interfaces that do not provide for multiple instances ofthe interface within a process.

If the audit library calls printf (3C), then the audit library must define adependency on libc (see “Generating a Shared Object” on page 26). Because theaudit library has a unique name-space, symbol references cannot be satisfied by thelibc present in the application being audited. If an audit library has a dependency

Support Interfaces 123

on libc then two versions of libc.so.1 will be loaded into the process. Onesatisfies the binding requirements of the application link-map list, and the othersatisfies the binding requirements of the audit link-map list.

To insure audit libraries are built with all dependencies recorded, the link-editors −zdefs option should be used (see “Generating a Shared Object” on page 26).

Some system interfaces exist assuming they are the only instance of theirimplementation within a process. For example, threads, signals and malloc (3C).Audit libraries should avoid using such interfaces, as doing so may inadvertentlyalter the behavior of the application.

Note - The allocation of memory using mapmalloc (3X) by an audit library isacceptable as this can exist with any allocation scheme normally employed by theapplication.

Invoking the Auditing InterfaceThe rtld_audit interface is enabled using the runtime linker environment variableLD_AUDIT. This environment variable is set to a colon separated list of shared objectsthat will be loaded by dlopen (3X). Each object is loaded onto its own audit link-maplist, and each object is searched for audit routines using dlsym (3X). Audit routinesthat are found will be called at various stages during the applications execution.

The rtld_audit interface allows for multiple audit libraries to be supplied. Auditlibraries that expect to be employed in this fashion should not alter the bindings thatwould normally be returned by the runtime linker, doing so may produceunexpected results from audit libraries that follow.

Secure applications (see “Security” on page 53) may only obtain audit libraries fromtrusted directories. Presently, the only trusted directories available for audit librariesare /usr/lib and /usr/ccs/lib .

Audit Interface FunctionsThe following functions are provided by the rtld-audit interface, and are described intheir expected order of use:

uint_t la_version(uint_t version);

la_version()

This function provides the initial handshake between the runtime linker and theaudit library. This interface must be provided by the audit library for it to be loaded.

124 Linker and Libraries Guide ♦ August 1997

The runtime linker calls this interface with the highest version of the rtld-auditinterface it is capable of supporting. The audit library can verify that this version issufficient for its use, and return the version it expects to use. This version is normallyLAV_CURRENTwhich is defined in /usr/include/link.h .

If the audit library returns a version of zero, or a value greater than the rtld-auditinterface the runtime linker supports, the audit library will not be used.

uint_t la_objopen(Link_map * lmp, Lmid_t lmid, uintptr_t * cookie);

la_objopen()

This function is called each time a new object is loaded by the runtime linker.

lmp provides the link-map structure describing the new object. lmid identifies thelink-map list to which the object has been added (see “Establishing a Name-space”on page 123). cookie provides a pointer to an identifer. This identifier is initialized tothe objects lmp, but may be modified by the audit library to better identify the objectto other rtld-audit interface routines

This function returns a value indicating the symbol bindings of interest for thisobject, which will result in later calls to la_symbind32() . The return value is amask of the following values defined in/usr/include/link.h :

� LA_FLG_BINDTO- audit symbol bindings to this object.

� LA_FLG_BINDFROM- audit symbol bindings from this object.

See la_symbind() for more details on the use of these two flags.

A return value of zero indicates that binding information is of no interest for thisobject.

void la_preinit(uintptr_t cookie);

la_preinit()

This function is called once after all objects have been loaded for the application, butbefore transfer of control to the application occurs.

cookie identifies the primary object that started the process, normally the dynamicexecutable.

uintptr_t la_symbind32(Elf32_Sym * sym, uint ndx,uintptr_t * refcook, uintptr_t * defcook, uint_t * flags);

Support Interfaces 125

la_symbind32()

This function is called when a binding occurs between two objects that have beentagged for binding notification (see la_objopen() ).

sym is a constructed symbol structure (see /usr/include/sys/elf.h ), whosesym->st_value indicates the address of the symbol definition being bound, andsym->st_name points to a symbol name string.

ndx indicates the symbol index within the bound objects dynamic symbol table.refcook describes the object making reference to this symbol. This identifier is thesame as passed to the la_objopen() that returned LA_FLG_BINDFROM. defcookdescribes the object defining this symbol. This identifier is the same as passed to thela_objopen() that returned LA_FLG_BINDTO.

flags points to a data item that can be used to modify the continued auditing ofprocedure linkage table symbol entries. This value is a mask of the following flagsdefined in /usr/include/link.h :

� LA_SYMB_NOPLTENTER- the la_*_pltenter() function will not be called forthis symbol.

� LA_SYMB_NOPLTEXIT- the la_pltexit() function will not be called for thissymbol.

� LA_SYMB_DLSYM- the symbol binding occured as a result of calling dlsym (3X).

By default, if the la_*_pltenter() or la_pltexit() functions exist within theaudit library, these will be called (after la_symbind32() ) for procedure linkagetable symbols each time the symbol is referenced (see also “Audit InterfaceLimitations” on page 129).

The return value indicates the address to which control should be passed followingthis call. An audit library that simply monitors symbol binding should return thevalue of sym->st_value so that control is passed to the bound symbol definition. Anaudit library may intentionally redirect a symbol binding by returning a differentvalue.

uint_t la_sparcv8_pltenter(Elf32_Sym * sym, uint ndx,uintptr_t * refcook, uintptr_t * defcook,La_sparcv8_regs * regs, uint_t * flags);

uint_t la_i86_pltenter(Elf32_Sym * sym, uint ndx,uintptr_t * refcook, uintptr_t * defcook,La_i86_regs * regs, uint_t * flags);

126 Linker and Libraries Guide ♦ August 1997

la_sparcv8_pltenter() , la_i86_pltenter( )

These functions are called on a SPARC and x86 system respectively, when aprocedure linkage symbol entry between two objects that have been tagged forbinding notification is called (see la_objopen() and la_symbind32() ).

sym, ndx, refcook and defcook provide the same information as passed tola_symbind32() .

regs points to the out registers on a SPARC system, and the stack and frame registerson a x86 system, as defined in /usr/include/link.h .

flags points to a data item that can be used to modify the continuing auditing of thisprocedure linkage table entry. This data item is the same as pointed to by the flagsfrom la_symbind32() . This value is a mask of the following flags defined in/usr/include/link.h :

� LA_SYMB_NOPLTENTER- the la_sparcv8_pltenter() orla_i86_pltenter() function will not be called subsequently for this symbol.

� LA_SYMB_NOPLTEXIT- the la_pltexit() function will not be called for thissymbol.

The return value indicates the address to which control should be passed followingthis call. An audit library that simply monitors symbol binding should return thevalue of sym->st_value so that control is passed to the bound symbol definition. Anaudit library may intentionally redirect a symbol binding by returning a differentvalue.

uint_t la_pltexit(Elf32_Sym * sym, uint ndx, uintptr_t * refcook,uintptr_t * defcook, uintptr_t retval);

la_pltexit()

This function is called when a procedure linkage symbol entry between two objectsthat have been tagged for binding notification (see la_objopen( ) andla_symbind32() ) returns, but before control reaches the caller.

sym, ndx, refcook and defcook provide the same information as passed tola_symbind32() . retval is the return code from the bound function.

An audit library that simply monitors symbol binding should return retval. An auditlibrary may intentionally return a different value.

Note - This interface function is experimental, see “Audit Interface Limitations” onpage 129.

Support Interfaces 127

uint_t la_objclose(uintptr_t * cookie);

la_objclose()

This function is called after any termination code for an object has been executed (see“Initialization and Termination Routines” on page 52) and prior to the object beingunloaded.

cookie was obtained from a previous la_objopen() and identifies the object. Anyreturn value is presently ignored.

Audit Interface ExampleThe following simple example creates an audit library that prints the name of eachshared object dependency loaded by the dynamic executable date (1):

$ cat audit.c#include <link.h>#include <stdio.h>

uint_tla_version(uint_t version){

return (LAV_CURRENT);}

uint_tla_objopen(Link_map * lmp, Lmid_t lmid, uintptr_t * cookie){

if (lmid == LM_ID_BASE)(void) printf("file: %s loaded\n", lmp->l_name);

return (0);}$ cc -o audit.so.1 -G -K pic -z defs audit.c -lmapmalloc -lc$ LD_AUDIT=./audit.so.1 datefile: date loadedfile: /usr/lib/libc.so.1 loadedfile: /usr/lib/libdl.so.1 loadedfile: /usr/locale/en_US/en_US.so.1 loadedFri Mar 8 10:03:55 PST 1997

Audit Interface DemonstrationsA number of demonstration applications that use the rtld-audit interface are providedin the SUNWosdempackage under /usr/demo/link_audit :

128 Linker and Libraries Guide ♦ August 1997

sotruss

This demo provides tracing of procedure calls between the dynamic objects of anamed application.

whocalls

This demo provides a stack trace for a specified function whenever called by anamed application.

perfcnt

This demo traces the amount of time spent in each function for a named application.

symbindrep

This demo reports all symbol bindings performed to load a named application.

sotruss (1) and whocalls (1) are also included in the SUNWtoopackage. perfcntand symbindrep are example programs only and are not intended for use in aproduction environment.

Audit Interface LimitationsThere are some limitations regarding the use of the la_pltexit() function. Theselimitations stem from the need to insert an extra stack frame between the caller andcallee to provide a means of acquiring the la_pltexit() return value. This is not aproblem when calling just the la_*_pltenter( ) routines, as any intervening stackcan be cleaned up prior to transferring control to the destination function.

Because of these limitations la_pltexit() should be considered an experimentalinterface, that may change in future releases to better address these limitations.When in doubt, the use of la_pltexit() should be avoided.

Functions that Directly Inspect the StackA small number of functions exist that directly inspect the stack or makeassumptions regarding its state. Some examples of these functions are thesetjmp (3C) family, vfork (2) and any function that returns a structure (not apointer to a structure). These functions will be compromised by the extra stackcreated to support la_pltexit() .

Support Interfaces 129

The runtime linker cannot detect functions of this type, and thus it becomes theresponsibility of the audit library creator to disable la_pltexit( ) for such routines.

Runtime Linker Debugger InterfaceAs described in Chapter 3 the runtime linker performs many operations includingthe mapping of objects into memory and the binding of symbols. Debuggingprograms often need to access information that describes these runtime linkeroperations as part of analyzing an application. These debugging programs run as aseparate process to the application they are analyzing.

This section describes the supported interface for monitoring and modifying adynamically linked application from another process. This interface is referred to asthe rtld-debugger interface. The architecture of this interface follows the model used inlibthread_db (3T).

When using the rtld-debugger interface at least two processes are involved:

� One or more target processes. The target processes must be dynamically linkedand use /usr/lib/ld.so.1 as their runtime linker.

� A controlling process links with the rtld-debugger interface library and uses it toinspect the dynamic aspects of the target process(es).

The most anticipated use for rtld-debugger is that the controlling process is adebugger and its target is a dynamic executable.

The rtld-debugger interface enables the following for a target process:

� Initial rendezvous with the runtime linker.

� Notification of the loading and unloading of dynamic objects.

� Retrieval of information regarding any loaded objects.

� Stepping over procedure linkage table entries.

� Enabling object padding.

Interaction Between Controlling and TargetProcessTo be able to inspect and manipulate a target process the rtld-debugger interfaceemploys an exported interface, an imported interface and agents for communicatingbetween these interfaces.

The controlling process is linked with the rtld-debugger interface provided bylibrtld_db.so.1 , and makes requests of the interface exported from this library.

130 Linker and Libraries Guide ♦ August 1997

This interface is defined in /usr/include/rtld_db.h . In turn librtld_db.so.1makes requests of the interface imported from the controlling process. Thisinteraction allows the rtld-debugger interface to:

� Look up symbols in a target process.

� Read and write memory in the target process.

The imported interface consists of a number of proc_service routines (which aredescribed in “Debugger Import Interface” on page 141), which most debuggersalready employ to analyze processes.

The rtld-debugger interface assumes that the process being analyzed is stopped whenrequests are made of the rtld-debugger interface. If this is not the case, data structureswithin the runtime linker of the target process may not be in a consistent state forexamination.

The flow of information between librtld_db.so.1 , the controlling process(debugger) and the target process (dynamic executable) is diagrammed below:

rtld_db

/proc

dynamic application

linker inforequest

linkerinfo

r/w process request

process data

debugger

controlling process target process

Figure 6–1 rtld-debugger information flow

Support Interfaces 131

Note - The rtld-debugger interface is dependent upon the proc_service interface(/usr/include/proc_service.h ) which is considered experimental. Thertld-debugger interface may have to track changes in the proc_service interface asit evolves.

A sample implementation of a controlling process that uses the rtld-debugger interfaceis provided in the SUNWosdempackage under /usr/demo/librtld_db . Thisdebugger, rdb , provides an example of using the proc_service imported interface,and shows the required calling sequence for all librtld_db.so.1 exportedinterfaces. The following sections describe the rtld-debugger interfaces, and moredetailed information can be obtained by examining the sample debugger.

Debugger Interface AgentsAn agent provides an opaque handle that can describe internal interface structures,and provides a mechanism of communication between the exported and importedinterfaces. As the rtld-debugger interface is intended to be used by a debugger whichcan manipulate several processes at the same time, these agents are used to identifythe process.

struct ps_prochandle;

struct ps_prochandle

An opaque structure created by the controlling process to identify the target processwhich is passed between the exported and imported interface.

struct rd_agent;

struct rd_agent

An opaque structure created by the rtld-debugger interface identifying the targetprocess which is passed between the exported and imported interface.

Debugger Exported InterfaceThis section describes the various interfaces exported by the/usr/lib/librtld_db.so.1 audit library, and is broken down into functionalgroups.

132 Linker and Libraries Guide ♦ August 1997

Agent Manipulation

rd_err_e rd_init(int version);

rd_init()

This function establishes the rtld-debugger version requirements. The current version isdefined by RD_VERSION.

If the version requirement of the controlling process is greater than the rtld-debuggerinterface available, then RD_NOCAPABis returned.

rd_agent * rd_new(struct ps_prochandle * php);

rd_new()

This function creates a new exported interface agent. php is a cookie created by thecontrolling process to identify the target process. This cookie is used by the importedinterface offered by the controlling process to maintain context, and is opaque to thertld-debugger interface.

rd_err_e rd_reset(struct rd_agent * rdap);

rd_reset()

This function resets the information within the agent based off the sameps_prochandle structure given to rd_new() . This function is called when a targetprocess is restarted.

void rd_delete(struct rd_agent * rdap);

rd_delete( )

This function deletes an agent and frees any state associated with it.

Error HandlingThe following error states can be returned by the rtld-debugger interface (defined inrtld_db.h ):

typedef enum {RD_ERR,RD_OK,RD_NOCAPAB,RD_DBERR,RD_NOBASE,RD_NODYNAM,RD_NOMAPS

(continued)

Support Interfaces 133

(Continuation)

} rd_err_e;

The following interfaces can be used to gather the error information:

char * rd_errstr(rd_err_e rderr);

rd_errstr( )

This function returns a descriptive error string describing the error code rderr.

void rd_log(const int onoff);

rd_log()

This function turns logging on (1) or off (0). When logging is turned on, the importedinterface function ps_plog() provided by the controlling process, is called withmore detailed diagnostic information.

Scanning Loadable ObjectsObtaining information for each object maintained on the runtime linkers link-map(see “Establishing a Name-space” on page 123) is achieved using the followingstructure (defined in rtld_db.h ):

typedef struct rd_loadobj {psaddr_t rl_nameaddr;unsigned rl_flags;psaddr_t rl_base;psaddr_t rl_data_base;unsigned rl_lmident;psaddr_t rl_refnameaddr;psaddr_t rl_plt_base;unsigned rl_plt_size;psaddr_t rl_bend;psaddr_t rl_padstart;psaddr_t rl_padend;

} rd_loadobj_t;

Note that all addresses given in this structure, including string pointers, are addressesin the target process and not in the address space of the controlling process itself:

rl_nameaddr

Pointer to a string which contains the name of the dynamic object.

134 Linker and Libraries Guide ♦ August 1997

rl_flags

Reserved for future use.

rl_base

Base address of dynamic object.

rl_data_base

Base address of data segment of dynamic object.

rl_lmident

The link-map identifier (see “Establishing a Name-space” on page 123).

rl_refnameaddr

If the dynamic object is a filter (see “Shared Objects as Filters” on page 78) then thispoints to the name of the filtee(s).

rl_plt_base , rl_plt_size

These elements are present for backward compatibility and are currently unused.

rl_bend

End address of object (text + data + bss ).

rl_padstart

Base address of padding before dynamic object (refer to “Dynamic Object Padding”on page 141).

rl_padend

Base address of padding after dynamic object (refer to “Dynamic Object Padding” onpage 141).

The following routine uses this object data structure to access information from theruntime linkers link-map lists:

typedef int rl_iter_f(const rd_loadobj_t *, void *);

rd_err_e rd_loadobj_iter(rd_agent_t * rap, rl_iter_f * cb,

Support Interfaces 135

(Continuation)

void * clnt_data);

rd_loadobj_iter( )

This function iterates over all dynamic objects currently loaded in the target process.On each iteration the imported function specified by cb is called. clnt_data can be usedto pass data to the cb call. Information about each object is returned via a pointer to avolatile (stack allocated) rd_loadobj_t structure.

Return codes from the cb routine are examined by rd_loadobj_iter( ) and havethe following meaning:

� 1 - continue processing link-maps.

� 0 - stop processing link-maps and return control to the controlling process.

rd_loadobj_iter( ) returns RD_OKon success. A return of RD_NOMAPSindicatesthe runtime linker has not yet loaded the initial link-maps.

Event NotificationThere are certain events that occur within the scope of the runtime linker that acontrolling process can track. These events are:

RD_PREINIT

The runtime linker has loaded and relocated all the dynamic objects and is about tostart calling the .init sections of each object loaded (see “Initialization andTermination Routines” on page 52).

RD_POSTINIT

The runtime linker has finished calling all of the .init sections and is about totransfer control to the primary executable.

RD_DLACTIVITY

The runtime linker has been invoked to either load or unload a dynamic object (see“Loading Additional Objects” on page 51).

136 Linker and Libraries Guide ♦ August 1997

These events can be monitored using the following interface (defined insys/link.h and rtld_db.h ):

typedef enum {RD_NONE = 0,RD_PREINIT,RD_POSTINIT,RD_DLACTIVITY

} rd_event_e;

/** ways that the event notification can take place:*/

typedef enum {RD_NOTIFY_BPT,RD_NOTIFY_AUTOBPT,RD_NOTIFY_SYSCALL

} rd_notify_e;

/** information on ways that the event notification can take place:*/

typedef struct rd_notify {rd_notify_e type;union {

psaddr_t bptaddr;long syscallno;

} u;} rd_notify_t;

rderr_e rd_event_enable(struct rd_agent * rdap, int onoff);

rd_event_enable( )

This function enables (1) or disables (0) event monitoring.

Note - Presently, for performance reasons, the runtime linker ignores eventdisabling. The controlling process should not assume that a given break-point willnot be reached because of the last call to this routine.

rderr_e rd_event_addr(rd_agent_t * rdap, rd_event_e event,rd_notify_t * notify);

rd_event_addr()

This function specifies how the controlling program will be notified of a given event.

Support Interfaces 137

Depending on the event type, the notification of the controlling process will takeplace by calling a benign, cheap system call which is identified by notify->u.syscallno,or executing a break point at the address specified by notify->u.bptaddr. It is theresponsibility of the controlling process to trace the system call or place the actualbreak-point.

When an event has occurred additional information can be obtained via this interface(defined in rtld_db.h ):

typedef enum {RD_NOSTATE = 0,RD_CONSISTENT,RD_ADD,RD_DELETE

} rd_state_e;

typedef struct rd_event_msg {rd_event_e type;union {

rd_state_e state;} u;

} rd_event_msg_t;

rd_state_e values have the following meaning:

RD_NOSTATE

There is no additional state information available.

RD_CONSISTANT

The link-maps are in a stable state and may be examined.

RD_ADD

A dynamic object is in the process of being loaded and the link-maps are not in astable state. They should not be examined until the RD_CONSISTANTstate is reached.

RD_DELETE

A dynamic object is in the process of being deleted and the link-maps are not in astable state. They should not be examined until the RD_CONSISTANTstate is reached.

138 Linker and Libraries Guide ♦ August 1997

rderr_e rd_event_getmsg(struct rd_agent * rdap,rd_event_msg_t * msg);

rd_event_getmsg()

This function provides additional information concerning an event.

The following table shows the possible state for each of the different event types:

RD_PREINIT RD_POSTINIT RD_DLACTIVITY

RD_NOSTATE RD_NOSTATE RD_CONSISTANT

RD_ADD

RD_DELETE

Procedure Linkage Table SkippingThe rtld-debugger interface offers the ability to help skip over procedure linkage tableentries (refer to “Procedure Linkage Table (Processor-Specific)” on page 219). When acontrolling process, such as a debugger, is asked to step into a function for the firsttime, they often wish to skip the actual procedure linkage table processing as thisresults in control being passed to the runtime linker to search for the functiondefinition.

The following interface allows a controlling process to step over the runtime linkersprocedure linkage table processing. It is assumed that the controlling process candetermine when a procedure linkage table entry is encountered based on externalinformation provided in the ELF file.

Once a target process has stepped into a procedure linkage table entry it calls thefollowing interface:

rd_err_e rd_plt_resolution(rd_agent_t * rdap, paddr_t pc,lwpid_t lwpid, paddr_t plt_base, rd_plt_info_t * rpi);

rd_plt_resolution()

This function returns resolution state of the current procedure linkage table entry andinformation on how to skip it.

pc represents the first instruction of the procedure linkage table entry. lwpid prividesthe lwp identifier and plt_base provides the base address of the procedure linkagetable. These three variables provide information sufficient for various architectures toprocess the procedure linkage table.

Support Interfaces 139

rpi provides detailed information regarding the procedure linkage table entry asdefined in the following data structure (defined in rtld_db.h ):

typedef enum {RD_RESOLVE_NONE,RD_RESOLVE_STEP,RD_RESOLVE_TARGET,RD_RESOLVE_TARGET_STEP

} rd_skip_e;

typedef struct rd_plt_info {rd_skip_e pi_skip_method;long pi_nstep;psaddr_t pi_target;

} rd_plt_info_t;

The following scenarios are possible from the rd_plt_info_t return values:

� This is the first call through this procedure linkage table so it must be resolved bythe runtime linker. rd_plt_info_t will contain:

{RD_RESOLVE_TARGET_STEP, M, <BREAK>}

The controlling process sets a break-point at BREAKand continues the targetprocess. When the break-point is reached the procedure linkage table entryprocessing has finish, and the controlling process can step Minstructions to thedestination function.

� This is the Nth time through this procedure linkage table. rd_plt_info_t willcontain:

{RD_RESOLVE_STEP, M, 0}

The procedure linkage table entry has already been resolved and the controllingprocess can step Minstructions to the destination function.

Note - Future implementations may employ RD_RESOLVE_TARGETas a means ofsetting a break point directly in the target function, however, this capability is not yetavailable in this version of the rtld-debugger interface.

140 Linker and Libraries Guide ♦ August 1997

Dynamic Object PaddingThe default behavior of the runtime linker relies on the operating system to loaddynamic objects where they can be most efficiently referenced. Some controllingprocesses benefit from the existence of padding around the objects loaded intomemory of the target process. This interface allows a controlling process to requestthis padding.

rd_err_e rd_objpad_enable(struct rd_agent * rdap, size_t padsize);

rd_objpad_enable()

This function enables or disables the padding of any subsequently loaded objectswith the target process. Padding occurs on both sides of the loaded object.

padsize specifies the size of the padding, in bytes, to be preserved both before andafter any objects loaded into memory. This padding is reserved as a memorymapping using mmap(2) with PROT_NONEpermissions and the MAP_NORESERVEflag. Effectively the runtime linker reserves areas of the virtual address space of thetarget process adjacent to any mapped objects. These areas can later be utilized bythe controlling process.

A padsize of 0 disables any object padding for later objects.

Note - Reservations obtained using mmap(2) from /dev/zero withMAP_NORESERVEcan be reported using the proc (1) facilities and by referring to thelink-map information provided in rd_loadobj_t .

Debugger Import InterfaceThe imported interface a controlling process must provide to librtld_db.so.1 isdefined in /usr/include/proc_service.h . A sample implementation of theseproc_service functions can be found in the rdb demonstration debugger. Thertld-debugger interface uses only a subset of the proc_service interfaces available.Future versions of the rtld-debugger interface may take advantage of additionalproc_service interfaces without creating an incompatible change.

The following interfaces are currently being used by the rtld-debugger interface:

ps_err_e ps_pauxv(const struct ps_prochandle * ph, auxv_t ** aux);

ps_pauxv()

This function returns a pointer to a copy of the auxv vector. As the auxv vectorinformation is copied to an allocated structure, the life time of this pointer is as longas the prochandle is valid.

Support Interfaces 141

ps_err_e ps_pread(const struct ps_prochandle * ph, paddr_t addr,char * buf, int size);

ps_pread()

This function reads size bytes from the target process at address addr and copies theminto buf.

ps_err_e ps_pwrite(const struct ps_prochandle * ph, paddr_t addr,char * buf, int size);

ps_pwrite( )

This function writes size bytes from buf into the target process at address addr.

void ps_plog(const char * fmt, ...);

ps_plog()

This function is called with additional diagnostic information from the rtld-debuggerinterface. It is up to the controlling process to decide where (or if) to log thisdiagnostic information. The arguments to ps_plog() follow the printf (3S)format.

ps_err_e ps_pglobal_sym(const struct ps_prochandle * ph,const char * obj, const char * name, Elf32_Sym * sym);

ps_pglobal_sym()

This function searches for the symbol named name within the object named obj withinthe target process ph. If the symbol is found the descriptor sym is filled in.

In the event that the rtld-debugger interface needs to find symbols within theapplication or runtime linker prior to any link-map creation, the following reservedvalues for obj are available:

142 Linker and Libraries Guide ♦ August 1997

#define PS_OBJ_EXEC ((const char *)0x0) /* application id */#define PS_OBJ_LDSO ((const char *)0x1) /* runtime linker id */

One mechanism the controlling process can use to find the symbol table for theseobjects is through the procfs file system using the following pseudo code:

ioctl(.., PIOCNAUXV, ...) - obtain AUX vectorsldsoaddr = auxv[AT_BASE];ldsofd = ioctl(..., PIOCOPENM, &ldsoaddr);

/* process elf information found in ldsofd ... */

execfd = ioctl(.., PIOCOPENM, 0);

/* process elf information found in execfd ... */

Once the file descriptors are found, the ELF files can be examined for their symbolinformation by the controlling program.

Support Interfaces 143

144 Linker and Libraries Guide ♦ August 1997

CHAPTER 7

Object Files

OverviewThis chapter describes the executable and linking format (ELF) of the object filesproduced by the assembler and link-editor. There are three main types of object files:

� A relocatable file holds code and data suitable to be linked with other object filesto create an executable or shared object file, or another relocatable object.

� An executable file holds a program that is ready to execute. The file specifies howexec (2) creates a program’s process image.

� A shared object file holds code and data suitable to be linked in two contexts.First, the link-editor can process it with other relocatable and shared object files tocreate other object files. Second, the runtime linker combines it with a dynamicexecutable file and other shared objects to create a process image.

The first section in this chapter, “File Format” on page 146, focuses on the format ofobject files and how that pertains to building programs. The second section,“Dynamic Linking” on page 195, focuses on how the format pertains to loadingprograms.

Programs manipulate object files with the functions contained in the ELF accesslibrary, libelf . Refer to elf (3E) for a description of libelf contents. Samplesource code that uses libelf is provided in the SUNWosdempackage under the/usr/demo/ELF directory.

145

File FormatAs indicated, object files participate in both program linking and program execution.For convenience and efficiency, the object file format provides parallel views of afile’s contents, reflecting the differing needs of these activities. Figure 7–1 shows anobject file’s organization.

Linking view

ELF header

Program header table optional

Section 1

. . .

Section n

. . .

. . .

Section header table

Execution view

ELF header

Program header table

Segment 1

Segment 2

. . .

Section header table optional

Figure 7–1 Object File Format

An ELF header resides at the beginning of an object file and holds a road mapdescribing the file’s organization.

Sections represent the smallest indivisible units that may be processed within an ELFfile. Segments are a collection of sections that represent the smallest individual unitsthat may be mapped to a memory image by exec (2) or by the runtime linker.

Sections hold the bulk of object file information for the linking view: instructions,data, symbol table, relocation information, and so on. Descriptions of sections appearin the first part of this chapter. The second part of this chapter discusses segmentsand the program execution view of the file.

A program header table, if present, tells the system how to create a process image.Files used to build a process image (executables and shared objects) must have aprogram header table; relocatable objects do not need one.

A section header table contains information describing the file’s sections. Everysection has an entry in the table; each entry gives information such as the sectionname, the section size, and so forth. Files used in link-editing must have a sectionheader table; other object files may or may not have one.

146 Linker and Libraries Guide ♦ August 1997

Note - Although the figure shows the program header table immediately after theELF header, and the section header table following the sections; actual files maydiffer. Moreover, sections and segments have no specified order. Only the ELF headerhas a fixed position in the file.

Data RepresentationAs described here, the object file format supports various processors with 8-bit bytesand 32-bit architectures. Nevertheless, it is intended to be extensible to larger (orsmaller) architectures.

Object files therefore represent some control data with a machine-independentformat, making it possible to identify object files and interpret their contents in acommon way. Remaining data in an object file use the encoding of the targetprocessor, regardless of the machine on which the file was created.

TABLE 7–1 32-Bit Data Types

Name Size Alignment Purpose

Elf32_Addr 4 4 Unsigned program address

Elf32_Half 2 2 Unsigned medium integer

Elf32_Off 4 4 Unsigned file offset

Elf32_Sword 4 4 Signed large integer

Elf32_Word 4 4 Unsigned large integer

unsigned char 1 1 Unsigned small integer

All data structures that the object file format defines follow the natural size andalignment guidelines for the relevant class. If necessary, data structures containexplicit padding to ensure 4-byte alignment for 4-byte objects, to force structure sizesto a multiple of 4, and so forth. Data also have suitable alignment from thebeginning of the file. Thus, for example, a structure containing an Elf32_Addrmember will be aligned on a 4-byte boundary within the file.

Object Files 147

Note - For portability, ELF uses no bit-fields.

ELF HeaderSome object file control structures can grow, because the ELF header contains theiractual sizes. If the object file format changes, a program may encounter controlstructures that are larger or smaller than expected. Programs might therefore ignoreextra information. The treatment of missing information depends on context and willbe specified if and when extensions are defined.

The ELF header has the following structure (defined in sys/elf.h ):

#define EI_NIDENT 16

typedef struct {unsigned char e_ident[EI_NIDENT];Elf32_Half e_type;Elf32_Half e_machine;Elf32_Word e_version;Elf32_Addr e_entry;Elf32_Off e_phoff;Elf32_Off e_shoff;Elf32_Word e_flags;Elf32_Half e_ehsize;Elf32_Half e_phentsize;Elf32_Half e_phnum;Elf32_Half e_shentsize;Elf32_Half e_shnum;Elf32_Half e_shstrndx;

} Elf32_Ehdr;

e_ident

The initial bytes mark the file as an object file and provide machine-independent datawith which to decode and interpret the file’s contents. Complete descriptions appearin “ELF Identification” on page 152.

e_type

This member identifies the object file type.

148 Linker and Libraries Guide ♦ August 1997

TABLE 7–2 ELF File Identifiers

Name Value Meaning

ET_NONE 0 No file type

ET_REL 1 Relocatable file

ET_EXEC 2 Executable file

ET_DYN 3 Shared object file

ET_CORE 4 Core file

ET_LOPROC 0xff00 Processor-specific

ET_HIPROC 0xffff Processor-specific

Although the core file contents are unspecified, type ET_COREis reserved to markthe file. Values from ET_LOPROCthrough ET_HIPROC(inclusive) are reserved forprocessor-specific semantics. Other values are reserved and will be assigned to newobject file types as necessary.

e_machine

This member’s value specifies the required architecture for an individual file.

TABLE 7–3 ELF Machines

Name Value Meaning

EM_NONE 0 No machine

EM_M32 1 AT&T WE 32100

EM_SPARC 2 SPARC

EM_386 3 Intel 80386

EM_68K 4 Motorola 68000

Object Files 149

TABLE 7–3 ELF Machines (continued)

Name Value Meaning

EM_88K 5 Motorola 88000

EM_486 6 Intel 80486

EM_860 7 Intel 80860

EM_MIPS 8 MIPS RS3000 Big-Endian

EM_MIPS_RS3_LE 10 MIPS RS3000 Little-Endian

EM_RS6000 11 RS6000

EM_PA_RISC 15 PA-RISC

EM_nCUBE 16 nCUBE

EM_VPP500 17 Fujitsu VPP500

EM_SPARC32PLUS 18 Sun SPARC 32+

EM_PPC 20 PowerPC

Other values are reserved and will be assigned to new machines as necessary.Processor-specific ELF names use the machine name to distinguish them. Forexample, the flags mentioned below use the prefix EF_; a flag named WIDGETfor theEM_XYZmachine would be called EF_XYZ_WIDGET.

e_version

This member identifies the object file version.

150 Linker and Libraries Guide ♦ August 1997

TABLE 7–4 ELF Versions

Name Value Meaning

EV_NONE 0 Invalid version

EV_CURRENT >=1 Current version

The value 1 signifies the original file format; extensions will create new versions withhigher numbers. The value of EV_CURRENTchanges as necessary to reflect thecurrent version number.

e_entry

This member gives the virtual address to which the system first transfers control, thusstarting the process. If the file has no associated entry point, this member holds zero.

e_phoff

This member holds the program header table’s file offset in bytes. If the file has noprogram header table, this member holds zero.

e_shoff

This member holds the section header table’s file offset in bytes. If the file has nosection header table, this member holds zero.

e_flags

This member holds processor-specific flags associated with the file. Flag names takethe form EF_machine _flag. This member is presently zero for SPARC and x86.

e_ehsize

This member holds the ELF header’s size in bytes.

e_phentsize

This member holds the size in bytes of one entry in the file’s program header table;all entries are the same size.

Object Files 151

e_phnum

This member holds the number of entries in the program header table. Thus theproduct of e_phentsize and e_phnum gives the table’s size in bytes. If a file has noprogram header table, e_phnum holds the value zero.

e_shentsize

This member holds a section header’s size in bytes. A section header is one entry inthe section header table; all entries are the same size.

e_shnum

This member holds the number of entries in the section header table. Thus theproduct of e_shentsize and e_shnum gives the section header table’s size in bytes.If a file has no section header table, e_shnum holds the value zero.

e_shstrndx

This member holds the section header table index of the entry associated with thesection name string table. If the file has no section name string table, this memberholds the value SHN_UNDEF. See “Sections” on page 155 and “String Table” on page170 for more information.

ELF IdentificationAs mentioned above, ELF provides an object file framework to support multipleprocessors, multiple data encoding, and multiple classes of machines. To support thisobject file family, the initial bytes of the file specify how to interpret the file,independent of the processor on which the inquiry is made and independent of thefile’s remaining contents.

The initial bytes of an ELF header (and an object file) correspond to the e_identmember.

TABLE 7–5 e_ident[ ] Identification Index

Name Value Purpose

EI_MAG0 0 File identification

EI_MAG1 1 File identification

152 Linker and Libraries Guide ♦ August 1997

TABLE 7–5 e_ident[ ] Identification Index (continued)

Name Value Purpose

EI_MAG2 2 File identification

EI_MAG3 3 File identification

EI_CLASS 4 File class

EI_DATA 5 Data encoding

EI_VERSION 6 File version

EI_PAD 7 Start of padding bytes

EI_NIDENT 16 Size ofe_ident[]

These indexes access bytes that hold the following values:

EI_MAG0 - EI_MAG3

A file’s first 4 bytes hold a magic number, identifying the file as an ELF object file.

TABLE 7–6 Magic Number

Name Value Position

ELFMAG0 0x7f e_ident[EI_MAG0]

ELFMAG1 ’E’ e_ident[EI_MAG1]

ELFMAG2 ’L’ e_ident[EI_MAG2]

ELFMAG3 ’F’ e_ident[EI_MAG3]

EI_CLASS

The next byte, e_ident[EI_CLASS] , identifies the file’s class, or capacity.

Object Files 153

TABLE 7–7 File Class

Name Value Meaning

ELFCLASSNONE 0 Invalid class

ELFCLASS32 1 32-bit objects

ELFCLASS64 2 64-bit objects

The file format is designed to be portable among machines of various sizes, withoutimposing the sizes of the largest machine on the smallest. Class ELFCLASS32supports machines with files and virtual address spaces up to 4 gigabytes; it uses thebasic types defined above.

Class ELFCLASS64 is reserved for 64-bit architectures. Its appearance here showshow the object file may change, but the 64-bit format is otherwise unspecified. Otherclasses will be defined as necessary, with different basic types and sizes for object filedata.

EI_DATA

Byte e_ident[EI_DATA] specifies the data encoding of the processor-specific datain the object file. The following encodings are currently defined.

TABLE 7–8 Data Encoding

Name Value Meaning

ELFDATANONE 0 Invalid data encoding

ELFDATA2LSB 1 See Figure 7–2.

ELFDATA2MSB 2 See Figure 7–3.

More information on these encodings appears below. Other values are reserved andwill be assigned to new encodings as necessary.

154 Linker and Libraries Guide ♦ August 1997

EI_VERSION

Byte e_ident[EI_VERSION] specifies the ELF header version number. Currently,this value must be EV_CURRENT, as explained in Table 7–4 for e_version .

EI_PAD

This value marks the beginning of the unused bytes in e_ident . These bytes arereserved and set to zero; programs that read object files should ignore them. Thevalue of EI_PAD will change in the future if currently unused bytes are givenmeanings.

A file’s data encoding specifies how to interpret the basic objects in a file. Asdescribed above, class ELFCLASS32files use objects that occupy 1, 2, and 4 bytes.Under the defined encodings, objects are represented as shown below. Byte numbersappear in the upper left corners.

Encoding ELFDATA2LSBspecifies 2’s complement values, with the least significantbyte occupying the lowest address.

0x01 010

0x0102 02 010 1

0x01020304 04 03 02 010 1 2 3

Figure 7–2 Data Encoding ELFDATA2LSB

Encoding ELFDATA2MSBspecifies 2’s complement values, with the most significantbyte occupying the lowest address.

0x01 010

0x0102 01 020 1

0x01020304 01 02 03 040 1 2 3

Figure 7–3 Data Encoding ELFDATA2MSB

SectionsAn object file’s section header table lets you locate all file’s sections. The sectionheader table is an array of Elf32_Shdr structures as described below. A sectionheader table index is a subscript into this array. The ELF header’s e_shoff membergives the byte offset from the beginning of the file to the section header table;

Object Files 155

e_shnum tells how many entries the section header table contains; e_shentsizegives the size in bytes of each entry.

Some section header table indexes are reserved; an object file does not have sectionsfor these special indexes.

TABLE 7–9 Special Section Indexes

Name Value

SHN_UNDEF 0

SHN_LORESERVE 0xff00

SHN_LOPROC 0xff00

SHN_BEFORE 0xff00

SHN_AFTER 0xff01

SHN_HIPROC 0xff1f

SHN_ABS 0xfff1

SHN_COMMON 0xfff2

SHN_HIRESERVE 0xffff

SHN_UNDEF

This value marks an undefined, missing, irrelevant, or otherwise meaningless sectionreference. For example, a symbol defined relative to section number SHN_UNDEFis anundefined symbol.

Note - Although index 0 is reserved as the undefined value, the section header tablecontains an entry for index 0. That is, if the e_shnum member of the ELF headersays a file has 6 entries in the section header table, they have the indexes 0 through5. The contents of the initial entry are specified later in this section.

156 Linker and Libraries Guide ♦ August 1997

SHN_LORESERVE

This value specifies the lower bound of the range of reserved indexes.

SHN_LOPROC- SHN_HIPROC

Values in this inclusive range are reserved for processor-specific semantics.

SHN_BEFORE, SHN_AFTER

These values provide for initial and final section ordering in conjunction with theSHF_ORDEREDsection flag (see Table 7–12).

SHN_ABS

This value specifies absolute values for the corresponding reference. For example,symbols defined relative to section number SHN_ABShave absolute values and arenot affected by relocation.

SHN_COMMON

Symbols defined relative to this section are common symbols, such as FORTRANCOMMONor unallocated C external variables. These symbols are sometimes referred toas tentative.

SHN_HIRESERVE

This value specifies the upper bound of the range of reserved indexes. The systemreserves indexes between SHN_LORESERVEand SHN_HIRESERVE, inclusive; thevalues do not reference the section header table. That is, the section header table doesnot contain entries for the reserved indexes.

Sections contain all information in an object file except the ELF header, the programheader table, and the section header table. Moreover, object files’ sections satisfyseveral conditions:

� Every section in an object file has exactly one section header describing it. Sectionheaders may exist that do not have a section.

� Each section occupies one contiguous (possibly empty) sequence of bytes within afile.

� Sections in a file may not overlap. No byte in a file resides in more than onesection.

� An object file may have inactive space. The various headers and the sections mightnot cover every byte in an object file. The contents of the inactive data areunspecified.

Object Files 157

A section header has the following structure (defined in sys/elf.h ):

typedef struct {Elf32_Word sh_name;Elf32_Word sh_type;Elf32_Word sh_flags;Elf32_Addr sh_addr;Elf32_Off sh_offset;Elf32_Word sh_size;Elf32_Word sh_link;Elf32_Word sh_info;Elf32_Word sh_addralign;Elf32_Word sh_entsize;

} Elf32_Shdr;

sh_name

This member specifies the name of the section. Its value is an index into the sectionheader string table section (see “String Table” on page 170) giving the location of anull-terminated string. Section names and their descriptions are in Table 7–14.

sh_type

This member categorizes the section’s contents and semantics. Section types and theirdescriptions are in Table 7–10.

sh_flags

Sections support 1-bit flags that describe miscellaneous attributes. Flag definitions arein Table 7–12.

sh_addr

If the section is to appear in the memory image of a process, this member gives theaddress at which the section’s first byte should reside. Otherwise, the membercontains 0.

sh_offset

This member gives the byte offset from the beginning of the file to the first byte inthe section. Section type SHT_NOBITS, described below, occupies no space in the file,and its sh_offset member locates the conceptual placement in the file.

158 Linker and Libraries Guide ♦ August 1997

sh_size

This member gives the section’s size in bytes. Unless the section type isSHT_NOBITS, the section occupies sh_size bytes in the file. A section of typeSHT_NOBITSmay have a nonzero size, but it occupies no space in the file.

sh_link

This member holds a section header table index link, whose interpretation dependson the section type. Table 7–13 describes the values.

sh_info

This member holds extra information, whose interpretation depends on the sectiontype. Table 7–13 describes the values.

sh_addralign

Some sections have address alignment constraints. For example, if a section holds adouble-word, the system must ensure double-word alignment for the entire section.That is, the value of sh_addr must be congruent to 0, modulo the value ofsh_addralign . Currently, only 0 and positive integral powers of two are allowed.Values 0 and 1 mean the section has no alignment constraints.

sh_entsize

Some sections hold a table of fixed-size entries, such as a symbol table. For such asection, this member gives the size in bytes of each entry. The member contains 0 ifthe section does not hold a table of fixed-size entries.

A section header’s sh_type member specifies the section’s semantics:

TABLE 7–10 Section Types, sh_type

Name Value

SHT_NULL 0

SHT_PROGBITS 1

SHT_SYMTAB 2

SHT_STRTAB 3

Object Files 159

TABLE 7–10 Section Types, sh_type (continued)

Name Value

SHT_RELA 4

SHT_HASH 5

SHT_DYNAMIC 6

SHT_NOTE 7

SHT_NOBITS 8

SHT_REL 9

SHT_SHLIB 10

SHT_DYNSYM 11

SHT_SUNW_verdef 0x6ffffffd

SHT_SUNW_verneed 0x6ffffffe

SHT_SUNW_versym 0x6fffffff

SHT_LOPROC 0x70000000

SHT_HIPROC 0x7fffffff

SHT_LOUSER 0x80000000

SHT_HIUSER 0xffffffff

SHT_NULL

This value marks the section header as inactive; it does not have an associatedsection. Other members of the section header have undefined values.

160 Linker and Libraries Guide ♦ August 1997

SHT_PROGBITS

The section holds information defined by the program, whose format and meaningare determined solely by the program.

SHT_SYMTAB, SHT_DYNSYM

These sections hold a symbol table. Typically a SHT_SYMTABsection providessymbols for link-editing. As a complete symbol table, it may contain many symbolsunnecessary for dynamic linking. Consequently, an object file may also contain aSHT_DYNSYMsection, which holds a minimal set of dynamic linking symbols, to savespace. See “Symbol Table” on page 171 for details.

SHT_STRTAB, SHT_DYNSTR

These sections hold a string table. An object file may have multiple string tablesections. See “String Table” on page 170 for details.

SHT_RELA

The section holds relocation entries with explicit addends, such as type Elf32_Relafor the 32-bit class of object files. An object file may have multiple relocation sections.See “Relocation” on page 177 for details.

SHT_HASH

The section holds a symbol hash table. All dynamically linked object files mustcontain a symbol hash table. Currently, an object file may have only one hash table,but this restriction may be relaxed in the future. See “Hash Table” on page 223 fordetails.

SHT_DYNAMIC

The section holds information for dynamic linking. Currently, an object file may haveonly one dynamic section, but this restriction may be relaxed in the future. See“Dynamic Section” on page 209 for details.

SHT_NOTE

The section holds information that marks the file in some way. See “Note Section” onpage 193 for details.

Object Files 161

SHT_NOBITS

A section of this type occupies no space in the file but otherwise resemblesSHT_PROGBITS. Although this section contains no bytes, the sh_offset membercontains the conceptual file offset.

SHT_REL

The section holds relocation entries without explicit addends, such as typeElf32_Rel for the 32-bit class of object files. An object file may have multiplerelocation sections. See “Relocation” on page 177 for details.

SHT_SHLIB

This section type is reserved but has unspecified semantics. Programs that contain asection of this type do not conform to the ABI.

SHT_SUNW_verdef

The section contains definitions of fine-grained versions defined by this file.

SHT_SUNW_verneed

The section contains descriptions of fine-grained dependencies required for theexecution of an image.

SHT_SUNW_versym

The section contains a table describing the relationship of symbols to the versiondefinitions offered by the file.

SHT_LOPROC- SHT_HIPROC

Values in this inclusive range are reserved for processor-specific semantics.

SHT_LOUSER

This value specifies the lower bound of the range of indexes reserved for applicationprograms.

SHT_HIUSER

This value specifies the upper bound of the range of indexes reserved for applicationprograms. Section types between SHT_LOUSERand SHT_HIUSERmay be used by theapplication, without conflicting with current or future system-defined section types.

162 Linker and Libraries Guide ♦ August 1997

Other section type values are reserved. As mentioned before, the section header forindex 0 (SHN_UNDEF) exists, even though the index marks undefined sectionreferences. This entry holds the following:

TABLE 7–11 Section Header Table Entry: Index 0

Name Value Note

sh_name 0 No name

sh_type SHT_NULL Inactive

sh_flags 0 No flags

sh_addr 0 No address

sh_offset 0 No file offset

sh_size 0 No size

sh_link SHN_UNDEF No link information

sh_info 0 No auxiliary information

sh_addralign 0 No alignment

sh_entsize 0 No entries

A section header’s sh_flags member holds 1-bit flags that describe the section’sattributes:

TABLE 7–12 Section Attribute Flags

Name Value

SHF_WRITE 0x1

SHF_ALLOC 0x2

SHF_EXECINSTR 0x4

Object Files 163

TABLE 7–12 Section Attribute Flags (continued)

Name Value

SHF_ORDERED 0x40000000

SHF_EXCLUDE 0x80000000

SHF_MASKPROC 0xf0000000

If a flag bit is set in sh_flags , the attribute is on for the section. Otherwise, theattribute is off or does not apply. Undefined attributes are reserved and set to zero.

SHF_WRITE

The section contains data that should be writable during process execution.

SHF_ALLOC

The section occupies memory during process execution. Some control sections do notreside in the memory image of an object file; this attribute is off for those sections.

SHF_EXECINSTR

The section contains executable machine instructions.

SHF_ORDERED

The section requires ordering in relation to other sections of the same type. Orderedsections are combined within the section pointed to by the sh_link entry. Thesh_link entry of an ordered section may point to itself.

If the sh_info entry of the ordered section is a valid section within the same inputfile, the ordered section will be sorted based on the relative ordering within theoutput file of the section pointed to by the sh_info entry. The special sh_infovalues SHN_BEFOREand SHN_AFTER(see Table 7–9) imply that the sorted section isto precede or follow, respectively, all other sections in the set being ordered. Input filelink-line order is preserved if multiple sections in an ordered set have one of thesespecial values.

In the absence of the sh_info ordering information, sections from a single input filecombined within one section of the output file shall be contiguous and have the samerelative ordering as they did in the input file. The contributions from multiple inputfiles shall appear in link-line order.

164 Linker and Libraries Guide ♦ August 1997

SHF_EXCLUDE

The section is excluded from input to the link-edit of an executable or shared object.This flag is ignored if the SHF_ALLOCflag is also set, or if relocations exist againstthe section.

SHF_MASKPROC

All bits included in this mask are reserved for processor-specific semantics.

Two members in the section header, sh_link and sh_info , hold specialinformation, depending on section type.

TABLE 7–13 sh_link and sh_info Interpretation

sh_type sh_link sh_info

SHT_DYNAMIC The section header index ofthe associated string table.

0

SHT_HASH The section header index ofthe associated symbol table.

0

SHT_REL

SHT_RELA

The section header index ofthe associated symbol table.

The section header index of thesection to which the relocationapplies. See also Table 7–14.

SHT_SYMTAB

SHT_DYNSYM

The section header index ofthe associated string table.

One greater than the symboltable index of the last localsymbol (binding STB_LOCAL).

SHT_SUNW_verdef The section header index ofthe associated string table.

The number of versiondefinitions within the section.

SHT_SUNW_verneed The section header index ofthe associated string table.

The number of versiondependencies within thesection.

SHT_SUNW_versym The section header index ofthe associated symbol table.

0

other SHN_UNDEF 0

Object Files 165

Special SectionsVarious sections hold program and control information. Sections in the list below areused by the system and have the indicated types and attributes.

TABLE 7–14 Special Sections

Name Type Attribute

.bss SHT_NOBITS SHF_ALLOC + SHF_WRITE

.comment SHT_PROGBITS None

.data SHT_PROGBITS SHF_ALLOC + SHF_WRITE

.data1 SHT_PROGBITS SHF_ALLOC + SHF_WRITE

.dynamic SHT_DYNAMIC SHF_ALLOC + SHF_WRITE

.dynstr SHT_STRTAB SHF_ALLOC

.dynsym SHT_DYNSYM SHF_ALLOC

.fini SHT_PROGBITS SHF_ALLOC + SHF_EXECINSTR

.got SHT_PROGBITS See “Global Offset Table(Processor-Specific)” on page 218

.hash SHT_HASH SHF_ALLOC

.init SHT_PROGBITS SHF_ALLOC + SHF_EXECINSTR

.interp SHT_PROGBITS See “Program Interpreter” on page 207

.note SHT_NOTE None

.plt SHT_PROGBITS See “Procedure Linkage Table(Processor-Specific)” on page 219

.rel name SHT_REL See “Relocation” on page 177

.rela name SHT_RELA See “Relocation” on page 177

166 Linker and Libraries Guide ♦ August 1997

TABLE 7–14 Special Sections (continued)

Name Type Attribute

.rodata SHT_PROGBITS SHF_ALLOC

.rodata1 SHT_PROGBITS SHF_ALLOC

.shstrtab SHT_STRTAB None

.strtab SHT_STRTAB See description below

.symtab SHT_SYMTAB See “Symbol Table” on page 171

.text SHT_PROGBITS SHF_ALLOC + SHF_EXECINSTR

.SUNW_heap SHT_PROGBITS SHF_ALLOC + SHF_WRITE

.SUNW_reloc SHT_rel

SHT_rela

SHF_ALLOC

.SUNW_version SHT_SUNW_verdef

SHT_SUNW_verneed

SHT_SUNW_versym

SHF_ALLOC

.bss

This section holds uninitialized data that contribute to the program’s memory image.By definition, the system initializes the data with zeros when the program begins torun. The section occupies no file space, as indicated by the section type,SHT_NOBITS.

.comment

This section holds comment information.

.data , .data1

These sections hold initialized data that contribute to the program’s memory image.

Object Files 167

.dynamic

This section holds dynamic linking information.

.dynstr

This section holds strings needed for dynamic linking, most commonly the stringsthat represent the names associated with symbol table entries.

.dynsym

This section holds the dynamic linking symbol table. See “Symbol Table” on page 171for details.

.fini

This section holds executable instructions that contribute to the process terminationcode. That is, when a program exits normally, the system arranges to execute thecode in this section.

.got

This section holds the global offset table. See “Global Offset Table(Processor-Specific)” on page 218 for more information.

.hash

This section holds a symbol hash table. See “Hash Table” on page 223 for moreinformation.

.init

This section holds executable instructions that contribute to the process initializationcode. That is, when a program starts to run, the system arranges to execute the codein this section before calling the program entry point.

.interp

This section holds the path name of a program interpreter. See “Program Interpreter”on page 207 for more information.

.note

This section holds information in the format that “Note Section” on page 193describes.

168 Linker and Libraries Guide ♦ August 1997

.plt

This section holds the procedure linkage table. See “Procedure Linkage Table(Processor-Specific)” on page 219 for more information.

.rel name, .rela name

These sections hold relocation information, as “Relocation” on page 177 describes. Ifthe file has a loadable segment that includes relocation, the sections’ attributes willinclude the SHF_ALLOCbit; otherwise, that bit will be off. Conventionally, name issupplied by the section to which the relocations apply. Thus a relocation section for.text normally will have the name .rel.text or .rela.text .

.rodata , .rodata1

These sections hold read-only data that typically contribute to a non-writablesegment in the process image. See “Program Header” on page 195 for moreinformation.

.shstrtab

This section holds section names.

.strtab

This section holds strings, most commonly the strings that represent the namesassociated with symbol table entries. If the file has a loadable segment that includesthe symbol string table, the section’s attributes will include the SHF_ALLOCbit;otherwise, that bit will be off.

.symtab

This section holds a symbol table, as “Symbol Table” on page 171 describes. If the filehas a loadable segment that includes the symbol table, the section’s attributes willinclude the SHF_ALLOCbit; otherwise, that bit will be off.

.text

This section holds the text or executable instructions of a program.

.SUNW_heap

This section holds the heap of a dynamic executable created from dldump (3X).

Object Files 169

.SUNW_reloc

This section holds relocation information, as “Relocation” on page 177 describes. Thissection is a concatenation of relocation sections that provides better locality ofreference of the individual relocation records. Only the offset of the relocation recorditself is meaningful and thus the section sh_info value is zero.

.SUNW_version

Sections of this name hold versioning information. See “Versioning Information” onpage 187 for more information.

Section names with a dot (.) prefix are reserved for the system, although applicationsmay use these sections if their existing meanings are satisfactory. Applications mayuse names without the prefix to avoid conflicts with system sections. The object fileformat lets one define sections not in the list above. An object file may have morethan one section with the same name.

Section names reserved for a processor architecture are formed by placing anabbreviation of the architecture name ahead of the section name. The name shouldbe taken from the architecture names used for e_machine . For example,.Foo.psect is the psect section defined by the FOOarchitecture.

Existing extensions use their historical names.

Preexisting Extensions:

.conflict .liblist .lit8 .sdata

.debug .line .reginfo .stab

.gptab .lit4 .sbss .tdesc

String TableString table sections hold null-terminated character sequences, commonly calledstrings. The object file uses these strings to represent symbol and section names. Onereferences a string as an index into the string table section.

The first byte, which is index zero, is defined to hold a null character. Likewise, astring table’s last byte is defined to hold a null character, ensuring null terminationfor all strings. A string whose index is zero specifies either no name or a null name,depending on the context.

An empty string table section is permitted; its section header’s sh_size memberwill contain zero. Nonzero indexes are invalid for an empty string table.

170 Linker and Libraries Guide ♦ August 1997

A section header’s sh_name member holds an index into the section header stringtable section, as designated by the e_shstrndx member of the ELF header. Thefollowing figures show a string table with 25 bytes and the strings associated withvarious indexes.

0 \0 n a m e . \0 V a r

20 \0 \0 x x \0

10 i a b l e \0 a b l e

Index +0 +1 +2 +3 +4 +5 +6 +7 +8 +9

Figure 7–4 String Table

The table below shows the strings of the string table above:

TABLE 7–15 String Table Indexes

Index String

0 none

1 name.

7 Variable

11 able

16 able

24 null string

As the example shows, a string table index may refer to any byte in the section. Astring may appear more than once; references to substrings may exist; and a singlestring may be referenced multiple times. Unreferenced strings also are allowed.

Symbol TableAn object file’s symbol table holds information needed to locate and relocate aprogram’s symbolic definitions and references. A symbol table index is a subscriptinto this array. Index 0 both designates the first entry in the table and serves as theundefined symbol index. The contents of the initial entry are specified later in thissection.

Object Files 171

TABLE 7–16 Symbol Table Initial Entry

Name Value

STN_UNDEF 0

A symbol table entry has the following format (defined in sys/elf.h ):

typedef struct {Elf32_Word st_name;Elf32_Addr st_value;Elf32_Word st_size;unsigned char st_info;unsigned char st_other;Elf32_Half st_shndx;

} Elf32_Sym;

st_name

This member holds an index into the object file’s symbol string table, which holds thecharacter representations of the symbol names. If the value is nonzero, it represents astring table index that gives the symbol name. Otherwise, the symbol table entry hasno name.

Note - External C symbols have the same names in C and in object files’ symboltables.

st_value

This member gives the value of the associated symbol. Depending on the context,this may be an absolute value, an address, and so forth. See “Symbol Values” onpage 177.

st_size

Many symbols have associated sizes. For example, a data object’s size is the numberof bytes contained in the object. This member holds 0 if the symbol has no size or anunknown size.

172 Linker and Libraries Guide ♦ August 1997

st_info

This member specifies the symbol’s type and binding attributes. A list of the valuesand meanings appears below. The following code shows how to manipulate thevalues (defined in sys/elf.h ):

#define ELF32_ST_BIND(i) ((i) >> 4)#define ELF32_ST_TYPE(i) ((i) & 0xf)#define ELF32_ST_INFO(b, t) (((b)<<4)+((t)&0xf))

st_other

This member currently holds 0 and has no defined meaning.

st_shndx

Every symbol table entry is defined in relation to some section; this member holdsthe relevant section header table index. Some section indexes indicate specialmeanings. See Table 7–10.

A symbol’s binding determines the linkage visibility and behavior.

TABLE 7–17 Symbol Binding, ELF32_ST_BIND

Name Value

STB_LOCAL 0

STB_GLOBAL 1

STB_WEAK 2

STB_LOPROC 13

STB_HIPROC 15

STB_LOCAL

Local symbols are not visible outside the object file containing their definition. Localsymbols of the same name may exist in multiple files without interfering with eachother.

Object Files 173

STB_GLOBAL

Global symbols are visible to all object files being combined. One file’s definition of aglobal symbol will satisfy another file’s undefined reference to the same globalsymbol.

STB_WEAK

Weak symbols resemble global symbols, but their definitions have lower precedence.

STB_LOPROC- STB_HIPROC

Values in this inclusive range are reserved for processor-specific semantics.

Global and weak symbols differ in two major ways:

� When the link-editor combines several relocatable object files, it does not allowmultiple definitions of STB_GLOBALsymbols with the same name. On the otherhand, if a defined global symbol exists, the appearance of a weak symbol with thesame name will not cause an error. The link-editor honors the global definitionand ignores the weak ones.

Similarly, if a common symbol exists (that is, a symbol with the st_index fieldholding SHN_COMMON), the appearance of a weak symbol with the same namedoes not cause an error. The link-editor uses the common definition and ignoresthe weak one.

� When the link-editor searches archive libraries (see “Archive Processing” on page11) it extracts archive members that contain definitions of undefined or tentative,global symbols. The member’s definition may be either a global or a weak symbol.

The link-editor, by default, does not extract archive members to resolve undefinedweak symbols. Unresolved weak symbols have a zero value. The use of −zweakextract overrides this default behavior, and allows weak references tocause the extraction of archive members.

In each symbol table, all symbols with STB_LOCALbinding precede the weak andglobal symbols. As “Sections” on page 155 describes, a symbol table section’ssh_info section header member holds the symbol table index for the first non-localsymbol.

A symbol’s type provides a general classification for the associated entity.

174 Linker and Libraries Guide ♦ August 1997

TABLE 7–18 Symbol Types, ELF32_ST_TYPE

Name Value

STT_NOTYPE 0

STT_OBJECT 1

STT_FUNC 2

STT_SECTION 3

STT_FILE 4

STT_LOPROC 13

STT_HIPROC 15

STT_NOTYPE

The symbol type is not specified.

STT_OBJECT

The symbol is associated with a data object, such as a variable, an array, and so forth.

STT_FUNC

The symbol is associated with a function or other executable code.

STT_SECTION

The symbol is associated with a section. Symbol table entries of this type existprimarily for relocation and normally have STB_LOCAL binding.

STT_FILE

Conventionally, the symbol’s name gives the name of the source file associated withthe object file. A file symbol has STB_LOCALbinding, its section index is SHN_ABS,and it precedes the other STB_LOCALsymbols for the file, if it is present. Symbolindex 1 of the SHT_SYMTABis an STT_FILE symbol representing the file itself.

Object Files 175

Conventionally, this is followed by the files STT_SECTIONsymbols, and any globalsymbols that have been reduced to locals (see “Reducing Symbol Scope” on page 33,and Chapter 5 for more details).

STT_LOPROC- STT_HIPROC

Values in this inclusive range are reserved for processor-specific semantics.

Function symbols (those with type STT_FUNC) in shared object files have specialsignificance. When another object file references a function from a shared object, thelink-editor automatically creates a procedure linkage table entry for the referencedsymbol. Shared object symbols with types other than STT_FUNCwill not bereferenced automatically through the procedure linkage table.

If a symbol’s value refers to a specific location within a section, its section indexmember, st_shndx , holds an index into the section header table. As the sectionmoves during relocation, the symbol’s value changes as well, and references to thesymbol continue to point to the same location in the program. Some special sectionindex values give other semantics:

SHN_ABS

The symbol has an absolute value that will not change because of relocation.

SHN_COMMON

The symbol labels a common block that has not yet been allocated. The symbol’svalue gives alignment constraints, similar to a section’s sh_addralign member.That is, the link-editor will allocate the storage for the symbol at an address that is amultiple of st_value . The symbol’s size tells how many bytes are required.

SHN_UNDEF

This section table index means the symbol is undefined. When the link-editorcombines this object file with another that defines the indicated symbol, this file’sreferences to the symbol will be bound to the actual definition.

As mentioned above, the symbol table entry for index 0 (STN_UNDEF) is reserved; itholds the following:

176 Linker and Libraries Guide ♦ August 1997

TABLE 7–19 Symbol Table Entry: Index 0

Name Value Note

st_name 0 No name

st_value 0 Zero value

st_size 0 No size

st_info 0 No type, local binding

st_other 0

st_shndx SHN_UNDEF No section

Symbol ValuesSymbol table entries for different object file types have slightly differentinterpretations for the st_value member.

� In relocatable files, st_value holds alignment constraints for a symbol whosesection index is SHN_COMMON.

� In relocatable files, st_value holds a section offset for a defined symbol. That is,st_value is an offset from the beginning of the section that st_shndx identifies.

� In executable and shared object files, st_value holds a virtual address. To makethese files’ symbols more useful for the runtime linker, the section offset (fileinterpretation) gives way to a virtual address (memory interpretation) for whichthe section number is irrelevant.

Although the symbol table values have similar meanings for different object files, thedata allow efficient access by the appropriate programs.

RelocationRelocation is the process of connecting symbolic references with symbolic definitions.For example, when a program calls a function, the associated call instruction musttransfer control to the proper destination address at execution. In other words,relocatable files must have information that describes how to modify their sectioncontents, thus allowing executable and shared object files to hold the rightinformation for a process’s program image. Relocation entries are these data.

Object Files 177

Relocation entries can have the following structure (defined in sys/elf.h ):

typedef struct {Elf32_Addr r_offset;Elf32_Word r_info;

} Elf32_Rel;

typedef struct {Elf32_Addr r_offset;Elf32_Word r_info;Elf32_Sword r_addend;

} Elf32_Rela;

r_offset

This member gives the location at which to apply the relocation action. For arelocatable file, the value is the byte offset from the beginning of the section to thestorage unit affected by the relocation. For an executable file or a shared object, thevalue is the virtual address of the storage unit affected by the relocation.

r_info

This member gives both the symbol table index with respect to which the relocationmust be made and the type of relocation to apply. For example, a call instruction’srelocation entry will hold the symbol table index of the function being called. If theindex is STN_UNDEF, the undefined symbol index, the relocation uses 0 as the symbolvalue. Relocation types are processor-specific; descriptions of their behavior appearbelow. When the text below refers to a relocation entry’s relocation type or symboltable index, it means the result of applying ELF32_R_TYPE or ELF32_R_SYM,respectively, to the entry’s r_info member:

#define ELF32_R_SYM(i) ((i)>>8)#define ELF32_R_TYPE(i) ((unsigned char)(i))#define ELF32_R_INFO(s, t) (((s)<<8)+(unsigned char)(t))

r_addend

This member specifies a constant addend used to compute the value to be stored intothe relocatable field.

As shown above, only Elf32_Rela entries contain an explicit addend. Entries oftype Elf32_Rel store an implicit addend in the location to be modified. SPARCuses Elf32_Rela entries and x86 uses Elf32_Rel entries.

A relocation section references two other sections: a symbol table and a section tomodify. The section header’s sh_info and sh_link members, described in

178 Linker and Libraries Guide ♦ August 1997

“Sections” on page 155 earlier, specify these relationships. Relocation entries fordifferent object files have slightly different interpretations for the r_offset member.

� In relocatable files, r_offset holds a section offset. That is, the relocation sectionitself describes how to modify another section in the file; relocation offsetsdesignate a storage unit within the second section.

� In executable and shared object files, r_offset holds a virtual address. To makethese files’ relocation entries more useful for the runtime linker, the section offset(file interpretation) gives way to a virtual address (memory interpretation).

Although the interpretation of r_offset changes for different object files to allowefficient access by the relevant programs, the relocation types’ meanings stay thesame.

Relocation Types (Processor-Specific)On SPARC, relocation entries describe how to alter the following instruction anddata fields (bit numbers appear in the lower box corners):

Object Files 179

byte8

half16

word32

disp30

disp22

imm22

7 0

15 0

31 0

3129 0

0

0

31

31

21

21

simm13031 12

simm11031 10

simm10031 9

disp19031 19

disp14031 21 19

d213

simm7031 6

On x86, relocation entries describe how to alter the following instruction and datafields (bit numbers appear in the lower box corners):

31 0word32

word32 specifies a 32-bit field occupying 4 bytes with an arbitrary byte alignment.These values use the same byte order as other word values in the x86 architecture):

180 Linker and Libraries Guide ♦ August 1997

31 0

3 2 1 0 0x0102030401 02 03 04

Calculations below assume the actions are transforming a relocatable file into eitheran executable or a shared object file. Conceptually, the link-editor merges one ormore relocatable files to form the output. It first decides how to combine and locatethe input files, then updates the symbol values, and finally performs the relocation.Relocations applied to executable or shared object files are similar and accomplishthe same result. Descriptions below use the following notation:

A means the addend used to compute the value of therelocatable field.

B means the base address at which a shared object is loadedinto memory during execution. Generally, a shared objectfile is built with a 0 base virtual address, but theexecution address is different. See “Program Header” onpage 195 for more information about the base address.

G means the offset into the global offset table at which theaddress of the relocation entry’s symbol resides duringexecution. See “Global Offset Table (Processor-Specific)”on page 218 for more information.

GOT means the address of the global offset table. See “GlobalOffset Table (Processor-Specific)” on page 218 for moreinformation.

L means the place (section offset or address) of the procedurelinkage table entry for a symbol. A procedure linkage tableentry redirects a function call to the proper destination.The link-editor builds the initial procedure linkage table,and the runtime linker modifies the entries duringexecution. See “Procedure Linkage Table(Processor-Specific)” on page 219 for more information.

P means the place (section offset or address) of the storageunit being relocated (computed using r_offset ).

S means the value of the symbol whose index resides in therelocation entry.

SPARC relocation entries apply to bytes (byte8), half-words (half16), or words (theothers). x86 relocation entries apply to words. In any case, the r_offset valuedesignates the offset or virtual address of the first byte of the affected storage unit.The relocation type specifies which bits to change and how to calculate their values.

Object Files 181

SPARC uses only Elf32_Rela relocation entries with explicit addends. Thus ther_addend member serves as the relocation addend. x86 uses only Elf32_Relrelocation entries, the field to be relocated holds the addend. In all cases the addendand the computed result use the same byte order.

SPARC: Relocation Types

Note - Field names in the following table tell whether the relocation type checks foroverflow . A calculated relocation value may be larger than the intended field, anda relocation type may verify (V) the value fits or truncate (T) the result. As anexample, V-simm13 means that the computed value may not have significant,nonzero bits outside the simm13 field.

TABLE 7–20 SPARC: Relocation Types

Name Value Field Calculation

R_SPARC_NONE 0 None None

R_SPARC_8 1 V-byte8 S + A

R_SPARC_16 2 V-half16 S + A

R_SPARC_32 3 V-word32 S + A

R_SPARC_DISP8 4 V-byte8 S + A - P

R_SPARC_DISP16 5 V-half16 S + A - P

R_SPARC_DISP32 6 V-disp32 S + A - P

R_SPARC_WDISP30 7 V-disp30 (S + A - P) >> 2

R_SPARC_WDISP22 8 V-disp22 (S + A - P) >> 2

R_SPARC_HI22 9 T-imm22 (S + A) >> 10

R_SPARC_22 10 V-imm22 S + A

R_SPARC_13 11 V-simm13 S + A

182 Linker and Libraries Guide ♦ August 1997

TABLE 7–20 SPARC: Relocation Types (continued)

Name Value Field Calculation

R_SPARC_LO10 12 T-simm13 (S + A) & 0x3ff

R_SPARC_GOT10 13 T-simm13 G & 0x3ff

R_SPARC_GOT13 14 V-simm13 G

R_SPARC_GOT22 15 T-simm22 G >> 10

R_SPARC_PC10 16 T-simm13 (S + A - P) & 0x3ff

R_SPARC_PC22 17 V-disp22 (S + A - P) >> 10

R_SPARC_WPLT30 18 V-disp30 (L + A - P) >> 2

R_SPARC_COPY 19 None None

R_SPARC_GLOB_DAT 20 V-word32 S + A

R_SPARC_JMP_SLOT 21 None See R_SPARC_JMP_SLOT,

R_SPARC_RELATIVE 22 V-word32 B + A

R_SPARC_UA32 23 V-word32 S + A

R_SPARC_PLT32 24 V-word32 L + A

R_SPARC_HIPLT22 25 T-imm22 (L + A) >> 10

R_SPARC_LOPLT10 26 T-simm13 (L + A) & 0x3ff

R_SPARC_PCPLT32 27 V-word32 L + A - P

R_SPARC_PCPLT22 28 V-disp22 (L + A - P) >> 10

R_SPARC_PCPLT10 29 V-simm12 (L + A - P) & 0x3ff

R_SPARC_10 30 V_simm10 S + A

Object Files 183

TABLE 7–20 SPARC: Relocation Types (continued)

Name Value Field Calculation

R_SPARC_11 31 V_simm11 S + A

R_SPARC_WDISP16 40 V-d2/disp14 (S + A - P) >> 2

R_SPARC_WDISP19 41 V-disp19 (S + A - P) >> 2

R_SPARC_7 43 V-imm7 S + A

R_SPARC_5 44 V-imm5 S + A

R_SPARC_6 45 V-imm6 S + A

Some relocation types have semantics beyond simple calculation:

R_SPARC_GOT10

This relocation type resembles R_SPARC_LO10, except it refers to the address of thesymbol’s global offset table entry and additionally instructs the link-editor to build aglobal offset table.

R_SPARC_GOT13

This relocation type resembles R_SPARC_13, except it refers to the address of thesymbol’s global offset table entry and additionally instructs the link-editor to build aglobal offset table.

R_SPARC_GOT22

This relocation type resembles R_SPARC_22, except it refers to the address of thesymbol’s global offset table entry and additionally instructs the link-editor to build aglobal offset table.

R_SPARC_WPLT30

This relocation type resembles R_SPARC_WDISP30, except it refers to the address ofthe symbol’s procedure linkage table entry and additionally instructs the link-editorto build a procedure linkage table.

184 Linker and Libraries Guide ♦ August 1997

R_SPARC_COPY

The link-editor creates this relocation type for dynamic linking. Its offset memberrefers to a location in a writable segment. The symbol table index specifies a symbolthat should exist both in the current object file and in a shared object. Duringexecution, the runtime linker copies data associated with the shared object’s symbolto the location specified by the offset. See “Copy Relocations” on page 91 for moredetails.

R_SPARC_GLOB_DAT

This relocation type resembles R_SPARC_32, except it sets a global offset table entryto the address of the specified symbol. The special relocation type allows you todetermine the correspondence between symbols and global offset table entries.

R_SPARC_JMP_SLOT

The link-editor creates this relocation type for dynamic linking. Its offset membergives the location of a procedure linkage table entry. The runtime linker modifies theprocedure linkage table entry to transfer control to the designated symbol address.

R_SPARC_RELATIVE

The link-editor creates this relocation type for dynamic linking. Its offset membergives the location within a shared object that contains a value representing a relativeaddress. The runtime linker computes the corresponding virtual address by addingthe virtual address at which the shared object is loaded to the relative address.Relocation entries for this type must specify 0 for the symbol table index.

R_SPARC_UA32

This relocation type resembles R_SPARC_32, except it refers to an unaligned word.That is, the word to be relocated must be treated as four separate bytes with arbitraryalignment, not as a word aligned according to the architecture requirements.

x86: Relocation Types

Object Files 185

TABLE 7–21 x86: Relocation Types

Name Value Field Calculation

R_386_NONE 0 none none

R_386_32 1 word32 S + A

R_386_PC32 2 word32 S + A - P

R_386_GOT32 3 word32 G + A

R_386_PLT32 4 word32 L + A - P

R_386_COPY 5 none none

R_386_GLOB_DAT 6 word32 S

R_386_JMP_SLOT 7 word32 S

R_386_RELATIVE 8 word32 B + A

R_386_GOTOFF 9 word32 S + A - GOT

R_386_GOTPC 10 word32 GOT + A - P

R_386_32PLT 11 word32 L + A

Some relocation types have semantics beyond simple calculation:

R_386_GOT32

This relocation type computes the distance from the base of the global offset table tothe symbol’s global offset table entry. It also tells the link-editor to build a globaloffset table.

R_386_PLT32

This relocation type computes the address of the symbol’s procedure linkage tableentry and tells the link-editor to build a procedure linkage table.

186 Linker and Libraries Guide ♦ August 1997

R_386_COPY

The link-editor creates this relocation type for dynamic linking. Its offset memberrefers to a location in a writable segment. The symbol table index specifies a symbolthat should exist both in the current object file and in a shared object. Duringexecution, the runtime linker copies data associated with the shared object’s symbolto the location specified by the offset. See “Copy Relocations” on page 91.

R_386_GLOB_DAT

This relocation type is used to set a global offset table entry to the address of thespecified symbol. The special relocation type lets one determine the correspondencebetween symbols and global offset table entries.

R_386_JMP_SLOT

The link-editor creates this relocation type for dynamic linking. Its offset membergives the location of a procedure linkage table entry. The runtime linker modifies theprocedure linkage table entry to transfer control to the designated symbol address.

R_386_RELATIVE

The link-editor creates this relocation type for dynamic linking. Its offset membergives the location within a shared object that contains a value representing a relativeaddress. The runtime linker computes the corresponding virtual address by addingthe virtual address at which the shared object is loaded to the relative address.Relocation entries for this type must specify 0 for the symbol table index.

R_386_GOTOFF

This relocation type computes the difference between a symbol’s value and theaddress of the global offset table. It also tells the link-editor to build the global offsettable.

R_386_GOTPC

This relocation type resembles R_386_PC32, except it uses the address of the globaloffset table in its calculation. The symbol referenced in this relocation normally is_GLOBAL_OFFSET_TABLE_, which also tells the link-editor to build the global offsettable.

Versioning InformationObjects created by the link-editor may contain two types of versioning information:

Object Files 187

� version definitions provide associations of global symbols and are implementedusing sections of type SHT_SUNW_verdef and SHT_SUNW_versym.

� version dependencies indicate the version definition requirements from other objectdependencies and are implemented using sections of type SHT_SUNW_verneed.

The structures that form these sections are defined in sys/link.h . Sections thatcontain versioning information are named .SUNW_version .

Version Definition SectionThis section is defined by the type SHT_SUNW_verdef. If this section exists aSHT_SUNW_versymsection must also exist. Using these two structures an associationof symbols to version definitions is maintained within the file (see “Creating aVersion Definition” on page 99 for more details). Elements of this section have thefollowing structure:

typedef struct {Elf32_Half vd_version;Elf32_Half vd_flags;Elf32_Half vd_ndx;Elf32_Half vd_cnt;Elf32_Word vd_hash;Elf32_Word vd_aux;Elf32_Word vd_next;

} Elf32_Verdef;

typedef struct {Elf32_Word vda_name;Elf32_Word vda_next;

} Elf32_Verdaux;

vd_version

This member identifies the version of the structure itself.

TABLE 7–22 Version Definition Structure Versions

Name Value Meaning

VER_DEF_NONE 0 Invalid version

VER_DEF_CURRENT >=1 Current version

188 Linker and Libraries Guide ♦ August 1997

The value 1 signifies the original section format; extensions will create new versionswith higher numbers. The value of VER_DEF_CURRENTchanges as necessary toreflect the current version number.

vd_flags

This member holds version definition specific information.

TABLE 7–23 Version Definition Section Flags

Name Value Meaning

VER_FLG_BASE 0x1 Version definition of the file itself

VER_FLG_WEAK 0x2 Weak version identifier

The base version definition is always present when version definitions, or symbolauto-reduction has been applied to the file. The base version provides a defaultversion for the files reserved symbols (see “Generating the Output Image” on page37). A weak version definition has no symbols associated with it (see “Creating aWeak Version Definition” on page 102 for more details).

vd_ndx

This member holds the version index. Each version definition has a unique index thatis used to associate SHT_SUNW_versymentries to the appropriate version definition.

vd_cnt

This member indicates the number of elements in the Elf32_Verdaux array.

vd_hash

This member holds the hash value of the version definition name (this value isgenerated using the same hashing function described in “Hash Table” on page 223).

vd_aux

This member holds the byte offset, from the start of this Elf32_Verdef entry, to theElf32_Verdaux array of version definition names. The first element of the arraymust exist and points to the version definition string this structure defines. Additionalelements may be present, the number being indicated by the vd_cnt value. These

Object Files 189

elements represent the dependencies of this version definition. Each of thesedependencies will have its own version definition structure.

vd_next

This member holds the byte offset, from the start of this Elf32_Verdef structure, tothe next Elf32_Verdef entry.

vda_name

This member holds a string table offset to a null-terminated string, giving the nameof the version definition.

vda_next

This member holds the byte offset, from the start of this Elf32_Verdaux entry, tothe next Elf32_Verdaux entry.

Version Symbol SectionThis section is defined by the type SHT_SUNW_versym, and consists of an array ofelements having the following structure:

typedef Elf32_Half Elf32_Versym;

The number of elements of the array must equal the number of symbol table entriescontained in the associated symbol table (determined by the sections sh_link value).Each element of the array contains a single index that may have the following values:

TABLE 7–24 Version Dependency Indexes

Name Value Meaning

VER_NDX_LOCAL 0 Symbol has local scope

VER_NDX_GLOBAL 1 Symbol has global scope (assigned to baseversion definition)

>1 Symbol has global scope (assigned touser-defined version definition)

Any index values greater than VER_NDX_GLOBALmust correspond to the vd_ndxvalue of an entry in the SHT_SUNW_verdef section. If no index values greater thanVER_NDX_GLOBALexist then no SHT_SUNW_verdef section need be present.

190 Linker and Libraries Guide ♦ August 1997

Version Dependency SectionThis section is defined by the type SHT_SUNW_verneed. This section complimentsthe dynamic dependency requirements of the file by indicating the versiondefinitions required from these dependencies. Only if a dependency contains versiondefinitions will a recording be made in this section. Elements of this section have thefollowing structure:

typedef struct {Elf32_Half vn_version;Elf32_Half vn_cnt;Elf32_Word vn_file;Elf32_Word vn_aux;Elf32_Word vn_next;

} Elf32_Verneed;

typedef struct {Elf32_Word vna_hash;Elf32_Half vna_flags;Elf32_Half vna_other;Elf32_Word vna_name;Elf32_Word vna_next;

} Elf32_Vernaux;

vn_version

This member identifies the version of the structure itself.

TABLE 7–25 Version Dependency Structure Versions

Name Value Meaning

VER_NEED_NONE 0 Invalid version

VER_NEED_CURRENT >=1 Current version

The value 1 signifies the original section format; extensions will create new versionswith higher numbers. The value of VER_NEED_CURRENTchanges as necessary toreflect the current version number.

vn_cnt

This member indicates the number of elements in the Elf32_Vernaux array.

Object Files 191

vn_file

This member holds a string table offset to a null-terminated string, giving thefilename having a version dependency. This name will match one of the .dynamicdependencies (refer to “Dynamic Section” on page 209) found in the file.

vn_aux

This member holds the byte offset, from the start of this Elf32_Verneed entry, tothe Elf32_Vernaux array of version definitions required from the associated filedependency. There must exist at least one version dependency. Additional versiondependencies may be present, the number being indicated by the vn_cnt value.

vn_next

This member holds the byte offset, from the start of this Elf32_Verneed entry, tothe next Elf32_Verneed entry.

vna_hash

This member holds the hash value of the version dependency name (this value isgenerated using the same hashing function described in “Hash Table” on page 223).

vna_flags

This member holds version dependency specific information.

TABLE 7–26 Version Dependency Structure Flags

Name Value Meaning

VER_FLG_WEAK 0x2 Weak version identifier

A weak version dependency indicates an original binding to aweak version definition.See “Creating a Version Definition” on page 99 for more details.

vna_other

This member is presently unused.

192 Linker and Libraries Guide ♦ August 1997

vna_name

This member holds a string table offset to a null-terminated string, giving the nameof the version dependency.

vna_next

This member holds the byte offset, from the start of this Elf32_Vernaux entry, tothe next Elf32_Vernaux entry.

Note SectionSometimes a vendor or system builder needs to mark an object file with specialinformation that other programs will check for conformance, compatibility, and soforth. Sections of type SHT_NOTEand program header elements of type PT_NOTEcan be used for this purpose.

The note information in sections and program header elements holds any number ofentries, each of which is an array of 4-byte words in the format of the targetprocessor. Labels are shown on Figure 5-7 to help explain note informationorganization, but they are not part of the specification.

namesz

descsz

type

name . . .

desc . . .

Figure 7–5 Note Information

namesz and name

The first namesz bytes in name contain a null-terminated character representation ofthe entry’s owner or originator. There is no formal mechanism for avoiding nameconflicts. By convention, vendors use their own name, such as “XYZ ComputerCompany,” as the identifier. If no name is present, namesz contains 0. Padding ispresent, if necessary, to ensure 4-byte alignment for the descriptor. Such padding isnot included in namesz .

Object Files 193

descsz and desc

The first descsz bytes in desc hold the note descriptor. If no descriptor is present,descsz contains 0. Padding is present, if necessary, to ensure 4-byte alignment forthe next note entry. Such padding is not included in descsz .

type

This word gives the interpretation of the descriptor. Each originator controls its owntypes; multiple interpretations of a single type value may exist. Thus, a programmust recognize both the name and the type to understand a descriptor. Typescurrently must be nonnegative.

To illustrate, the following note segment holds two entries.

X Y Z

\0 padC o

7

0

1

7

8

3

X

C

Y Z

\0o pad

word0

word1

namesz

descsz

type

namesz

descsz

type

name

desc

No descriptor

+0 +1 +2 +3

name

Figure 7–6 Example Note Segment

Note - The system reserves note information with no name (namesz==0 ) and with azero-length name (name[0]==’\0’ ) but currently defines no types. All other namesmust have at least one non-null character.

194 Linker and Libraries Guide ♦ August 1997

Dynamic LinkingThis section describes the object file information and system actions that createrunning programs. Some information here applies to all systems; information specificto one processor resides in sections marked accordingly.

Executable and shared object files statically represent programs. To execute suchprograms, the system uses the files to create dynamic program representations, orprocess images. A process image has segments that contain its text, data, stack, andso on. The major subsections of this section are:

� “Program Header” on page 195 describes object file structures that are directlyinvolved in program execution. The primary data structure, a program headertable, locates segment images in the file and contains other information needed tocreate the memory image of the program.

� “Program Loading (Processor-Specific)” on page 201 describes the informationused to load a program into memory.

� “Runtime Linker” on page 208 describes the information used to specify andresolve symbolic references among the object files of the process image.

Program HeaderAn executable or shared object file’s program header table is an array of structures,each describing a segment or other information the system needs to prepare theprogram for execution. An object file segment contains one or more sections, asdescribed in “Segment Contents” on page 200.

Program headers are meaningful only for executable and shared object files. A filespecifies its own program header size with the ELF header’s e_phentsize ande_phnum members. See “ELF Header” on page 148 for more information.

A program header has the following structure (defined in sys/elf.h ):

typedef struct {Elf32_Word p_type;Elf32_Off p_offset;Elf32_Addr p_vaddr;Elf32_Addr p_paddr;Elf32_Word p_filesz;Elf32_Word p_memsz;Elf32_Word p_flags;Elf32_Word p_align;

} Elf32_Phdr;

Object Files 195

p_type

This member tells what kind of segment this array element describes or how tointerpret the array element’s information. Type values and their meanings arespecified in Table 7–27.

p_offset

This member gives the offset from the beginning of the file at which the first byte ofthe segment resides.

p_vaddr

This member gives the virtual address at which the first byte of the segment residesin memory.

p_paddr

On systems for which physical addressing is relevant, this member is reserved for thesegment’s physical address. Because the system ignores physical addressing forapplication programs, this member has unspecified contents for executable files andshared objects.

p_filesz

This member gives the number of bytes in the file image of the segment; it may bezero.

p_memsz

This member gives the number of bytes in the memory image of the segment; it maybe zero.

p_flags

This member gives flags relevant to the segment. Defined flag values appear below.

p_align

As “Program Loading (Processor-Specific)” on page 201 describes, loadable processsegments must have congruent values for p_vaddr and p_offset , modulo the pagesize. This member gives the value to which the segments are aligned in memory andin the file. Values 0 and 1 mean no alignment is required. Otherwise, p_alignshould be a positive, integral power of 2, and p_vaddr should equal p_offset ,modulo p_align .

196 Linker and Libraries Guide ♦ August 1997

Some entries describe process segments; others give supplementary information anddo not contribute to the process image. Segment entries may appear in any order,except as explicitly noted below. Defined type values follow; other values arereserved for future use.

TABLE 7–27 Segment Types, p_type

Name Value

PT_NULL 0

PT_LOAD 1

PT_DYNAMIC 2

PT_INTERP 3

PT_NOTE 4

PT_SHLIB 5

PT_PHDR 6

PT_LOPROC 0x70000000

PT_HIPROC 0x7fffffff

PT_NULL

The array element is unused; other members’ values are undefined. This type lets theprogram header table contain ignored entries.

PT_LOAD

The array element specifies a loadable segment, described by p_filesz andp_memsz. The bytes from the file are mapped to the beginning of the memorysegment. If the segment’s memory size (p_memsz) is larger than the file size(p_filesz ), the extra bytes are defined to hold the value 0 and to follow thesegment’s initialized area. The file size may not be larger than the memory size.

Object Files 197

Loadable segment entries in the program header table appear in ascending order,sorted on the p_vaddr member.

PT_DYNAMIC

The array element specifies dynamic linking information. See “Dynamic Section” onpage 209 for more information.

PT_INTERP

The array element specifies the location and size of a null-terminated path name toinvoke as an interpreter. This segment type is meaningful only for executable files(though it may occur for shared objects); it may not occur more than once in a file. Ifit is present, it must precede any loadable segment entry. See “Program Interpreter”on page 207 for further information.

PT_NOTE

The array element specifies the location and size of auxiliary information. See “NoteSection” on page 193 for details.

PT_SHLIB

This segment type is reserved but has unspecified semantics.

PT_PHDR

The array element, if present, specifies the location and size of the program headertable itself, both in the file and in the memory image of the program. This segmenttype may not occur more than once in a file. Moreover, it may occur only if theprogram header table is part of the memory image of the program. If it is present, itmust precede any loadable segment entry. See “Program Interpreter” on page 207 forfurther information.

PT_LOPROC- PT_HIPROC

Values in this inclusive range are reserved for processor-specific semantics.

Note - Unless specifically required elsewhere, all program header segment types areoptional. That is, a file’s program header table may contain only those elementsrelevant to its contents.

198 Linker and Libraries Guide ♦ August 1997

Base AddressExecutable and shared object files have a base address, which is the lowest virtualaddress associated with the memory image of the program’s object file. One use ofthe base address is to relocate the memory image of the program during dynamiclinking.

An executable or shared object file’s base address is calculated during execution fromthree values: the memory load address, the maximum page size, and the lowestvirtual address of a program’s loadable segment. As “Program Loading(Processor-Specific)” on page 201 describes, the virtual addresses in the programheaders might not represent the actual virtual addresses of the program’s memoryimage.

To compute the base address, you determine the memory address associated with thelowest p_vaddr value for a PT_LOADsegment. You then obtain the base address bytruncating the memory address to the nearest multiple of the maximum page size.Depending on the kind of file being loaded into memory, the memory address mightor might not match the p_vaddr values.

Segment PermissionsA program to be loaded by the system must have at least one loadable segment(although this is not required by the file format). When the system creates loadablesegments’ memory images, it gives access permissions as specified in the p_flagsmember. All bits included in the PF_MASKPROCmask are reserved forprocessor-specific semantics.

TABLE 7–28 Segment Flag Bits, p_flags

Name Value Meaning

PF_X 0x1 Execute

PF_W 0x2 Write

PF_R 0x4 Read

PF_MASKPROC 0xf0000000 Unspecified

If a permission bit is 0, that type of access is denied. Actual memory permissionsdepend on the memory management unit, which may vary from one system toanother. Although all flag combinations are valid, the system may grant more access

Object Files 199

than requested. In no case, however, will a segment have write permission unless itis specified explicitly. The following figure shows both the exact flag interpretationand the allowable flag interpretation.

TABLE 7–29 Segment Permissions

Flags Value Exact Allowable

None 0 All access denied All access denied

PF_X 1 Execute only Read, execute

PF_W 2 Write only Read, write, execute

PF_W + PF_X 3 Write, execute Read, write, execute

PF_R 4 Read only Read, execute

PF_R + PF_X 5 Read, execute Read, execute

PF_R + PF_W 6 Read, write Read, write, execute

PF_R + PF_W + PF_X 7 Read, write, execute Read, write, execute

For example, typical text segments have read and execute, but not write permissions.Data segments normally have read, write, and execute permissions.

Segment ContentsAn object file segment comprises one or more sections, though this fact is transparentto the program header. Whether the file segment holds one or many sections also isimmaterial to program loading. Nonetheless, various data must be present forprogram execution, dynamic linking, and so on. The diagrams below illustratesegment contents in general terms. The order and membership of sections within asegment may vary; moreover, processor-specific constraints may alter the examplesbelow.

Text segments contain read-only instructions and data, in sections described earlier inthis chapter. Data segments contain writable data and instructions. See Table 7–14 fora list of all special sections. Use dump(1) to see which sections are in a particularexecutable file.

200 Linker and Libraries Guide ♦ August 1997

A PT_DYNAMICprogram header element points at the .dynamic section, asexplained in “Dynamic Section” on page 209 later. The .got and .plt sections alsohold information related to position-independent code and dynamic linking.

The .plt may reside in a text or a data segment, depending on the processor. See“Global Offset Table (Processor-Specific)” on page 218 and “Procedure Linkage Table(Processor-Specific)” on page 219 for details.

As previously described on Table 7–10, the .bss section has the type SHT_NOBITS.Although it occupies no space in the file, it contributes to the segment’s memoryimage. Normally, these uninitialized data reside at the end of the segment, therebymaking p_memsz larger than p_filesz in the associated program header element.

Program Loading (Processor-Specific)As the system creates or augments a process image, it logically copies a file’ssegment to a virtual memory segment. When, and if, the system physically reads thefile depends on the program’s execution behavior, system load, and so forth.

A process does not require a physical page unless it references the logical pageduring execution, and processes commonly leave many pages unreferenced.Therefore delaying physical reads frequently obviates them, improving systemperformance. To obtain this efficiency in practice, executable and shared object filesmust have segment images whose file offsets and virtual addresses are congruent,modulo the page size.

Virtual addresses and file offsets for SPARC segments are congruent modulo 64K(0x10000). Virtual addresses and file offsets for x86 segments are congruent modulo4K (0x1000). By aligning segments to the maximum page size, the files are suitablefor paging regardless of physical page size.

The following example presents the SPARC version.

Object Files 201

File Virtual addressFile of fset

ELF header 0

Program header

Other information

0x100 T ext segment 0x10100

. . .

0x2be00 bytes 0x3beff

0x2bf00 Data segment 0x4bf00

. . .

0x4e00 bytes 0x50cff

0x30d00 Other information

. . .

Figure 7–7 SPARC: Executable File (64 K alignment)

TABLE 7–30 SPARC: Program Header Segments (64 K alignment)

Member Text Data

p_type PT_LOAD PT_LOAD

p_offset 0x100 0x2bf00

p_vaddr 0x10100 0x4bf00

p_paddr Unspecified Unspecified

p_filesize 0x2be00 0x4e00

p_memsz 0x2be00 0x5e24

p_flags PF_R + PF_X PF_R + PF_W + PF_X

p_align 0x10000 0x10000

The following example presents the x86 version.

202 Linker and Libraries Guide ♦ August 1997

File Virtual address File of fset

ELF header0

Program header

Other information

0x100 T ext segment 0x8048100

. . .

0x2be00 bytes 0x8073eff

0x2bf00 Data segment 0x8074f00

. . .

0x4e00 bytes 0x8079cff

0x30d00 Other information

. . .

Figure 7–8 x86: Executable File (4 K alignment)

TABLE 7–31 x86: Program Header Segments (4 K alignment)

Member Text Data

p_type PT_LOAD PT_LOAD

p_offset 0x100 0x2bf00

p_vaddr 0x8048100 0x8074f00

p_paddr Unspecified Unspecified

p_filesize 0x2be00 0x4e00

p_memsz 0x2be00 0x5e24

p_flags PF_R + PF_X PF_R + PF_W + PF_X

p_align 0x1000 0x1000

Object Files 203

Although the example’s file offsets and virtual addresses are congruent modulo themaximum page size for both text and data, up to four file pages hold impure text ordata (depending on page size and file system block size).

� The first text page contains the ELF header, the program header table, and otherinformation.

� The last text page holds a copy of the beginning of data.

� The first data page has a copy of the end of text.

� The last data page may contain file information not relevant to the runningprocess. Logically, the system enforces the memory permissions as if each segmentis complete and separate; segments’ addresses are adjusted to ensure each logicalpage in the address space has a single set of permissions. In the examples above,the region of the file holding the end of text and the beginning of data will bemapped twice: at one virtual address for text and at a different virtual address fordata.

The end of the data segment requires special handling for uninitialized data, whichthe system defines to begin with zero values. Thus, if a file’s last data page includesinformation not in the logical memory page, the extraneous data must be set to zero,not the unknown contents of the executable file.

Impurities in the other three pages are not logically part of the process image;whether the system expunges them is unspecified. The memory image for thisprogram follows, assuming 4 Kilobyte (0x1000) pages. For simplicity, these examplesillustrates only one page size.

204 Linker and Libraries Guide ♦ August 1997

Contents SegmentVirtual Address

Header Padding 0x10000

0x100 bytes

0x10100 T ext segment

Text . . .

0x2be00 bytes

0x3bf00

Data segment

. . .

0x4e00 bytes

Data

0x4b000

Data Padding0x100 bytes

Text Padding0x100 bytes

0x4bf00

0x50d00 Uninitialized Data

0x1024 zero bytes

0x51d24 Page Padding

0x2dc zer o bytes

Figure 7–9 SPARC: Process Image Segments

Object Files 205

Contents SegmentVirtual Address

Header Padding 0x10000

0x100 bytes

0x10100 T ext segment

Text . . .

0x2be00 bytes

0x3bf00

Data segment

. . .

0x4e00 bytes

Data

0x4b000

Data Padding0x100 bytes

Text Padding0x100 bytes

0x4bf00

0x50d00 Uninitialized Data

0x1024 zero bytes

0x51d24 Page Padding

0x2dc zer o bytes

Figure 7–10 x86: Process Image Segments

One aspect of segment loading differs between executable files and shared objects.Executable file segments typically contain absolute code. For the process to executecorrectly, the segments must reside at the virtual addresses used to build theexecutable file. Thus the system uses the p_vaddr values unchanged as virtualaddresses.

On the other hand, shared object segments typically contain position-independentcode. (For background, see Chapter 2.) This lets a segment’s virtual address changefrom one process to another, without invalidating execution behavior.

Though the system chooses virtual addresses for individual processes, it maintainsthe segments’ relative positions. Because position-independent code uses relativeaddressing between segments, the difference between virtual addresses in memorymust match the difference between virtual addresses in the file.

206 Linker and Libraries Guide ♦ August 1997

The following tables show possible shared object virtual address assignments forseveral processes, illustrating constant relative positioning. The table also illustratesthe base address computations.

TABLE 7–32 SPARC: Example Shared Object Segment Addresses

Source Text Data Base Address

File 0x200 0x2a400 0x0

Process 1 0xc0000200 0xc002a400 0xc0000000

Process 2 0xc0010200 0xc003c400 0xc0010000

Process 3 0xd0020200 0xd004a400 0xd0020000

Process 4 0xd0030200 0xd005a400 0xd0030000

TABLE 7–33 x86: Example Shared Object Segment Addresses

Source Text Data Base Address

File 0x200 0x2a400 0x0

Process 1 0x80000200 0x8002a400 0x80000000

Process 2 0x80081200 0x800ab400 0x80081000

Process 3 0x900c0200 0x900ea400 0x900c0000

Process 4 0x900c6200 0x900f0400 0x900c6000

Program InterpreterAn executable file may have one PT_INTERP program header element. Duringexec (2), the system retrieves a path name from the PT_INTERP segment and createsthe initial process image from the interpreter file’s segments. That is, instead of using

Object Files 207

segment images of the original executable files, the system composes a memoryimage for the interpreter. It then is the interpreter’s responsibility to receive controlfrom the system and provide an environment for the application program.

The interpreter receives control in one of two ways. First, it may receive a filedescriptor to read the executable file, positioned at the beginning. It can use this filedescriptor to read and/or map the executable file’s segments into memory. Second,depending on the executable file format, the system may load the executable file intomemory instead of giving the interpreter an open file descriptor.

With the possible exception of the file descriptor, the interpreter’s initial process statematches what the executable file has received. The interpreter itself may not require asecond interpreter. An interpreter may be either a shared object or an executable file.

� A shared object (the normal case) is loaded as position-independent, withaddresses that may vary from one process to another; the system creates itssegments in the dynamic segment area used by mmap(2) and related services.Consequently, a shared object interpreter typically will not conflict with theoriginal executable file’s original segment addresses.

� An executable file is loaded at fixed addresses; the system creates its segmentsusing the virtual addresses from the program header table. Consequently, anexecutable file interpreter’s virtual addresses may collide with the first executablefile; the interpreter is responsible for resolving conflicts.

Runtime LinkerWhen building an executable file that uses dynamic linking, the link-editor adds aprogram header element of type PT_INTERP to an executable file, telling the systemto invoke the runtime linker as the program interpreter. exec (2) and the runtimelinker cooperate to create the process image for the program, which entails thefollowing actions:

� Adding the executable file’s memory segments to the process image.

� Adding shared object memory segments to the process image.

� Performing relocations for the executable file and its shared objects.

� Closing the file descriptor that was used to read the executable file, if one wasgiven to the runtime linker.

� Calling any .init section provided in the objects mapped. See “Initialization andTermination Functions” on page 224.

� Transferring control to the program, making it look as if the program had receivedcontrol directly from exec (2).

The link-editor also constructs various data that assist the runtime linker forexecutable and shared object files. As shown above in “Program Header,” these datareside in loadable segments, making them available during execution. (Once again,recall the exact segment contents are processor-specific.)

208 Linker and Libraries Guide ♦ August 1997

� A .dynamic section with type SHT_DYNAMICholds various data. The structureresiding at the beginning of the section holds the addresses of other dynamiclinking information.

� The .hash section with type SHT_HASHholds a symbol hash table.

� The .got and .plt sections with type SHT_PROGBITShold two separate tables:the global offset table and the procedure linkage table. Sections below explain howthe runtime linker uses and changes the tables to create memory images for objectfiles.

As explained in “Program Loading (Processor-Specific)” on page 201, shared objectsmay occupy virtual memory addresses that are different from the addresses recordedin the file’s program header table. The runtime linker relocates the memory image,updating absolute addresses before the application gains control. Although theabsolute address values will be correct if the library is loaded at the addressesspecified in the program header table, this normally is not the case.

If the process environment (see exec (2) contains a variable named LD_BIND_NOWwith a non-null value, the runtime linker processes all relocation before transferringcontrol to the program. For example, each of the environment entries:

LD_BIND_NOW=1 LD_BIND_NOW=on LD_BIND_NOW=off

specifies this behavior. The runtime linker can evaluate procedure linkage tableentries lazily, so avoiding resolution and relocation overhead for functions that arenot called. See “Procedure Linkage Table (Processor-Specific)” on page 219 for moreinformation.

Dynamic SectionIf an object file participates in dynamic linking, its program header table will have anelement of type PT_DYNAMIC. This segment contains the .dynamic section. Aspecial symbol, _DYNAMIC, labels the section, which contains an array of thefollowing structures (defined in sys/link.h ):

typedef struct {Elf32_Sword d_tag;union {

Elf32_Word d_val;Elf32_Addr d_ptr;Elf32_Off d_off;

} d_un;} Elf32_Dyn;

For each object with this type, d_tag controls the interpretation of d_un .

Object Files 209

d_val

These Elf32_Word objects represent integer values with various interpretations.

d_ptr

These Elf32_Addr objects represent program virtual addresses. As mentionedpreviously, a file’s virtual addresses might not match the memory virtual addressesduring execution. When interpreting addresses contained in the dynamic structure,the runtime linker computes actual addresses, based on the original file value and thememory base address. For consistency, files do not contain relocation entries to correctaddresses in the dynamic structure.

The following table summarizes the tag requirements for executable and sharedobject files. If a tag is marked mandatory, then the dynamic linking array must havean entry of that type. Likewise, optional means an entry for the tag may appear but isnot required.

TABLE 7–34 Dynamic Array Tags, d_tag

Name Value d_un Executable Shared Object

DT_NULL 0 Ignored Mandatory Mandatory

DT_NEEDED 1 d_val Optional Optional

DT_PLTRELSZ 2 d_val Optional Optional

DT_PLTGOT 3 d_ptr Optional Optional

DT_HASH 4 d_ptr Mandatory Mandatory

DT_STRTAB 5 d_ptr Mandatory Mandatory

DT_SYMTAB 6 d_ptr Mandatory Mandatory

DT_RELA 7 d_ptr Mandatory Optional

DT_RELASZ 8 d_val Mandatory Optional

DT_RELAENT 9 d_val Mandatory Optional

210 Linker and Libraries Guide ♦ August 1997

TABLE 7–34 Dynamic Array Tags, d_tag (continued)

Name Value d_un Executable Shared Object

DT_STRSZ 10 d_val Mandatory Mandatory

DT_SYMENT 11 d_val Mandatory Mandatory

DT_INIT 12 d_ptr Optional Optional

DT_FINI 13 d_ptr Optional Optional

DT_SONAME 14 d_val Ignored Optional

DT_RPATH 15 d_val Optional Ignored

DT_SYMBOLIC 16 Ignored Ignored Optional

DT_REL 17 d_ptr Mandatory Optional

DT_RELSZ 18 d_val Mandatory Optional

DT_RELENT 19 d_val Mandatory Optional

DT_PLTREL 20 d_val Optional Optional

DT_DEBUG 21 d_ptr Optional Ignored

DT_TEXTREL 22 Ignored Optional Optional

DT_JMPREL 23 d_ptr Optional Optional

DT_FLAGS_1 0x6ffffffb d_val Optional Optional

DT_VERDEF 0x6ffffffc d_ptr Optional Optional

DT_VERDEFNUM 0x6ffffffd d_val Optional Optional

DT_VERNEED 0x6ffffffe d_ptr Optional Optional

DT_VERNEEDNUM 0x6fffffff d_val Optional Optional

Object Files 211

TABLE 7–34 Dynamic Array Tags, d_tag (continued)

Name Value d_un Executable Shared Object

DT_AUXILIARY 0x7ffffffd d_val Unspecified Optional

DT_USED 0x7ffffffe d_val Optional Optional

DT_FILTER 0x7fffffff d_val Unspecified Optional

DT_LOPROC 0x70000000 Unspecified Unspecified Unspecified

DT_HIPROC 0x7fffffff Unspecified Unspecified Unspecified

DT_NULL

An entry with a DT_NULLtag marks the end of the _DYNAMICarray.

DT_NEEDED

This element holds the string table offset of a null-terminated string, giving the nameof a needed dependency. The offset is an index into the table recorded in theDT_STRTABentry. See “Shared Object Dependencies” on page 218 for moreinformation about these names. The dynamic array may contain multiple entries withthis type. These entries’ relative order is significant, though their relation to entries ofother types is not.

DT_PLTRELSZ

This element holds the total size, in bytes, of the relocation entries associated withthe procedure linkage table. If an entry of type DT_JMPRELis present, aDT_PLTRELSZmust accompany it.

DT_PLTGOT

This element holds an address associated with the procedure linkage table and/orthe global offset table.

DT_HASH

This element points to the symbol hash table, described in “Hash Table” on page 223.This hash table refers to the symbol table indicated by the DT_SYMTABelement.

212 Linker and Libraries Guide ♦ August 1997

DT_STRTAB

This element holds the address of the string table, described in the first part of thischapter. Symbol names, dependency names, and other strings required by theruntime linker reside in this table.

DT_SYMTAB

This element holds the address of the symbol table, described in the first part of thischapter, with Elf32_Sym entries for the 32-bit class of files.

DT_RELA

This element holds the address of a relocation table, described in the first part of thischapter. Entries in the table have explicit addends, such as Elf32_Rela for the32-bit file class.

An object file may have multiple relocation sections. When building the relocationtable for an executable or shared object file, the link-editor catenates those sections toform a single table. Although the sections remain independent in the object file, theruntime linker sees a single table. When the runtime linker creates the process imagefor an executable file or adds a shared object to the process image, it reads therelocation table and performs the associated actions.

If this element is present, the dynamic structure must also have DT_RELASZandDT_RELAENTelements. When relocation is mandatory for a file, either DT_RELAorDT_RELmay occur (both are permitted but not required).

DT_RELASZ

This element holds the total size, in bytes, of the DT_RELArelocation table.

DT_RELAENT

This element holds the size, in bytes, of the DT_RELArelocation entry.

DT_STRSZ

This element holds the size, in bytes, of the string table.

DT_SYMENT

This element holds the size, in bytes, of a symbol table entry.

Object Files 213

DT_INIT

This element holds the address of the initialization function, discussed in“Initialization and Termination Functions” on page 224 later.

DT_FINI

This element holds the address of the termination function, discussed in“Initialization and Termination Functions” on page 224 later.

DT_SONAME

This element holds the string table offset of a null-terminated string, giving the nameof the shared object. The offset is an index into the table recorded in the DT_STRTABentry. See “Shared Object Dependencies” on page 218 for more information aboutthese names.

DT_RPATH

This element holds the string table offset of a null-terminated search library searchpath string, discussed in “Shared Objects with Dependencies” on page 76. The offsetis an index into the table recorded in the DT_STRTABentry.

DT_SYMBOLIC

This element’s presence in a shared object library alters the runtime linker’s symbolresolution algorithm for references within the library. Instead of starting a symbolsearch with the executable file, the runtime linker starts from the shared object itself.If the shared object fails to supply the referenced symbol, the runtime linker thensearches the executable file and other shared objects as usual.

DT_REL

This element is similar to DT_RELA, except its table has implicit addends, such asElf32_Rel for the 32-bit file class. If this element is present, the dynamic structuremust also have DT_RELSZand DT_RELENTelements.

DT_RELSZ

This element holds the total size, in bytes, of the DT_RELrelocation table.

DT_RELENT

This element holds the size, in bytes, of the DT_RELrelocation entry.

214 Linker and Libraries Guide ♦ August 1997

DT_PLTREL

This member specifies the type of relocation entry to which the procedure linkagetable refers. The d_val member holds DT_RELor DT_RELA, as appropriate. Allrelocations in a procedure linkage table must use the same relocation.

DT_DEBUG

This member is used for debugging.

DT_TEXTREL

This member’s absence signifies that no relocation entry should cause a modificationto a non-writable segment, as specified by the segment permissions in the programheader table. If this member is present, one or more relocation entries might requestmodifications to a non-writable segment, and the runtime linker can prepareaccordingly.

DT_FLAGS_1

If present, this entry’s d_val member holds various state flags. See Table 7–35.

DT_JMPREL

If present, this entry’s d_ptr member holds the address of relocation entriesassociated solely with the procedure linkage table. Separating these relocation entrieslets the runtime linker ignore them during process initialization, if lazy binding isenabled. If this entry is present, the related entries of types DT_PLTRELSZandDT_PLTRELmust also be present.

DT_VERDEF

Holds the address of the version definition table, described in the first part of thischapter, with Elf32_Verdef entries for the 32-bit class of files. See section “VersionDefinition Section” on page 188for more information. Elements within these entriescontain indexes into the table recorded in the DT_STRTABentry.

DT_VERDEFNUM

This element specifies the number of entries in the version definition table.

DT_VERNEED

Holds the address of the version dependency table, described in the first part of thischapter, with Elf32_Verneed entries for the 32-bit class of files. See section

Object Files 215

“Version Dependency Section” on page 191 for more information. Elements withinthese entries contain indexes into the table recorded in the DT_STRTABentry.

DT_VERNEEDNUM

This element specifies the number of entries in the version dependency table.

DT_AUXILIARY

Holds the string table offset of a null-terminated string that names an object. Theoffset is an index into the table recorded in the DT_STRTABentry. Symbols in theauxiliary object will be used in preference to the symbols within this object.

DT_FILTER

Holds the string table offset of a null-terminated string that names an object. Theoffset is an index into the table recorded in the DT_STRTABentry. The symbol tableof this object acts as a filter for the symbol table of the named object.

DT_LOPROC- DT_HIPROC

Values in this inclusive range are reserved for processor-specific semantics.

The following dynamic state flags are presently available:

TABLE 7–35 Dynamic Tags, DT_FLAGS_1

Name Value Meaning

DF_1_NOW 0x1 Perform complete relocation processing.

DT_1_GLOBAL 0x2 Unused.

DT_1_GROUP 0x4 Indicate object is a member of a group.

DT_1_NODELETE 0x8 Object can not be deleted from a process.

DT_1_LOADFLTR 0x10 Insure immediate loading of filtee(s)..

DT_1_INITFIRST 0x20 Run objects’ initialization first.

DT_1_NOOPEN 0x40 Object can not be used with dlopen (3X).

216 Linker and Libraries Guide ♦ August 1997

TABLE 7–35 Dynamic Tags, DT_FLAGS_1 (continued)

DF_1_NOW

When the object is loaded all relocation processing is completed, see “WhenRelocations are Performed” on page 48. This state is recorded in the object using thelink-editors’ −z now option.

DF_1_GROUP

Indicates that the object is a member of a group, see “Symbol Lookup” on page 57.This state is recorded in the object using the link-editors’ −B group option.

DF_1_NODELETE

Indicates that the object can not be deleted from a process. Thus if the object isloaded in a process, either directly or as a dependency, with dlopen (3X), it can notbe unloaded with dlclose (3X). This state is recorded in the object using thelink-editors’ −z nodelete option.

DF_1_LOADFLTR

This state is only meaningful for filters (See “Shared Objects as Filters” on page 78).When the filter is loaded all associated filtees are immediately processed, see “FilteeProcessing” on page 83. This state is recorded in the object using the link-editors’ −zloadfltr option.

DF_1_INITFIRST

When the object is loaded its initialization section is run before any other objectsloaded with it, see “Initialization and Termination Routines” on page 52. Thisspecialized state is intended for libthread.so.1 . This state is recorded in theobject using the link-editors’ −z initfirst option.

DF_1_NOOPEN

Indicates that the object can not be added to a running process with dlopen (3X).This state is recorded in the object using the link-editors’ −z nodlopen option.

Except for the DT_NULLelement at the end of the dynamic array and the relativeorder of DT_NEEDEDelements, entries may appear in any order. Tag values notappearing in the table are reserved.

Object Files 217

Shared Object DependenciesWhen the runtime linker creates the memory segments for an object file, thedependencies (recorded in DT_NEEDEDentries of the dynamic structure) tell whatshared objects are needed to supply the program’s services. By repeatedly connectingreferenced shared objects and their dependencies, the runtime linker builds acomplete process image.

When resolving symbolic references, the runtime linker examines the symbol tableswith a breadth-first search. That is, it first looks at the symbol table of the executableprogram itself, then at the symbol tables of the DT_NEEDEDentries (in order), then atthe second level DT_NEEDEDentries, and so on.

Note - Even when a shared object is referenced multiple times in the dependencylist, the runtime linker will connect the object only once to the process.

Names in the dependency list are copies either of the DT_SONAMEstrings or the pathnames of the shared objects used to build the object file.

Global Offset Table (Processor-Specific)Position-independent code cannot, in general, contain absolute virtual addresses.Global offset tables hold absolute addresses in private data, thus making theaddresses available without compromising the position-independence andshareability of a program’s text. A program references its global offset table usingposition-independent addressing and extracts absolute values, thus redirectingposition-independent references to absolute locations.

Initially, the global offset table holds information as required by its relocation entries(see “Relocation” on page 177 for more information). After the system createsmemory segments for a loadable object file, the runtime linker processes therelocation entries, some of which will be type R_SPARC_GLOB_DAT(for SPARC), orR_386_GLOB_DAT(for x86) referring to the global offset table.

The runtime linker determines the associated symbol values, calculates their absoluteaddresses, and sets the appropriate memory table entries to the proper values.Although the absolute addresses are unknown when the link-editor builds an objectfile, the runtime linker knows the addresses of all memory segments and can thuscalculate the absolute addresses of the symbols contained therein.

If a program requires direct access to the absolute address of a symbol, that symbolwill have a global offset table entry. Because the executable file and shared objectshave separate global offset tables, a symbol’s address may appear in several tables.The runtime linker processes all the global offset table relocations before givingcontrol to any code in the process image, thus ensuring the absolute addresses areavailable during execution.

The table’s entry zero is reserved to hold the address of the dynamic structure,referenced with the symbol _DYNAMIC. This allows a program, such as the runtime

218 Linker and Libraries Guide ♦ August 1997

linker, to find its own dynamic structure without having yet processed its relocationentries. This is especially important for the runtime linker, because it must initializeitself without relying on other programs to relocate its memory image.

The system may choose different memory segment addresses for the same sharedobject in different programs; it may even choose different library addresses fordifferent executions of the same program. Nonetheless, memory segments do notchange addresses once the process image is established. As long as a process exists,its memory segments reside at fixed virtual addresses.

A global offset table’s format and interpretation are processor-specific. For SPARCand x86 processors, the symbol _GLOBAL_OFFSET_TABLE_may be used to accessthe table.

extern Elf32_Addr _GLOBAL_OFFSET_TABLE_[];

The symbol _GLOBAL_OFFSET_TABLE_may reside in the middle of the .gotsection, allowing both negative and nonnegative subscripts into the array ofaddresses.

Procedure Linkage Table (Processor-Specific)As the global offset table converts position-independent address calculations toabsolute locations, the procedure linkage table converts position-independentfunction calls to absolute locations. The link-editor cannot resolve execution transfers(such as function calls) from one executable or shared object to another. So, thelink-editor puts the program transfer control to entries in the procedure linkage table.

SPARC: Procedure Linkage Table

On SPARC architectures, procedure linkage tables reside in private data. The runtimelinker determines the destinations’ absolute addresses and modifies the procedurelinkage table’s memory image accordingly. The runtime linker thus redirects theentries without compromising the position-independence and shareability of theprogram’s text. Executable files and shared object files have separate procedurelinkage tables.

The first four procedure linkage table entries are reserved. (The original contents ofthese entries are unspecified, despite the example, below.) Each entry in the tableoccupies 3 words (12 bytes), and the last table entry is followed by a nop instruction.

A relocation table is associated with the procedure linkage table. The DT_JMP_RELentry in the _DYNAMICarray gives the location of the first relocation entry. Therelocation table has one entry, in the same sequence, for each procedure linkage tableentry. Except the first four entries, the relocation type is R_SPARC_JMP_SLOT, therelocation offset specifies the address of the first byte of the associated procedurelinkage table entry, and the symbol table index refers to the appropriate symbol.

Object Files 219

To illustrate procedure linkage tables, the figure below shows four entries: two of thefour initial reserved entries, the third is a call to name1, and the fourth is a call toname2. The example assumes the entry for name2 is the table’s last entry and showsthe following nop instruction. The left column shows the instructions from the objectfile before dynamic linking. The right column demonstrates a possible way theruntime linker might fix the procedure linkage table entries.

TABLE 7–36 SPARC: Procedure Linkage Table Example

Object File Memory Segment

.PLT0:unimpunimpunimp

.PLT1:unimpunimpunimp...

.PLT0:save %sp,-64,%spcall runtime-linkernop

.PLT1:.word identificationunimpunimp...

....PLT101:

sethi (.-.PLT0),%g1ba,a .PLT0nop

.PLT102:sethi (.-.PLT0),%g1ba,a .PLT0nop

....PLT101:

sethi (.-.PLT0),%g1sethi %hi(name1),%g1jmp1 %g1+%lo(name1),%g0

.PLT102:sethi (.-.PLT0),%g1sethi %hi(name2),%g1jmp1 %g1+%lo(name2),%g0

nop nop

Following the steps below, the runtime linker and program jointly resolve thesymbolic references through the procedure linkage table. Again, the steps describedbelow are for explanation only. The precise execution-time behavior of the runtimelinker is not specified.

1. When first creating the memory image of the program, the runtime linker changesthe initial procedure linkage table entries, making them transfer control to one ofthe runtime linker’s own routines. It also stores a word of identificationinformation in the second entry. When it receives control, it can examine thisword to find what object called it.

2. All other procedure linkage table entries initially transfer to the first entry, lettingthe runtime linker gain control at the first execution of each table entry. Forexample, the program calls name1, which transfers control to the label .PLT101 .

3. The sethi instruction computes the distance between the current and the initialprocedure linkage table entries, .PLT101 and .PLT0, respectively. This valueoccupies the most significant 22 bits of the %g1register. In this example, &g1contains 0x12f000 when the runtime linker receives control.

220 Linker and Libraries Guide ♦ August 1997

4. Next, the ba,a instruction jumps to .PLT0 , establishing a stack frame and callsthe runtime linker.

5. With the identification value, the runtime linker gets its data structures for theobject, including the relocation table.

6. By shifting the %g1value and dividing by the size of the procedure linkage tableentries, the runtime linker calculates the index of the relocation entry for name1.Relocation entry 101 has type R_SPARC_JMP_SLOT, its offset specifies the addressof .PLT101 , and its symbol table index refers to name1. Thus, the runtime linkergets the symbol’s real value, unwinds the stack, modifies the procedure linkagetable entry, and transfers control to the desired destination.

Although the runtime linker does not have to create the instruction sequences underthe Memory Segment column, it might. If it did, some points deserve more explanation.

� To make the code reentrant, the procedure linkage table’s instructions are changedin a particular sequence. If the runtime linker is fixing a function’s procedurelinkage table entry and a signal arrives, the signal handling code must be able tocall the original function with predictable (and correct) results.

� The runtime linker changes two words to convert an entry. It updates each wordautomatically. Reentrancy is achieved by first overwriting the nop with the jmp1instruction, and then patching the ba,a to be sethi . If a reentrant function callhappens between the two word updates, the jmp1 resides in the delay slot of theba,a instruction, and cancels the delay instruction. So, the runtime linker gainscontrol a second time. Although both invocations of the runtime linker modify thesame procedure linkage table entry, their changes do not interfere with each other.

� The first sethi instruction of a procedure linkage table entry can fill the delayslot of the previous entry’s jmp1 instruction. Although the sethi changes thevalue of the %g1register, the previous contents can be safely discarded.

� After conversion, the last procedure linkage table entry (.PLT102 above) needs adelay instruction for its jmp1 . The required, trailing nop fills this delay slot.

The LD_BIND_NOWenvironment variable changes dynamic linking behavior. If itsvalue is non-null, the runtime linker processes R_SPARC_JMP_SLOTrelocationentries (procedure linkage table entries) before transferring control to the program. IfLD_BIND_NOWis null, the runtime linker evaluates linkage table entries on the firstexecution of each table entry.

x86: Procedure Linkage TableOn x86 architectures, procedure linkage tables reside in shared text, but they useaddresses in the private global offset table. The runtime linker determines thedestinations’ absolute addresses and modifies the global offset table’s memory imageaccordingly. The runtime linker thus redirects the entries without compromising theposition-independence and shareability of the program’s text. Executable files andshared object files have separate procedure linkage tables.

Object Files 221

TABLE 7–37 x86: Procedure Linkage Table Example

.PLT0: pushl got_plus_4jmp *got_plus_8nop; nopnop; nop

.PLT1: jmp *name1_in_GOTpushl $offsetjmp .PLT0@PC

.PLT2: jmp *name2_in_GOTpushl $offsetjmp .PLT0@PC...

.PLT0: pushl 4(%ebx)jmp *8(%ebx)nop; nopnop; nop

.PLT1: jmp *name1@GOT(%ebx)pushl $offsetjmp .PLT0@PC

.PLT2: jmp *name2@GOT(%ebx)pushl $offsetjmp .PLT0@PC...

Following the steps below, the runtime linker and program cooperate to resolve thesymbolic references through the procedure linkage table and the global offset table.

1. When first creating the memory image of the program, the runtime linker sets thesecond and third entries in the global offset table to special values. Steps belowexplain these values.

2. If the procedure linkage table is position-independent, the address of the globaloffset table must be in %ebx. Each shared object file in the process image has itsown procedure linkage table, and control transfers to a procedure linkage tableentry only from within the same object file. So, the calling function must set theglobal offset table base register before it calls the procedure linkage table entry.

3. For example, the program calls name1, which transfers control to the label .PLT1 .

4. The first instruction jumps to the address in the global offset table entry forname1. Initially, the global offset table holds the address of the following pushlinstruction, not the real address of name1.

5. So, the program pushes a relocation offset (offset ) on the stack. The relocationoffset is a 32-bit, nonnegative byte offset into the relocation table. the designatedrelocation entry has the type R_386_JMP_SLOT, and its offset specifies the globaloffset table entry used in the previous jmp instruction. The relocation entry alsocontains a symbol table index, which the runtime linker uses to get the referencedsymbol, name1.

6. After pushing the relocation offset, the program jumps to .PLT0 , the first entry inthe procedure linkage table. The pushl instruction pushes the value of the second

222 Linker and Libraries Guide ♦ August 1997

global offset table entry (got_plus_4 or 4(%ebx) ) on the stack, giving theruntime linker one word of identifying information. The program then jumps tothe address in the third global offset table entry (got_plus_8 or 8(%ebx) ), tojump to the runtime linker.

7. The runtime linker unwinds the stack, checks the designated relocation entry, getsthe symbol’s value, stores the actual address of name1 in its global offset entrytable, and jumps to the destination.

8. Subsequent executions of the procedure linkage table entry transfer directly toname1, without calling the runtime linker again. This is because the jmpinstruction at .PLT1 jumps to name1 instead of falling through to the pushlinstruction.

The LD_BIND_NOWenvironment variable changes dynamic linking behavior. If itsvalue is non-null, the runtime linker processes R_386_JMP_SLOTrelocation entries(procedure linkage table entries) before transferring control to the program. IfLD_BIND_NOWis null, the runtime linker evaluates linkage table entries on the firstexecution of each table entry.

Hash TableA hash table of Elf32_Word objects supports symbol table access. The symbol tableto which the hashing is associated is specified in the sh_link entry of the hashtable’s section header (refer to Table 7–13). Labels appear below to help explain thehash table organization, but they are not part of the specification.

nbucket

nchain

bucket [0]

. . . bucket [nbucket - 1]

chain [0]

. . .

chain [nchain - 1]

Figure 7–11 Symbol Hash Table

The bucket array contains nbucket entries, and the chain array contains nchainentries; indexes start at 0. Both bucket and chain hold symbol table indexes. Chaintable entries parallel the symbol table. The number of symbol table entries shouldequal nchain ; so, symbol table indexes also select chain table entries.

Object Files 223

A hashing function accepts a symbol name and returns a value that may be used tocompute a bucket index. Consequently, if the hashing function returns the value xfor some name, bucket [x%nbucket ] gives an index y into both the symbol tableand the chain table. If the symbol table entry is not the one desired, chain [y] givesthe next symbol table entry with the same hash value.

One can follow the chain links until either the selected symbol table entry holds thedesired name or the chain entry contains the value STN_UNDEF.

unsigned longelf_Hash(const unsigned char *name){

unsigned long h = 0, g;

while (*name){

h = (h << 4) + *name++;if (g = h & 0xf0000000)

h ^= g >> 24;h &= ~g;

}return h;

}

Initialization and Termination FunctionsAfter the runtime linker has built the process image and performed the relocations,each shared object gets the opportunity to execute some initialization code.

Similarly, shared objects may have termination functions, which are executed withthe atexit (3C) mechanism after the base process begins its termination sequence.Refer to atexit (3C) for more information.

Shared objects designate their initialization and termination functions through theDT_INIT and DT_FINI entries in the dynamic structure, described in “DynamicSection” above. Typically, the code for these functions resides in the .init and.fini sections, mentioned in “Sections” on page 155 earlier.

Note - Although the atexit (3C) termination processing normally will be done, it isnot guaranteed to have executed upon process death. In particular, the process willnot execute the termination processing if it calls _exit( ) or if the process diesbecause it received a signal that it neither caught nor ignored.

224 Linker and Libraries Guide ♦ August 1997

CHAPTER 8

Mapfile Option

OverviewThe link-editor automatically and intelligently maps input sections from relocatableobjects to segments within the output file object. The −Moption with an associatedmapfile allows you to change the default mapping provided by the link-editor.

In particular, this mapfile option allows you to:

� Declare segments and specify values for segment attributes such as segment type,permissions, addresses, length, and alignment.

� Control mapping of input sections to segments by specifying the attribute valuesnecessary in a section to map to a specific segment (the attributes are sectionname, section type, and permissions) and by specifying which object file(s) theinput sections should be taken from, if necessary.

� Declare a global-absolute symbol that is assigned a value equal to the size of aspecified segment (by the link-editor) and that can be referenced from object files.

The mapfile option allows users of ifiles (an option previously available to thelink-editor that used command language directives) to convert to mapfiles . Allother facilities previously available for ifiles , other than those mentioned above,are not available with the mapfile option.

Note - When using the mapfile option, be aware that you can easily create a.outfiles that do not execute. The link-editor knows how to produce a correct a.outwithout the use of the mapfile option. The mapfile option is intended for systemprogramming use, not application programming use.

225

Using the Mapfile OptionTo use the mapfile option, you must:

� Enter the mapfile directives into a file, for example mapfile

� Supply the following option on the link-editor command line using −M mapfile .

If the mapfile is not in your current directory, include the full path name; nodefault search path exists.

Mapfile Structure and SyntaxYou can enter four basic types of directives into a mapfile :

� Segment declarations.

� Mapping directives.

� Size-symbol declarations.

� File control directives.

Each directive can span more than one line and can have any amount of white space(including new-lines) as long as it is followed by a semicolon. You can enter zero ormore directives in a mapfile . (Entering zero directives causes the link-editor toignore the mapfile and use its own defaults.)

Typically, segment declarations are followed by mapping directives, that is, youdeclare a segment and then define the criteria by which a section becomes part ofthat segment. If you enter a mapping directive or size-symbol declaration withoutfirst declaring the segment to which you are mapping (except for built-in segments,explained later), the segment is given default attributes as explained below. Suchsegment is then an “implicitly declared segment.”

Size-symbol declarations, and file control directives can appear anywhere in amapfile .

The following sections describe each directive type. For all syntax discussions, thefollowing notations apply:

� All entries in constant width, all colons, semicolons, equal signs, and at (@) signsare typed in literally.

� All entries in italics are substitutable.

� { ... }* means “zero or more.”

� { ... }+ means “one or more.”

226 Linker and Libraries Guide ♦ August 1997

� [ ... ]means “optional.”

� section_names and segment_names follow the same rules as C identifierswhere a period (.) is treated as a letter (for example, .bss is a legal name).

� section_names , segment_names , file_names , and symbol_names are casesensitive; everything else is not case sensitive.

� Spaces (or new-lines) may appear anywhere except before a number or in themiddle of a name or value.

� Comments beginning with # and ending at a new-line may appear anywhere thata space may appear.

Segment DeclarationsA segment declaration creates a new segment in the a.out or changes the attributevalues of an existing segment. (An existing segment is one that you previouslydefined or one of the three built-in segments described below.)

A segment declaration has the following syntax:

segment_name = {segment_attribute_value}*;

For each segment_name, you can specify any number of segment_attribute_values inany order, each separated by a space. (Only one attribute value is allowed for eachsegment attribute.) The segment attributes and their valid values are as follows:

TABLE 8–1 Mapfile Segment Attributes

Attribute Value

segment_type LOAD | NOTE

segment_flags ? [E] [N] [O] [R] [W] [X]

virtual_address Vnumber

physical_address Pnumber

length Lnumber

rounding Rnumber

alignment Anumber

Mapfile Option 227

TABLE 8–1 Mapfile Segment Attributes (continued)

There are three built-in segments with the following default attribute values:

� text (LOAD, ?RX, no virtual_address, physical_address, or length specified,alignment values set to defaults per CPU type)

� data (LOAD, ?RWX, no virtual_address, physical_address, or length specified,alignment values set to defaults per CPU type)

� note (NOTE)

The link-editor behaves as if these segments are declared before your mapfile isread in. See “Mapfile Option Defaults” on page 235 for more information.

Note the following when entering segment declarations:

� A number can be hexadecimal, decimal, or octal, following the same rules as inthe C language.

� No space is allowed between the V, P, L, R, or A and the number.

� The segment_type value can be either LOADor NOTE.

� The segment_type value defaults to LOAD.

� The segment_flags values are R for readable, Wfor writable, X for executable, andO for order. No spaces are allowed between the question mark (?) and theindividual flags that make up the segment_flags value.

� The segment_flags value for a LOADsegment defaults to RWX.

� NOTEsegments cannot be assigned any segment attribute value other than asegment_type.

� Implicitly declared segments default to segment_type value LOAD, segment_flagsvalue RWX, a default virtual_address, physical_address, and alignment value, andhave no length limit.

Note - the link-editor calculates the addresses and length of the current segmentbased on the previous segment’s attribute values. Also, even though implicitlydeclared segments default to “no length limit,” machine memory limitations stillapply.

� LOADsegments can have an explicitly specified virtual_address value and/orphysical_address value, as well as a maximum segment length value.

� If a segment has a segment_flags value of ? with nothing following, the valuedefaults to not readable, not writable, and not executable.

� The alignment value is used in calculating the virtual address of the beginning ofthe segment. This alignment only affects the segment for which it is specified;other segments still have the default alignment unless their alignments are alsochanged.

228 Linker and Libraries Guide ♦ August 1997

� If any of the virtual_address, physical_address, or length attribute values are notset, the link-editor calculates these values as it builds the a.out .

� If an alignment value is not specified for a segment, it is set to the built-in default.(The default differs from one CPU to another and may even differ between kernelversions. You should check the appropriate documentation for these numbers).

� If both a virtual_address and an alignment value are specified for a segment, thevirtual_address value takes priority.

� If a virtual_address value is specified for a segment, the alignment field in theprogram header contains the default alignment value.

� If the rounding value is set for a segment, that segments virtual address will berounded to the next address that conforms to the value given. This value onlyeffects the segments that it is specified for. If no value is given no rounding isperformed.

The ?E flag allows the creation of an empty segment, this is a segment that has nosections associated with it. This segment can only be specified for executables, andmust be of type LOADwith a specified size and alignment. Multiple segmentdefinitions of this type are permitted.

The ?N flag lets you control whether the ELF header, and any program headers, willbe included as part of the first loadable segment. By default, the ELF header andprogram headers are included with the first segment, as the information in theseheaders is used within the mapped image (commonly by the runtime linker). Theuse of the ?N option causes the virtual address calculations for the image to start atthe first section of the first segment.

The ?O flag lets you control the order of sections in the final relocatable object,executable file or shared object. This flag is intended for use in conjunction with the−xF option to the compiler(s). When a file is compiled with the −xF option, eachfunction in that file is placed in a separate section with the same attributes as the.text section. These sections are now called .text %function_name.

For example, a file containing three functions main( ) , foo() and bar( ) , whencompiled with the −xF option, will yield an object file with text for the threefunctions in sections called .text%main , .text%foo and .text%bar . Because the−xF option forces one function per section, the use of the ?O flag to control the orderof sections in effect controls the order of functions.

Consider the following user-defined mapfile :

text = LOAD ?RXO;text: .text%foo;text: .text%bar;text: .text%main;

If the order of function definitions in the source file is main , foo and bar , then thefinal executable will contain functions in the order foo , bar and main .

Mapfile Option 229

For static functions with the same name the file names must also be used. The ?Oflag forces the ordering of sections as requested in the mapfile . For example, if astatic function bar() exists in files a.o and b.o , and function bar( ) from file a.ois to be placed before function bar() from file b.o , then the mapfile entriesshould read:

text: .text%bar: a.o;text: .text%bar: b.o;

Although the syntax allows for the entry:

text: .text%bar: a.o b.o;

this entry does not guarantee that function bar() from file a.o will be placedbefore function bar() from file b.o . The second format is not recommended as theresults are not reliable.

Note - If a virtual_address value is specified, the segment is placed at that virtualaddress. For the system kernel this creates a correct result. For files that start viaexec (2), this method creates an incorrect a.out file because the segments do nothave correct offsets relative to their page boundaries.

Mapping DirectivesA mapping directive tells the link-editor how to map input sections to outputsegments. Basically, you name the segment that you are mapping to and indicatewhat the attributes of a section must be in order to map into the named segment.The set of section_attribute_values that a section must have to map into aspecific segment is called the “entrance criteria” for that segment. In order to beplaced in a specified segment of the a.out , a section must meet the entrance criteriafor a segment exactly.

A mapping directive has the following syntax:

segment_name : {section_attribute_value}* [: {file_name}+];

For a segment_name, you specify any number of section_attribute_values inany order, each separated by a space. (At most one section attribute value is allowedfor each section attribute.) You can also specify that the section must come from acertain .o file(s) via the file_name substitutable. The section attributes and their validvalues are as follows:

230 Linker and Libraries Guide ♦ August 1997

TABLE 8–2 Section Attributes

Section Attribute Value

section_name any valid section name

section_type $PROGBITS

$SYMTAB

$STRTAB

$REL

$RELA

$NOTE

$NOBITS

section_flags ? [[!]A] [[!]W] [[!]X]

Note the following when entering mapping directives:

� You must choose at most one section_type from the section_types listed above.The section_types listed above are built-in types. For more information onsection_types, see “Sections” on page 155.

� The section_flags values are A for allocatable, Wfor writable, or X for executable. Ifan individual flag is preceded by an exclamation mark (! ), the link-editor checksto make sure that the flag is not set. No spaces are allowed between the questionmark, exclamation mark(s), and the individual flags that make up the section_flagsvalue.

� file_name may be any legal file name and can be of the formarchive_name(component_name), for example,/usr/lib/usr/libc.a(printf.o) . A file name may be of the form*filename (see next bullet item). Note that the link-editor does not check thesyntax of file names.

� If a file_name is of the form *filename , the link-editor simulates a basename (1)on the file name from the command line and uses that to match against thespecified filename . In other words, the filename from the mapfile only needsto match the last part of the file name from the command line. (See “MappingExample” on page 233.)

� If you use the −l option during a link-edit, and the library after the −l option is inthe current directory, you must precede the library with ./ (or the entire pathname) in the mapfile in order to create a match.

Mapfile Option 231

� More than one directive line may appear for a particular output segment, forexample, the following set of directives is legal:

S1 : $PROGBITS;S1 : $NOBITS;

Entering more than one mapping directive line for a segment is the only way tospecify multiple values of a section attribute.

� A section can match more than one entrance criteria. In this case, the first segmentencountered in the mapfile with that entrance criteria is used, for example, if amapfile reads:

S1 : $PROGBITS;S2 : $PROGBITS;

the $PROGBITSsections are mapped to segment S1.

Section-within-Segment OrderingBy using the following notation it is possible to specify the order that sections will beplaced within a segment:

segment_name | section_name1;segment_name | section_name2;segment_name | section_name3;

The sections that are named in the above form will be placed before any unnamedsections, and in the order they are listed in the mapfile .

Size-Symbol DeclarationsSize-symbol declarations let you define a new global-absolute symbol that representsthe size, in bytes, of the specified segment. This symbol can be referenced in yourobject files. A size-symbol declaration has the following syntax:

segment_name @ symbol_name;

symbol_name can be any legal C identifier, although the link-editor does not checkthe syntax of the symbol_name.

232 Linker and Libraries Guide ♦ August 1997

File Control DirectivesFile control directives allow users to specify which version definitions within sharedobjects are to be made available during a link-edit. The file control definition has thefollowing syntax:

shared_object_name - version_name [ version_name ... ];

version_name is a version definition name contained within the specifiedshared_object_name . For more information on version control see “Specifying aVersion Binding” on page 109.

Mapping ExampleFollowing is an example of a user-defined mapfile . The numbers on the left areincluded in the example for tutorial purposes. Only the information to the right ofthe numbers actually appears in the mapfile .

CODE EXAMPLE 8–1 User-Defined Mapfile

1. elephant : .data : peanuts.o *popcorn.o;2. monkey : $PROGBITS ?AX;3. monkey : .data;4. monkey = LOAD V0x80000000 L0x4000;5. donkey : .data;6. donkey = ?RX A0x1000;7. text = V0x80008000;

Four separate segments are manipulated in this example. The implicitly declaredsegment elephant (line 1) receives all of the .data sections from the filespeanuts.o and popcorn.o . Note that *popcorn.o matches any popcorn.o filethat may be supplied to the link-edit; the file need not be in the current directory. Onthe other hand, if /var/tmp/peanuts.o was supplied to the link-edit, it will notmatch peanuts.o because it is not preceded by a * .

The implicitly declared segment monkey (line 2) receives all sections that are both$PROGBITSand allocatable-executable (?AX), as well as all sections (not already inthe segment elephant ) with the name .data (line 3). The .data sections enteringthe monkey segment need not be $PROGBITSor allocatable-executable because thesection_type and section_flags values are entered on a separate line from thesection_name value. (An “and” relationship exists between attributes on the sameline as illustrated by $PROGBITS“and” ?AX on line 2. An “or” relationship existsbetween attributes for the same segment that span more than one line as illustratedby $PROGBITS ?AXon line 2 “or” .data on line 3.)

Mapfile Option 233

The monkey segment is implicitly declared in line 2 with segment_type value LOAD,segment_flags value RWX, and no virtual_address, physical_address, length oralignment values specified (defaults are used). In line 4 the segment_type value ofmonkey is set to LOAD(since the segment_type attribute value does not change, nowarning is issued), virtual_address value to 0x80000000 and maximum length valueto 0x4000.

Line 5 implicitly declares the donkey segment. The entrance criteria are designed toroute all .data sections to this segment. Actually, no sections fall into this segmentbecause the entrance criteria for monkey in line 3 capture all of these sections. In line6, the segment_flags value is set to ?RX and the alignment value is set to 0x1000(since both of these attribute values changed, a warning is issued).

Line 7 sets the virtual_address value of the text segment to 0x80008000.

The example of a user-defined mapfile is designed to cause warnings forillustration purposes. If you want to change the order of the directives to avoidwarnings, use the following example:

1. elephant : .data : peanuts.o *popcorn.o;4. monkey = LOAD V0x80000000 L0x4000;2. monkey : $PROGBITS ?AX;3. monkey : .data;6. donkey = ?RX A0x1000;5. donkey : .data;7. text = V0x80008000;

The following mapfile example uses the segment within section ordering:

1. text = LOAD ?RXN V0xf0004000;2. text | .text;3. text | .rodata;4. text : $PROGBITS ?A!W;5. data = LOAD ?RWX R0x1000;

The text and data segments are manipulated in this example. Line 1 declares thetext segment to have a virtual_address of 0xf0004000 and to not include theELF header or any program headers as part of this segments address calculations.Lines 2 and 3 turn on section-within-segment ordering and specify that the .textand .rodata sections will be the first two sections in this segment. The result is thatthe .text section will have a virtual address of 0xf0004000, and the .rodatasection will immediately follow that.

Any other $PROGBITSsection that make up the text segment will follow the.rodata section. Line 5 declares the data segment and specifies that its virtualaddress must begin on a 0x1000 byte boundary. The first section that constitutes thedata segment will also reside on a 0x1000 byte boundary within the file image.

234 Linker and Libraries Guide ♦ August 1997

Mapfile Option DefaultsThe link-editor defines three built-in segments (text , data , and note ) with defaultsegment_attribute_values and corresponding default mapping directives as describedin “Segment Declarations” on page 227. Even though the link-editor does not use anactual mapfile to provide the defaults, the model of a default mapfile helpsillustrate what happens when the link-editor encounters your mapfile .

The example below shows how a mapfile would appear for the link-editordefaults. The link-editor begins execution behaving as if the mapfile has alreadybeen read in. Then the link-editor reads your mapfile and either augments ormakes changes to the defaults.

text = LOAD ?RX;text : ?A!W;data = LOAD ?RWX;data : ?AW;note = NOTE;note : $NOTE;

As each segment declaration in your mapfile is read in, it is compared to theexisting list of segment declarations as follows:

1. If the segment does not already exist in the mapfile , but another with the samesegment-type value exists, the segment is added before all of the existingsegments of the same segment_type.

2. If none of the segments in the existing mapfile has the same segment_type valueas the segment just read in, then the segment is added by segment_type value tomaintain the following order:

INTERP

LOAD

DYNAMIC

NOTE

3. If the segment is of segment_type LOADand you have defined a virtual_addressvalue for this LOADable segment, the segment is placed before any LOADablesegments without a defined virtual_address value or with a highervirtual_address value, but after any segments with a virtual_address value that islower.

As each mapping directive in a mapfile is read in, the directive is added after anyother mapping directives that you already specified for the same segment but beforethe default mapping directives for that segment.

Mapfile Option 235

Internal Map StructureOne of the most important data structures in the ELF-based link-editor is the mapstructure. A default map structure, corresponding to the model default mapfilementioned above, is used by the link-editor when the command is executed. Then, ifthe mapfile option is used, the link-editor parses the mapfile to augment and/oroverride certain values in the default map structure.

A typical (although somewhat simplified) map structure is illustrated in Figure 8–1.The “Entrance Criteria” boxes correspond to the information in the default mappingdirectives and the “Segment Attribute Descriptors” boxes correspond to theinformation in the default segment declarations. The “Output Section Descriptors”boxes give the detailed attributes of the sections that fall under each segment. Thesections themselves are in circles.

Entrancecriteria

$PROGBITS?A!W

$PROGBITS?AW

$NOGBITS?AW $NOTE

NO MATCH -appended toend of a.out

Segmentattributedescriptors

textLOAD?RX

dataLOAD?RWX

noteNOTE

Output sectiondescriptors

.data$PROGBITS

?AWX

.data1$PROBITS

?AWX

.data2$PROGBITS

?AWX

.bss$NOBITS

?AWX

.datafromfido.o

.data1fromfido.o

.data2fromfido.o

.bssfrom

rover.o

.data1from

rover.o

.data1from

sam.oSectionsplaced insegments

Figure 8–1 Simple Map Structure

The link-editor performs the following steps when mapping sections to segments:

1. When a section is read in, the link-editor checks the list of Entrance Criterialooking for a match. All specified criteria must be matched.

In Figure 8–1, for a section to fall into the text segment it must have asection_type value of $PROGBITSand have a section_flags value of ?A!W. It need

236 Linker and Libraries Guide ♦ August 1997

not have the name .text since no name is specified in the Entrance Criteria. Thesection may be either X or !X (in the section_flags value) since nothing wasspecified for the execute bit in the Entrance Criteria.

If no Entrance Criteria match is found, the section is placed at the end of thea.out file after all other segments. (No program header entry is created for thisinformation. See “Program Header” on page 195 for more information).

2. When the section falls into a segment, the link-editor checks the list of existingOutput Section Descriptors in that segment as follows:

If the section attribute values match those of an existing Output SectionDescriptor exactly, the section is placed at the end of the list of sections associatedwith that Output Section Descriptor.

For instance, a section with a section_name value of .data1 , a section_type valueof $PROGBITS, and a section_flags value of ?AWXfalls into the second EntranceCriteria box in Figure 8–1, placing it in the data segment. The section matchesthe second Output Section Descriptor box exactly (.data1 , $PROGBITS, ?AWX)and is added to the end of the list associated with that box. The .data1 sectionsfrom fido.o , rover.o , and sam.o illustrate this point.

If no matching Output Section Descriptor is found, but other Output SectionDescriptors of the same section_type exist, a new Output Section Descriptor iscreated with the same attribute values as the section and that section is associatedwith the new Output Section Descriptor. The Output Section Descriptor (and thesection) are placed after the last Output Section Descriptor of the samesection_type. The .data2 section in Figure 8–1 was placed in this manner.

If no other Output Section Descriptors of the indicated section_type exist, a newOutput Section Descriptor is created and the section is placed in that section.

Note - If the input section has a user-defined section_type value (that is, betweenSHT_LOUSERand SHT_HIUSER, as described in the “Sections” on page 155) it istreated as a $PROGBITSsection. Note that no method exists for naming thissection_type value in the mapfile , but these sections can be redirected using theother attribute value specifications (section_flags, section_name) in the entrancecriteria.

3. If a segment contains no sections after all of the command line object files andlibraries are read in, no program header entry is produced for that segment.

Note - Input sections of type $SYMTAB, $STRTAB, $REL, and $RELA are usedinternally by the link-editor. Directives that refer to these section_types can only mapoutput sections produced by the link-editor to segments.

Mapfile Option 237

Error MessagesWarningsErrors within this category do not stop execution of the link-editor nor do theyprevent the link-editor from producing a viable a.out . The following conditionsproduce warnings:

� A physical_address or a virtual_address value or a length value appears for anysegment other than a LOADsegment. (The directive is ignored).

� A second declaration line exists for the same segment that changes an attributevalue(s). (The second declaration overrides the original).

� An attribute value(s) (segment_type and/or segment_flags for text and data ;segment_type for note ) was changed for one of the built-in segments.

� An attribute value(s) (segment_type, segment_flags, length and/or alignment) waschanged for a segment created by an implicit declaration. If only the ?O flag hasbeen added then the change of attribute value warning will not be generated.

� An entrance criteria was not met. If the ?O flag has been turned on and if none ofthe input sections met an entrance criteria, the warning is generated.

Fatal ErrorsErrors within this category stop execution of the link-editor at the point the fatalerror occurred. The following conditions produce fatal errors:

� A mapfile cannot be opened or read.

� A syntax error is found in the mapfile .

Note - The link-editor does not return an error if a file_name, section_name,segment_name or symbol_name does not conform to the rules under “MapfileStructure and Syntax” on page 226 unless this condition produces a syntax error.For instance, if a name begins with a special character and this name is at thebeginning of a directive line, the link-editor returns an error. If the name is asection_name (appearing within the directive), the link-editor does not return anerror.

� More than one segment_type, segment_flags, virtual_address, physical_address,length, or alignment value appears on a single declaration line.

� You attempt to manipulate either the interp segment or dynamic segment in amapfile .

238 Linker and Libraries Guide ♦ August 1997

Note - The interp and dynamic segments are special built-in segments that youcannot change in any way.

� A segment grows larger than the size specified by a your length attribute value.

� A user-defined virtual_address value causes a segment to overlap the previoussegment.

� More than one section_name, section_type, or section_flags value appears on asingle directive line.

� A flag and its complement (for example, A and !A ) appear on a single directiveline.

Mapfile Option 239

240 Linker and Libraries Guide ♦ August 1997

APPENDIX A

Link-Editor Quick Reference

OverviewThe following sections provide a simple overview, or cheat sheet, of the mostcommonly used link-editor scenarios (see “Link-Editing” on page 2for anintroduction to the kinds of output modules generated by the link-editor).

The examples provided show the link-editor options as supplied to the compilerdriver cc (1), this being the most common mechanism of invoking the link-editor(see “Using a Compiler Driver” on page 9).

The link-editor places no meaning on the name of any input file. Each file is openedand inspected to determine the type of processing it requires (see “Input FileProcessing” on page 10).

Shared objects that follow a naming convention of lib x.so , and archive librariesthat follow a naming convention of lib x.a , can be input using the −l option (see“Library Naming Conventions” on page 13). This provides additional flexibility inallowing search paths to be specified using the −L option (see “Directories Searchedby the Link-Editor” on page 15).

The link-editor basically operates in one of two modes, static or dynamic.

Static ModeThis mode is selected when the −dn option is used, and allows for the creation ofrelocatable objects and static executables. Under this mode only relocatable objects

241

and archive libraries are acceptable forms of input. Use of the −l option will result ina search for archive libraries.

Building a Relocatable Object� Use the −dn and −r options:

$ cc -dn -r -o temp.o file1.o file2.o file3.o .....

Building a Static ExecutableThe use of static executables is limited. Static executables usually contain platformspecific implementation details which restricts the ability of the executable to be runon an alternative platform. Also, many implementations of Solaris librariesdepend on dynamic linking capabilities such as dlopen (3X) and dlsym (3X). (see“Loading Additional Objects” on page 55). These capabilities are not available tostatic executables.

� Use the −dn option without the −r option:

$ cc -dn -o prog file1.o file2.o file3.o .....

Note - The −a option is available to indicate the creation of a static executable,however, the use of −dn without a −r implies −a.

Dynamic ModeThis is the default mode of operation for the link-editor. It can be enforced byspecifying the −dy option, but is implied when not using the −dn option.

Under this mode, relocatable objects, shared objects and archive libraries areacceptable forms of input. Use of the −l option will result in a directory search,where each directory is searched for a shared object, and if none is found the samedirectory is then searched for an archive library. A search for archive libraries only,can be enforced by using the −B static option (see “Linking with a Mix of SharedObjects and Archives” on page 14).

Building a Shared Object� Use the −G option (−dy is optional as it is implied by default).

242 Linker and Libraries Guide ♦ August 1997

� Input relocatable objects should be built from position-independent code. Use the−z text option to enforce this requirement (see “Position-Independent Code” onpage 86).

� Establish the shared objects public interface by defining the global symbols thatshould be visible from this shared object, and reducing any other global symbolsto local scope. This definition is provided by the −Moption together with anassociated mapfile , and is covered in more detail inAppendix B.

� Use a versioned name for the shared object to allow for future upgrades (see“Coordination of Versioned Filenames” on page 114).

� If the shared object being generated has dependencies on any other shared objects,and these dependencies do not reside in /usr/lib , record their pathname in theoutput file using the −R option (see “Shared Objects with Dependencies” on page76).

� Self contained shared objects offer maximum flexibility, and are produced whenthe object expresses all dependency needs. Use the −z defs to enforce this selfcontainment (see “Generating a Shared Object” on page 26)

The following example combines the above points:

$ cc -c -o foo.o -Kpic foo.c$ cc -M mapfile -G -o libfoo.so.1 -z text -z defs \-R /home/lib foo.o -L. -lbar

� If the shared object being generated will be used as input to another link-edit,record within it the shared object’s runtime name using the −h option (see“Recording a Shared Object Name” on page 73).

� Make the shared object available to the compilation environment by creating a filesystem link to a non-versioned shared object name (see “Coordination ofVersioned Filenames” on page 114).

The following example combines the above points:

$ cc -M mapfile -G -o libfoo.so.1 -z text -z defs \-R /home/lib-h libfoo.so.1 foo.o$ ln -s libfoo.so.1 libfoo.so

� Consider the performance implications of the shared object; maximize shareability(see “Maximizing Shareability” on page 88) and minimize paging activity (see“Minimizing Paging Activity” on page 90), reduce relocation overhead, especiallyby minimizing symbolic relocations (see “Profiling Shared Objects” on page 95),and allow access to data via functional interfaces (see “Copy Relocations” on page91).

Link-Editor Quick Reference 243

Building a Dynamic Executable� Don’t use the −G, or −dn options.

� If the dynamic executable being generated has dependencies on any other sharedobjects, and these dependencies do not reside in /usr/lib , record their pathnamein the output file using the −R option (see “Directories Searched by the RuntimeLinker” on page 16).

The following example combines the above points:

$ cc -o prog -R /home/lib -L. -lfoo file1.o file2.o file3.o .....

244 Linker and Libraries Guide ♦ August 1997

APPENDIX B

Versioning Quick Reference

OverviewELF objects make available global symbols to which other objects can bind. Some ofthese global symbols can be identified as providing the object’s public interface. Othersymbols are part of the objects internal implementation and are not intended forexternal use. An objects interface can evolve from one software release to another,and thus the ability to identify this evolution is desirable.

In addition, identifying the internal implementation changes of an object from onesoftware release to another might be desirable.

Both interface and implementation identifications can be recorded within an objectby establishing internal version definitions (see “Overview” on page 97 for a morecomplete introduction to the concept of internal versioning).

Shared objects are prime candidates for internal versioning as this technique definestheir evolution, provides for interface validation during runtime processing (see“Binding to a Version Definition” on page 105), and provides for the selectivebinding of applications (see “Specifying a Version Binding” on page 109). Sharedobjects will be used as the examples throughout this chapter.

The following sections provide a simple overview, or cheat sheet, of the internalversioning mechanism provided by the link-editors as applied to shared objects. Theexamples recommend conventions and mechanisms for versioning shared objects,from their initial construction through several common update scenarios.

245

Naming ConventionsA shared object follows a naming convention that includes a major number file suffix(see “Naming Conventions” on page 72). Within this shared object, one or moreversion definitions can be created. Each version definition corresponds to one of thefollowing categories:

� It defines an industry standard interface (for example, the System V ApplicationBinary Interface).

� It defines a vendor specific public interface.

� It defines a vendor specific private interface.

� It defines a vendor specific change to the internal implementation of the object.

The following version definition naming conventions help indicate which of thesecategories the definition represents.

The first three of these categories indicate interface definitions. These definitionsconsist of an association of the global symbol names that comprise the interface, witha version definition name (see “Creating a Version Definition” on page 99). Interfacechanges within a shared object are often referred to as minor revisions. Therefore,version definitions of this type, are suffixed with a minor version number which isbased off of the filenames major version number suffix.

The last category indicates a change having occurred within the object. Thisdefinition consists of a version definition acting as a label and has no symbol namesassociated with it. This definition is referred to as being a weak version definition (see“Creating a Weak Version Definition” on page 102). Implementation changes within ashared object are often referred to as micro revisions. Therefore, version definitions ofthis type are suffixed with a micro version number based off of the previous minornumber to which the internal changes have been applied.

Any industry standard interfaces should use a version definition name that reflectsthe standard. Any vendor interfaces should use a version definition name unique tothat vendor (the company’s stock symbol is often appropriate).

Private version definitions indicate symbols that have restricted or uncommitted use,and should have the word private clearly visible.

All version definitions result in the creation of associated version symbol names.Therefore, the use of unique names and the minor/micro suffix convention reduce thechance of symbol collision within the object being built.

The following version definition examples show the use of these naming conventions:

SVABI.1

defines the System V Application Binary Interface standards interface.

246 Linker and Libraries Guide ♦ August 1997

SUNW_1.1

defines a SunSoft public interface.

SUNWprivate_1.1

defines a SunSoft private interface.

SUNW_1.1.1

defines a SunSoft internal implementation change.

Defining a Shared Object’s InterfaceWhen establishing a shared object’s interface the first task is to determine whichglobal symbols provided by the shared object can be associated to one of the threeinterface version definition categories:

� Industry standard interface symbols conventionally are defined in publiclyavailable header files and associated manual pages supplied by the vendor, andare also documented in recognized standards literature.

� Vendor public interface symbols conventionally are defined in publicly availableheader files and associated manual pages supplied by the vendor.

� Vendor private interface symbols can have little or no public definition.

By defining these interfaces, a vendor is indicating the commitment level of eachinterface of the shared object. Industry standard and vendor public interfaces remainstable from release to release. You are free to bind to these interfaces safe in theknowledge that your application will continue to function correctly from release torelease.

Industry standard interfaces might be available on systems provided by othervendors, and thus you can achieve a higher level of binary compatibility byrestricting your applications to use these interfaces.

Vendor public interfaces might not be available on systems provided by othervendors, however these interfaces will remain stable during the evolution of thesystem on which they are provided.

Vendor private interfaces are very unstable, and can change, of even be deleted, fromrelease to release. These interfaces provide for uncommitted or experimentalfunctionality, or are intended to provide access for vendor specific applications only.If you who wish to achieve any level of binary compatibility you should avoid usingthese interfaces.

Versioning Quick Reference 247

Any global symbols that do not fall into one of the above categories should bereduced to local scope so that they are no longer visible for binding (see “ReducingSymbol Scope” on page 33).

Versioning a Shared ObjectHaving determined a shared object’s available interfaces, the associated versiondefinitions are created using a mapfile and the link-editors −Moption (see “DefiningAdditional Symbols” on page 28 for an introduction of this mapfile syntax).

The following example defines a vendor public interface in the shared objectlibfoo.so.1 :

$ cat mapfileSUNW_1.1 { # Release X.

global:foo2;foo1;

local:*;

};$ cc -G -o libfoo.so.1 -h libfoo.so.1 -z text -M mapfile foo.c

Here the global symbols foo1 and foo2 are assigned to the shared objects publicinterface SUNW_1.1. Any other global symbols supplied from the input files arereduced to local by the auto-reduction directive “*” (see “Reducing Symbol Scope” onpage 33).

Note - Each version definition mapfile entry should be accompanied by a commentreflecting the release or date of the update. This information helps coordinatemultiple updates of a shared object, possibly by different developers, into one versiondefinition suitable for delivery of the shared object as part of a software release.

Versioning an Existing (Non-versioned) SharedObjectVersioning an existing, non-versioned shared object requires extra care, as the sharedobject delivered in a previous software release has made available all its globalsymbols for others to bind with. Although it can be possible to determine the sharedobjects intended interfaces, it can be the case that others have discovered and bound

248 Linker and Libraries Guide ♦ August 1997

to other symbols. Therefore, the removal of any symbols might result in anapplications failure on delivery of the new versioned shared object.

The internal versioning of an existing, non-versioned shared object can be achieved ifthe interfaces can be determined, and applied, without breaking any existingapplications. The runtime linker’s debugging capabilities can be useful to help verifythe binding requirements of various applications (see “Debugging Aids” on page 67).However, this determination of existing binding requirements assumes that all usersof the shared object are known.

If the binding requirements of an existing, non-versioned shared object can not bedetermined then it is necessary to create a new shared object file using a newversioned name (see “Coordination of Versioned Filenames” on page 114). Inaddition to this new shared object, the original shared object must also be deliveredso as to satisfy the dependencies of any existing applications.

If the implementation of the original shared object is to be frozen then maintainingand delivering the shared object binary might be sufficient. If however, the originalshared object might require updating - for example, through patches, or because itsimplementation must evolve to remain compatible with new platforms - then analternative source tree from which to generate the shared object can be moreapplicable.

Updating a Versioned Shared ObjectThe only changes that can be made to a shared object that can be absorbed byinternal versioning are compatible changes (see “Interface Compatibility” on page 98).Any incompatible changes require producing a new shared object with a new externalversioned name (see “Coordination of Versioned Filenames” on page 114).

Compatible updates that can be accommodated by internal versioning fall into threebasic categories:

� adding new symbols.

� creating new interfaces from existing symbols.

� internal implementation changes.

The first two categories are achieved by associating an interface version definitionwith the appropriate symbols. The latter is achieved by creating a weak versiondefinition that has no associated symbols.

Versioning Quick Reference 249

Adding New SymbolsAny compatible new release of a shared object that contains new global symbolsshould assign these symbols to a new version definition. This new version definitionshould inherit the previous version definition.

The following mapfile example assigns the new symbol foo3 to the new interfaceversion definition SUNW_1.2. This new interface inherits the original interfaceSUNW_1.1:

$ cat mapfileSUNW_1.2 { # Release X+1.

global:foo3;

} SUNW_1.1;

SUNW_1.1 { # Release X.global:

foo2;foo1;

local:*;

};

The inheritance of version definitions reduces the amount of version information thatmust be recorded in any user of the shared object.

Internal Implementation ChangesAny compatible new release of the shared object that consists of an update to theimplementation of the object - for example, a bug fix or performance improvement -should be accompanied by a weak version definition. This new version definitionshould inherit the latest version definition present at the time the update occurred.

The following mapfile example generates a weak version definition SUNW_1.1.1 .This new interface indicates that the internal changes were made to theimplementation offered by the previous interface SUNW_1.1:

$ cat mapfileSUNW_1.1.1 { } SUNW_1.1; # Release X+1.

SUNW_1.1 { # Release X.global:

foo2;foo1;

local:*;

(continued)

250 Linker and Libraries Guide ♦ August 1997

(Continuation)

};

New Symbols and Internal ImplementationChangesIf both internal changes and the addition of a new interface has occurred during thesame release, both a weak version and a interface version definition should becreated. The following example shows the addition of a version definition SUNW_1.2and an interface change SUNW_1.1.1 which are added during the same releasecycle. Both interfaces inherit the original interface SUNW_1.1:

$ cat mapfileSUNW_1.2 { # Release X+1.

global:foo3;

} SUNW_1.1;

SUNW_1.1.1 { } SUNW_1.1; # Release X+1.

SUNW_1.1 { # Release X.global:

foo2;foo1;

local:*;

};

Note - The comments for the SUNW_1.1 and SUNW_1.1.1 version definitionsindicate that they have both been applied to the same release.

Migrating Symbols to a Standard InterfaceOccasionally, symbols offered by a vendors interface become absorbed into a newindustry standard. When creating a new standard interface it is important tomaintain the original interface definitions provided by the shared object. Toaccomplish this it is necessary to create intermediate version definitions on which thenew standard, and original interface definitions, can be built.

The following mapfile example shows the addition of a new industry standardinterface STAND.1. This interface contains the new symbol foo4 and the existing

Versioning Quick Reference 251

symbols foo3 and foo1 which were originally offered through the interfacesSUNW_1.2and SUNW_1.1 respectively:

$ cat mapfileSTAND.1 { # Release X+2.

global:foo4;

} STAND.0.1 STAND.0.2;

SUNW_1.2 { # Release X+1.global:

SUNW_1.2;} STAND.0.1 SUNW_1.1;

SUNW_1.1.1 { } SUNW_1.1; # Release X+1.

SUNW_1.1 { # Release X.global:

foo2;local:

*;} STAND.0.2;

# Subversion - providing forSTAND.0.1 { # SUNW_1.2 and STAND.1 interfaces.

global:foo3;

};# Subversion - providing for

STAND.0.2 { # SUNW_1.1 and STAND.1 interfaces.global:

foo1;};

Here the symbols foo3 and foo1 are pulled into their own intermediate interfacedefinitions which are used to build the original and new interface definitions.

Note - The new definition of the SUNW_1.2 interface has referenced its own versiondefinition symbol. Without this reference the SUNW_1.2 interface would havecontained no immediate symbol references and hence would be categorized as aweak version definition.

When migrating symbol definitions to a standards interface the requirement is thatany original interface definitions continue to represent the same symbol list. Thisrequirement can be validated using pvs (1). The following example shows thesymbol list of the SUNW_1.2 interface as it existed in the software release X+1:

$ pvs -ds -N SUNW_1.2 libfoo.so.1SUNW_1.2:

foo3;SUNW_1.1:

foo2;

252 Linker and Libraries Guide ♦ August 1997

(Continuation)

foo1;

Although the introduction of the new standards interface in software release X+2 haschanged the interface version definitions available, the list of symbols provided byeach of the original interfaces remains constant. The following example shows thatinterface SUNW_1.2 still provides symbols foo1 , foo2 and foo3 :

$ pvs -ds -N SUNW_1.2 libfoo.so.1SUNW_1.2:STAND.0.1:

foo3;SUNW_1.1:

foo2;STAND.0.2:

foo1;

It is possible that an application might only reference one of the new subversions, inwhich case any attempt to run the application on a previous release will result in aruntime versioning error (see “Binding to a Version Definition” on page 105).

In this case an applications version binding can be promoted by directly referencingan existing version name (see “Binding to Additional Version Definitions” on page111).

For example, if an application only references the symbol foo1 from the sharedobject libfoo.so.1 , then its version reference will be to STAND.0.2 . To allow thisapplication to be run on previous releases, the version binding can be promoted toSUNW_1.1using a version control mapfile directive:

$ cat prog.cextern void foo1();

main(){

foo1();}$ cc -o prog prog.c -L. -R. -lfoo$ pvs -r prog

libfoo.so.1 (STAND.0.2);

$ cat mapfilelibfoo.so - SUNW_1.1 $ADDVERS=SUNW_1.1;$ cc -M mapfile -o prog prog.c -L. -R. -lfoo$ pvs -r prog

(continued)

Versioning Quick Reference 253

(Continuation)

libfoo.so.1 (SUNW_1.1);

In practice it is rarely necessary to promote a version binding in this manner, as theintroduction of new standards binary interfaces is rare, and most applicationsreference many symbols from an interface family.

254 Linker and Libraries Guide ♦ August 1997

Index

AABI (see Application Binary Interface and

System V Application BinaryInterface), 5

$ADDVERS, see versioning,Application Binary Interface, 5, 80, 97ar(1), 11archives, 13

inclusion of shared objects in, 74link-editor processing, 11multiple passes through, 12

naming conventions, 13as(1), 2auxiliary filters, 78, 81

Bbase address, 199binding, 1

dependency ordering, 77lazy, 49, 57, 69to shared object dependencies, 73, 105to version definitions, 105to weak version definitions, 112

Ccc(1), 1, 2, 9COMMON, 19, 30, 32, 157compilation environment, 4, 14, 72

See also link-editing and link-editor,

Ddata representation, 147debugging aids

link-editing, 38runtime linking, 67

demonstrationsprefcnt, 129sotruss, 129symbindrep, 129whocalls, 129

dependencygroups, 56, 58

dependency ordering, 77dlclose(3X), 55dldump(3X), 18dlerror(3X), 55dlfcn.h, 55dlmopen(3X), 123dlopen(3X), 44, 55, 61, 83, 108, 118

effects of ordering, 60group, 56, 58modes

RTLD_GLOBAL, 57, 61RTLD_GROUP, 62RTLD_LAZY, 57RTLD_NOLOAD, 123RTLD_NOW, 57RTLD_PARENT, 62, 63

of a dynamic executable, 57, 61shared object naming conventions, 72

dlsym(3X), 44, 55, 63, 66, 108, 118

Index-255

special handleRTLD_DEFAULT, 27, 63RTLD_NEXT, 63

dump(1), 5, 45, 47, 85, 87dynamic executables, 2, 4dynamic information tags

NEEDED, 45, 73RPATH, 45SONAME, 74TEXTREL, 87

dynamic linking, 4implementation, 177, 185, 204

EELF, 2, 7, 83

(see also object files), 145elf(3E), 5environment variables

LD_AUDIT, 124LD_BIND_NOT, 69LD_BIND_NOW, 49, 69, 209, 221, 223LD_BREADTH, 53LD_DEBUG, 67LD_DEBUG_OUTPUT, 68LD_LIBRARY_PATH, 16, 46, 54, 56, 76LD_LOADFLTR, 83LD_NOAUXFLTR, 82LD_OPTIONS, 9, 39LD_PRELOAD, 51, 54LD_PROFILE, 95LD_PROFILE_OUTPUT, 95LD_RUN_PATH, 17SGS_SUPPORT, 118

error messages

link-editorillegal argument to option, 10illegal option, 10incompatible options, 10multiple instances of an option, 10

multiply defined symbols, 24relocations against non-writable

sections, 87shared object name conflicts, 75soname conflicts, 75symbol not assigned to version, 35symbol warnings, 22undefined symbols, 24, 25undefined symbols from an implicit

reference, 26version unavailable, 110

runtime linkercopy relocation size differences, 94relocation errors, 49, 107unable to find shared object, 46, 56unable to find version definition, 107unable to locate symbol, 64

exec(2), 7, 43, 146executable and linking format (see ELF), 2

Ff77(1), 9filters, 78

auxiliary, 78, 81platform specific, 82

standard, 78

Ggenerating a shared object, 26generating an executable, 24generating the output file image, 37global offset table, 38, 47, 86, 185, 218, 219global symbols, 19, 98, 173, 174

Iinitialization and termination, 9, 17, 52input file processing, 10interface

private, 98public, 98, 246

Index-256 Linker and Libraries Guide ♦ August 1997

interposition, 21, 22, 34, 48, 52, 65, 98interpreter (see also runtime linker), 43

Llazy binding, 49, 57, 69, 122ld(1), 1ld.so.1(1) (see also runtime linker), 7, 43ld.so.1(1) (see runtime linker), 2ldd(1), 5, 44, 46, 48, 50, 83, 107, 108ldd(1) options, 52

-d, 50, 83, 94-i, 52-l, 83-r, 83, 94-v, 107

LD_AUDIT, 124LD_BIND_NOT, 69LD_BIND_NOW, 49, 69, 209, 221, 223LD_BREADTH, 53LD_DEBUG, 67LD_DEBUG_OUTPUT, 68LD_LIBRARY_PATH, 16, 46, 54, 56, 76LD_LOADFLTR, 83LD_NOAUXFLTR, 82LD_OPTIONS, 10, 39LD_PRELOAD, 51, 54LD_PROFILE, 95LD_PROFILE_OUTPUT, 95LD_RUN_PATH, 17libdl.so.1, 55libelf.so.1, 118, 145libldstab.so.1, 118libraries

archives, 13naming conventions, 13shared, 177, 185, 204

link-editing, 2, 171, 185, 204adding additional libraries, 13archive processing, 11binding to a version definition, 105, 109dynamic, 177, 185, 204input file processing, 10library input processing, 11library linking options, 11mixing shared objects and archives, 14multiply defined symbols, 174position of files on command line, 14

search paths, 15shared object processing, 12

link-editor, 1, 7debugging aids, 38invoking directly, 8invoking using compiler driver, 9overview, 7sections, 7segments, 7specifying options, 9

link-editor options-a, 242-B dynamic, 14-B group, 58, 62, 217-B reduce, 30, 37-B static, 14, 242-D, 39-d, 242-e, 38-F, 78-f, 78-G, 71-h, 45, 73, 116, 243-i, 16-l, 11, 13

-L, 15-l, 72, 114-L, 241-l, 241-M, 8-m, 13, 22-M, 28, 29, 98, 99, 109, 225, 243, 248-r, 9-R, 17, 76-r, 242-R, 243, 244-s, 37-S, 118-t, 22, 23-u, 28-Y, 15-z allextract, 11-z defaultextract, 12-z defs, 26, 124, 243-z ignore, 12-z initfirst, 217-z loadfltr, 83, 217

Index-257

-z muldefs, 24-z nodefs, 25, 50-z nodelete, 217-z nodlopen, 217-z noversion, 35, 100, 107-z now, 49, 57, 217-z text, 87, 243-z weakextract, 11, 174

link-editor outputdynamic executables, 3relocatable objects, 2shared objects, 3static executables, 2

link-editor support interface (ld-support), 117ld_atexit, 120ld_file, 119ld_section, 120ld_start, 119

link-editor, see error messageserror messages,

local symbols, 19, 173, 174lorder(1), 12, 40

Mmapfiles, 225, 241

defaults, 235error messages, 238example, 233map structure, 236mapping directives, 230segment declarations, 227size-symbol declarations, 232structure, 226syntax, 226usage, 226

mmap(2), 43multiply defined symbols, 37, 173, 174

NName-space, 123naming conventions

archives, 13libraries, 13shared objects, 13, 72

NEEDED, 45, 73nm(1), 5, 85

Oobject files, 2

base address, 199data representation, 147global offset table (see global offset

table), 218note section, 193, 194preloading at runtime, 51procedure linkage table (see procedure

linkage table), 219, 221program header, 195, 198program interpretor, 207program loading, 201relocation, 177, 185, 218section alignment, 159section attributes, 163, 170section header, 156, 170section names, 170section types, 159, 170segment contents, 200, 201segment permissions, 199, 200segment types, 196, 199string table, 170, 171symbol table, 171, 177

Ppackages

SUNWosdem, 129, 132, 145SUNWtool, 129

paging, 204, 201performance

allocating buffers dynamically, 89collapsing multiple definitions, 89improving locality of references, 90, 95maximizing shareability, 88minimizing data segment, 88position-independent code (see

position-dependent code), 86relocations, 90, 95the underlying system, 86using automatic variables, 89

platform specific auxiliary filters, 82$PLATFORM, see search paths,position-independent code, 86, 206, 217, 218preloading objects (see LD_PRELOAD

also), 51

Index-258 Linker and Libraries Guide ♦ August 1997

procedure linkage table, 38, 49, 86, 185, 219,221

SPARC, 219, 221profil(2), 95program interpreter, 43, 207, 208

(see also runtime linker), 43pvs(1), 5, 100, 102, 105, 106

Rrelocatable objects, 2relocation, 46, 90, 94, 177, 185

copy, 91data references, 48function references, 49non-symbolic, 47, 90runtime linker

symbol lookup, 48, 49, 57, 69symbolic, 47, 90

RPATH (see also runpath), 45RTLD_DEFAULT, 27

See also dependency ordering,RTLD_GLOBAL, 57, 61RTLD_GROUP, 62RTLD_LAZY, 57RTLD_NEXT

See also dependency ordering,RTLD_NOLOAD, 123RTLD_NOW, 57RTLD_PARENT, 62, 63runpath, 17, 45, 54, 56, 69, 76runtime environment, 4, 14, 72runtime linker, 2, 3, 43, 208

initialization and termination routines, 52lazy binding, 49, 57, 69link-maps, 123loading additional objects, 51name-space, 123programming interface (see also

dlopen(3X) family ofroutines), 54

relocation processing, 46search paths, 17, 44security, 53, 124shared object processing, 44version definition verification, 107

runtime linker support interfaces(rtld-audit), 117, 122

la_i86_pltenter, 127la_objclose, 128la_objopen, 125la_pltexit, 127la_preinit, 125la_sparcv8_pltenter, 127la_symbind32, 126la_version, 125

runtime linker support interfaces(rtld-debugger), 117, 130

ps_global_sym, 142ps_pglobal_sym, 142ps_plog, 142ps_pread, 142ps_pwrite, 142rd_delete, 133rd_errstr, 134rd_event_addr, 138rd_event_enable, 137rd_event_getmsg, 139rd_init, 133rd_loadobj_iter, 136rd_log, 134rd_new, 133rd_objpad_enable, 141rd_plt_resolution, 139rd_reset, 133

runtime linking, 3

SSCD (see SPARC Compliance Definition), 5search paths

link-editing, 15runtime linker, 17, 44

$PLATFORM token, 82section types, 17, 45, 92

.bss, 7

.data, 7, 88

.dynamic, 38, 43

.dynstr, 37

.dynsym, 37

.fini, 17, 52

.got, 38, 47

.init, 17, 52

.interp, 43

.picdata, 89

Index-259

.plt, 38, 49, 95

.rela.text, 7

.rodata, 88

.strtab, 7, 37

.SUNW_version, 188

.symtab, 7, 37

.text, 7sections, 7, 84

(see also section types), 7security, 53, 124segments, 7, 84

data, 84, 86text, 84, 86

SGS_SUPPORT, 118shared libraries (see shared objects), 2shared objects, 2 to 4, 44

as filters (see filters), 78building (see also performance), 71dependency ordering, 77explicit definition, 26implementation, 177, 185, 204implicit definition, 25link-editor processing, 12naming conventions, 13, 72recording a runtime name, 73with dependencies, 76

size(1), 83SONAME, 74SPARC Compliance Definition, 5standard filters, 78static executables, 2strings(1), 89strip(1), 37SUNWosdem, 129, 132, 145SUNWtoo, 129support interfaces

link-editor (ld-support), 117runtime linker (rtld-audit), 117, 122runtime linker (rtld-debugger), 117, 130

symbol reserved names, 37_DYNAMIC, 38_edata, 37_end, 38_END_, 38_etext, 37_fini, 17_GLOBAL_OFFSET_TABLE_, 38, 219_init, 17

main, 38_PROCEDURE_LINKAGE_TABLE_, 38_start, 38_START_, 38

symbol resolution, 18, 19, 37complex, 22fatal, 23interposition (see interposition), 48multiple definitions, 13search scope

group, 58simple, 20symbol visibility

global, 58local, 58

symbolsabsolute, 30, 157archive extraction, 11auto-reduction, 30, 35, 100, 248COMMON, 19, 30, 32, 157defined, 19definition, 11, 24existence test, 26global, 19, 20, 98, 173, 174local, 19, 173, 174

private interface, 98public interface, 98reference, 11, 24runtime lookup, 57, 66

deferred, 49, 57, 69scope, 57, 61tentative, 11, 19, 27, 30, 32, 157

ordering in the output file, 27realignment, 32

undefined, 11, 19, 24, 26weak, 11, 20, 26, 174

System V Application Binary Interface, 246

Ttentative symbols, 11, 19, 30, 32TEXTREL, 87tsort(1), 12, 40

Uundefined symbols, 24

Index-260 Linker and Libraries Guide ♦ August 1997

/usr/ccs/bin/ld, see link-editor,/usr/lib, 16, 44, 45, 54, 56, 124/usr/lib/ld.so.1, 43, 130

Vversioning, 97

base version definition, 100binding to a definition, 105, 109

$ADDVERS, 109defining a public interface, 35, 99definitions, 98, 99, 105file control directive, 109

filename, 99, 249generating definitions within an

image, 29, 35, 99normalization, 106overview, 97runtime verification, 107, 108

virtual addressing, 201

Wweak symbols, 20, 173, 174

undefined, 26

Index-261