I am sponsoring the following fasttrack for myself --- timeout 8/11/2010.
It adds three new options to the Solaris link-editor (ld).

A copy of the original (ld.1.orig) and new (ld.1.new) ld manpage, as well
as diffs (ld.1.diffs) can be found in the case materials.

Release Binding:                                Patch/Micro
-z guidance:                                    Committed
-z fatal-warnings/--fatal-warnings              Committed
-z nofatal-warnings/--no-fatal-warnings         Committed

--------------------------------------------------------------------------
The new options are:

    -z guidance

        The link-editor has many options that are highly
        recommended, but which are not on by default. When
        the user enables the -z guidance feature, ld will issue
        "guidance" warning (non-fatal) messages to recommend
        options or changes that will result in a better object.


    -z fatal-warnings, --fatal-warnings

        ld warnings are advisory, in that the link-editor continues
        on to build the output object. If -z fatal-warnings is set,
        warnings are treated as fatal conditions --- the output object
        is not built, and a non-zero exit status is returned. This
        feature is useful for building code that is held to very
        high standards (such as the core Solaris OS/net consolidation),
        since it will prevent inadvertent errors from slipping past
        developers. It should be noted that this includes the warnings
        issued by -z guidance.

        --fatal-warnings is the name used by the GNU ld for their version of
        this feature. We will accept it as an alias for -z fatal-warnings.


    -z nofatal-warnings, --no-fatal-warnings

        Undo the effect of -z fatal-warnings, and revert to non-fatal
        warnings. This is the default, and so should be rarely needed,
        but is useful in the context of the LD_OPTIONS environment
        variable to override the use -f -z fatal-warnings from within
        a Makefile:

            % LD_OPTIONS=-D-znofatal-warnings make

        --no-fatal-warnings is the name used by GNU ld for their version of
        this feature. We will accept it as an alias for -z nofatal-warnings.

I have successfully built the OS/net with -z guidance, and -z fatal-warnings
turned on. I was able to get a completely clean build with only a modest
set of changes (167 lines changed: 54 ins; 46 del; 67 mod). This reflects the
fact that we already do extensive checking of the objects in the OS/net
(via check_rtime). In general, the changes fall into the following categories:

    - Suppress guidance in known cases where the flagged behavior
      needs to be retained.

    - Some applications pull in dependencies they do not directly require
      for the benefit of plugins they later load, and the dependencies for
      those plugins are not completely specified. Correcting the plugin
      dependencies allows these extras to be dropped.

Although not part of this case, I expect to integrate these changes
in a future project, and to apply -z guidance and -z fatal-warnings to
the OS/net by default. This should make it easier for developers to spot
difficulties earlier in the coding process.

--------------------------------------------------------------------------
Example:

The following example demonstrates how the guidance feature
is intended to work. We will build a shared object that
has a variety of shortcomings:

    - Does not specify all it's dependencies
    - Specifies dependencies it does not use
    - Does not use direct bindings
    - Uses a version 1 mapfile
    - Contains relocations to the readonly allocable text (not PIC)

This scenario is sadly very common --- many shared objects
have one or more of these issues.

    % cat hello.c
    #include <stdio.h>
    #include <unistd.h>

    void
    hello(void)
    {
            printf("hello user %d\n", getpid());
    }

    % cat mapfile.v1
    # This version 1 mapfile will trigger a guidance message

    % cc -c hello.c
    % ld -o hello.so -G -M mapfile.v1 hello.o -lelf

As you can see, the operation completes without error, resulting
in a usable object. However, turning on guidance reveals a number
of things that could be better:

    ld -o hello.so -G -M mapfile.v1 hello.o -lelf -zguidance
    ld: guidance: version 2 mapfile syntax recommended: mapfile.v1
    ld: guidance: -z lazyload option recommended before first dependency
    ld: guidance: -B direct or -z direct option recommended before
                  first dependency
    Undefined                       first referenced
     symbol                             in file
    getpid                              hello.o  (symbol belongs to implicit
                                                  dependency /lib/libc.so.1)
    printf                              hello.o  (symbol belongs to implicit
                                                  dependency /lib/libc.so.1)
    ld: warning: symbol referencing errors
    ld: guidance: -z defs option recommended for shared objects
    ld: guidance: removal of unused dependency recommended: libelf.so.1
    warning: Text relocation remains                referenced
        against symbol                  offset      in file
    .rodata1 (section)                  0xa         hello.o
    getpid                              0x4         hello.o
    printf                              0xf         hello.o
    ld: guidance: position independent (PIC) code recommended for shared objects
    ld: guidance: see ld(1) -z guidance for more information

Given the explicit advice in the above guidance messages, it is
relatively easy to modify the example to do the right things:

    % cat mapfile.v2
    # This version 2 mapfile will not trigger a guidance message
    $mapfile_version 2

    % cc -c -Kpic hello.c
    % ld -o hello.so -G -Bdirect -M mapfile.v2 hello.o -lc -zguidance

Although unlikely, one might imagine a scenario in which it was desired
to use non-PIC code, and accept the price of performing relocations at
runtime on the readonly allocable text segment:

    % cc -c hello.c
    % ld -o hello.so -G -Bdirect -M mapfile.v2 hello.o -lc -zguidance
    warning: Text relocation remains                referenced
        against symbol                  offset      in file
    .rodata1 (section)                  0xa         hello.o
    getpid                              0x4         hello.o
    printf                              0xf         hello.o
    ld: guidance: position independent (PIC) code recommended for shared objects
    ld: guidance: see ld(1) -z guidance for more information

It is easy to disable that specific guidance warning without losing the
overall benefit from allowing the remainder of the guidance feature to
operate:

    % ld -o hello.so -G -Bdirect -M mapfile.v2 hello.o -lc -zguidance=notext




--------------------------------------------------------------------------
Rationale:

The information that follows below is not strictly part of this
case, but provides background information that may prove useful
to the reader in understanding the evolution in thinking and design
that led to the implementation of -z guidance and -z fatal-warnings
in their current form.

   The Solaris link-editor is one of the older Unix commands. Over
the years, applications have grown in size and complexity, and the ELF
system has evolved to provide them with tools needed to manage their
growing requirements. Features such as lazy loading, and direct bindings
have been added. In an ideal world, many of these options would be defaults,
with rarely used options that allow the user to turn them off. However, the
reality is exactly the reverse: For backward compatibility, these features
are all options that must be explicitly turned on by the user. This has
led to a situation in which most applications do not take advantage of
the many improvements that have been made in linking over the last 20
years. If their code seems to link and run without issue, what motivation
does a developer have to read a complex manpage, absorb the information
provided, choose the features that matter for their application, and apply
them? Experience shows that only the most motivated and diligent programmers
will make that effort. We would like to do something to make it easier
for everyone else.

There have been many conversations over the years regarding this issue,
and how to address it. They break down along the following lines:

    Change ld defaults
        Since the world would be a better place if these ld features were
        defaults, the ls command could simply be changed to make them so.

        This idea is simple, elegant, and impossible. Doing so would
        break a large number of existing applications, including those of
        ISVs, big customers, a plethora of existing open source packages.
        In each case, the owner of that code may choose to follow our lead
        and fix their code, or they may view it as an invitation to reconsider
        their commitment to our platform. Backward compatibility, and our
        installed base of working software, is one of our greatest assets,
        and not something to be lightly put at risk. Breaking backward
        compatibility at this level of the system is likely to do more
        harm than good.

    New link-editor
        One might create a new linker command, not called 'ld', leaving the
        old command as it is. The new one could use the same code as 'ld',
        but would offer only modern options, with the proper defaults for
        features such as direct binding.

        The resulting link-editor would be a pleasure to use. However,
        the approach is doomed to niche status. There is a vast pile
        of exiting code in the world built around the 'ld' command, that
        reaches back to the 1970's. ld use is embedded in large and unknown
        numbers of makefiles, and is used by name by compilers that
        execute it. A Unix link-editor that is not named 'ld' will not find
        a majority audience no matter how good it might be.

        Finally, a new linker command will eventually cease to be
        new, and will accumulate its own burden of backward compatibility
        issues.

    An option to make 'ld' do the right things automatically

        This line of reasoning is best summarized by a CR filed
        in 2005, entitled

            6239804 make it easier for ld(1) to do what's best

        The idea is to have a '-z best' option that unchains ld from
        its backward compatibility commitment, and allows it to turn
        on the "best" set of features, as determined by the authors
        of 'ld'. The specific set of features enabled by -z best would
        be subject to change over time, as requirements change.

        This idea is more realistic than the other two, but has not been
        implemented to date because it has some significant issues.

            - The -z best proposal assumes that the user can turn it
              on, and trust it to select good options without the user
              needing to be aware of the options being applied. This is
              a fallacy. Features such as direct bindings require the
              user to do some analysis to ensure that the resulting
              program will still operate properly.

            - A user who is willing to do the work to know what -z best
              does is capable of turning on those features directly,
              and therefore gains little benefit from -z best.

            - The intent is that when a user opts into -z best, that
              they understand that z best is subject to sometimes
              incompatible evolution. Experience teaches us that
              this won't work. People will use this feature, the meaning
              of -z best will change, code that used to build will fail,
              and then there will be complaints and demands to retract
              the change. When (not if) this occurs, we will of course
              defend our actions, and point at the disclaimer. We'll win
              some of those debates, and lose others. Ultimately, we'll
              end up with -z best2 (-z better), or other compromises, and
              our goal of simplifying the world will have failed.

            - The -z best idea rolls up a set of features that
              may or may not be related to each other into a unit
              that must be taken wholesale, or not at all. It could
              be that only a subset of what it does is compatible
              with a given application, in which case the user is expected
              to abandon -z best and instead set the options that apply to
              their application directly. In doing so, they lose one of
              the benefits of -z best, that if you use it, future versions
              of ld may choose a different set of options, and automatically
              improve the object through the act of rebuilding it.

I draw two conclusions from the above history:

    (1) For a link-editor, backward compatibility is vital. If
        a given command line linked your application 10 years ago,
        you have every reason to expect that it will link today,
        assuming that the libraries you're linking against are still
        available and compatible with their previous interfaces.

    (2) For an application of any size or complexity, there is no
        substitute for the work involved in examining the code and
        determining which linker options apply and which do not.
        These options are largely orthogonal to each other, and
        there are reasonable reasons not to use any or all of them,
        even in modern applications. It is a mistake to tie them
        together.

The idea for -z guidance came from consideration of these points.
By decoupling the advice from the act of taking the advice, we can
retain the good aspects of -z best while avoiding its pitfalls:

    - -z guidance gives advice, but the decision to take that advice
      remains with the user who must evaluate its merit and make
      a decision to take it or not. As such, we are free to change
      the specific guidance given in future releases of ld, without
      breaking existing applications. The only fallout from this will
      be some new warnings in the build output, which can be ignored
      or dealt with at the user's convenience.

    - It does not couple the various features given into a single
      "take it or leave it" option, meaning that there will be no
      need to offer "-zguidance2", or other such variants when
      things change over time.

    - The user is given the flexibility to disable specific
      categories of guidance without losing the benefit of
      others, including those that might be added to future
      versions of the system.

Although -z fatal-warnings stands on its own as a useful feature,
it is of particular interest in combination with -z guidance.
Used together, the guidance turns from advice to hard requirement: The
user must either make the suggested change, or explicitly reject
the advice, in order to get a build. This is valuable in environments
with high coding standards. In addition, it gains us an additional
point of compatibility with the GNU link-editor.
_______________________________________________
opensolaris-arc mailing list
opensolaris-arc@opensolaris.org

Reply via email to