Skip to content
Permalink
Browse files
[build] Fix the REQUIRE_SYMBOL mechanism
At some point in the past few years, binutils became more aggressive
at removing unused symbols.  To function as a symbol requirement, a
relocation record must now be in a section marked with @progbits and
must not be in a section which gets discarded during the link (either
via --gc-sections or via /DISCARD/).

Update REQUIRE_SYMBOL() to generate relocation records meeting these
criteria.  To minimise the impact upon the final binary size, we use
existing symbols (specified via the REQUIRING_SYMBOL() macro) as the
relocation targets where possible.  We use R_386_NONE or R_X86_64_NONE
relocation types to prevent any actual unwanted relocation taking
place.  Where no suitable symbol exists for REQUIRING_SYMBOL() (such
as in config.c), the macro PROVIDE_REQUIRING_SYMBOL() can be used to
generate a one-byte-long symbol to act as the relocation target.

If there are versions of binutils for which this approach fails, then
the fallback will probably involve killing off REQUEST_SYMBOL(),
redefining REQUIRE_SYMBOL() to use the current definition of
REQUEST_SYMBOL(), and postprocessing the linked ELF file with
something along the lines of "nm -u | wc -l" to check that there are
no undefined symbols remaining.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Mar 5, 2015
1 parent 86ae6e6 commit fbc4ba4b4ed13cc86cb8fdea0bac6c3be0164ed5
Showing 37 changed files with 182 additions and 43 deletions.
@@ -3,6 +3,9 @@

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

/** Dummy relocation type */
#define RELOC_TYPE_NONE R_386_NONE

#ifndef ASSEMBLY

/** Declare a function with standard calling conventions */
@@ -346,6 +346,7 @@ int pxe_start_nbp ( void ) {
return 0;
}

REQUIRING_SYMBOL ( pxe_api_call );
REQUIRE_OBJECT ( pxe_preboot );
REQUIRE_OBJECT ( pxe_undi );
REQUIRE_OBJECT ( pxe_udp );
@@ -8,6 +8,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

/* Provide the PXENV_FILE_EXIT_HOOK API call */
REQUIRING_SYMBOL ( _kkkpxe_start )
REQUIRE_OBJECT ( pxe_exit_hook )

#define PXELOADER_KEEP_UNDI
@@ -875,5 +875,8 @@ wait_for_tick:
ret
.size wait_for_tick, . - wait_for_tick

/* Drag in objects via _rom_start */
REQUIRING_SYMBOL ( _rom_start )

/* Drag in ROM configuration */
REQUIRE_OBJECT ( config_romprefix )
@@ -118,4 +118,5 @@ struct self_test librm_test __self_test = {
.exec = librm_test_exec,
};

REQUIRING_SYMBOL ( librm_test );
REQUIRE_OBJECT ( test );
@@ -590,5 +590,8 @@ struct root_device hv_root_device __root_device = {
.driver = &hv_root_driver,
};

/* Drag in objects via hv_root_device */
REQUIRING_SYMBOL ( hv_root_device );

/* Drag in netvsc driver */
REQUIRE_OBJECT ( netvsc );
@@ -496,5 +496,8 @@ struct pci_driver hvm_driver __pci_driver = {
.remove = hvm_remove,
};

/* Drag in objects via hvm_driver */
REQUIRING_SYMBOL ( hvm_driver );

/* Drag in netfront driver */
REQUIRE_OBJECT ( netfront );
@@ -1,6 +1,9 @@
#ifndef _BITS_COMPILER_H
#define _BITS_COMPILER_H

/** Dummy relocation type */
#define RELOC_TYPE_NONE R_X86_64_NONE

#ifndef ASSEMBLY

/** Declare a function with standard calling conventions */
@@ -44,6 +44,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* in the final iPXE executable built.
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in all requested console types
*
@@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in Ethernet-specific protocols
*/
@@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in Fibre Channel-specific commands
*
@@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in Infiniband-specific protocols
*/
@@ -25,6 +25,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in 802.11-specific commands
*
@@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Provide UNDI loader if PXE stack is requested
*
@@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in routing management for relevant protocols
*
@@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in USB controllers
*/
@@ -1765,5 +1765,8 @@ int x509_validate_chain ( struct x509_chain *chain, time_t time,
return -EACCES_USELESS;
}

/* Drag in objects via x509_validate() */
REQUIRING_SYMBOL ( x509_validate );

/* Drag in certificate store */
REQUIRE_OBJECT ( certstore );
@@ -1903,6 +1903,9 @@ struct usb_port * usb_root_hub_port ( struct usb_device *usb ) {
return usb->port;
}

/* Drag in objects via register_usb_bus() */
REQUIRING_SYMBOL ( register_usb_bus );

/* Drag in USB configuration */
REQUIRE_OBJECT ( config_usb );

@@ -4,6 +4,7 @@ FILE_LICENCE(GPL2_OR_LATER);

#include <ipxe/pci.h>

PROVIDE_REQUIRING_SYMBOL();
REQUIRE_OBJECT(rtl818x);
REQUIRE_OBJECT(rtl8180_grf5101);
REQUIRE_OBJECT(rtl8180_max2820);
@@ -4,6 +4,7 @@ FILE_LICENCE(GPL2_OR_LATER);

#include <ipxe/pci.h>

PROVIDE_REQUIRING_SYMBOL();
REQUIRE_OBJECT(rtl818x);
REQUIRE_OBJECT(rtl8185_rtl8225);

@@ -9,6 +9,7 @@ FILE_LICENCE(GPL2_OR_LATER);

#include <ipxe/pci.h>

PROVIDE_REQUIRING_SYMBOL();
REQUIRE_OBJECT(vxge_main);

/** vxge PCI IDs for util/parserom.pl which are put into bin/NIC */
@@ -173,6 +173,9 @@ struct command image_trust_commands[] __command = {
},
};

/* Drag in objects via command list */
REQUIRING_SYMBOL ( image_trust_commands );

/* Drag in objects typically required for signature verification */
REQUIRE_OBJECT ( rsa );
REQUIRE_OBJECT ( md5 );
@@ -57,54 +57,101 @@
* @{
*/

/** Provide a symbol within this object file */
/**
* Provide a symbol within this object file
*
* @v symbol Symbol name
*/
#ifdef ASSEMBLY
#define PROVIDE_SYMBOL( _sym ) \
.section ".provided", "a", @nobits ; \
.hidden _sym ; \
.globl _sym ; \
_sym: ; \
#define PROVIDE_SYMBOL( symbol ) \
.section ".provided", "a", @nobits ; \
.hidden symbol ; \
.globl symbol ; \
symbol: ; \
.previous
#else /* ASSEMBLY */
#define PROVIDE_SYMBOL( _sym ) \
char _sym[0] \
#else
#define PROVIDE_SYMBOL( symbol ) \
char symbol[0] \
__attribute__ (( section ( ".provided" ) ))
#endif /* ASSEMBLY */
#endif

/** Require a symbol within this object file
/**
* Request a symbol
*
* @v symbol Symbol name
*
* The symbol is referenced by a relocation in a discarded section, so
* if it is not available at link time the link will fail.
* Request a symbol to be included within the link. If the symbol
* cannot be found, the link will succeed anyway.
*/
#ifdef ASSEMBLY
#define REQUIRE_SYMBOL( _sym ) \
.section ".discard", "a", @progbits ; \
.extern _sym ; \
.long _sym ; \
.previous
#else /* ASSEMBLY */
#define REQUIRE_SYMBOL( _sym ) \
extern char _sym; \
static char * _C2 ( _C2 ( __require_, _sym ), _C2 ( _, __LINE__ ) ) \
__attribute__ (( section ( ".discard" ), used )) \
= &_sym
#define REQUEST_SYMBOL( symbol ) \
.equ __request_ ## symbol, symbol
#else
#define REQUEST_SYMBOL( symbol ) \
__asm__ ( ".equ __request_" #symbol ", " #symbol )
#endif

/** Request that a symbol be available at runtime
/**
* Require a symbol
*
* The requested symbol is entered as undefined into the symbol table
* for this object, so the linker will pull in other object files as
* necessary to satisfy the reference. However, the undefined symbol
* is not referenced in any relocations, so the link can still succeed
* if no file contains it.
* @v symbol Symbol name
*
* Require a symbol to be included within the link. If the symbol
* cannot be found, the link will fail.
*
* To use this macro within a file, you must also specify the file's
* "requiring symbol" using the REQUIRING_SYMBOL() or
* PROVIDE_REQUIRING_SYMBOL() macros.
*/
#ifdef ASSEMBLY
#define REQUEST_SYMBOL( _sym ) \
.equ __need_ ## _sym, _sym
#else /* ASSEMBLY */
#define REQUEST_SYMBOL( _sym ) \
__asm__ ( ".equ\t__need_" #_sym ", " #_sym )
#endif /* ASSEMBLY */
#define REQUIRE_SYMBOL( symbol ) \
.reloc __requiring_symbol__, RELOC_TYPE_NONE, symbol
#else
#define REQUIRE_SYMBOL( symbol ) \
__asm__ ( ".reloc __requiring_symbol__, " \
_S2 ( RELOC_TYPE_NONE ) ", " #symbol )
#endif

/**
* Specify the file's requiring symbol
*
* @v symbol Symbol name
*
* REQUIRE_SYMBOL() works by defining a dummy relocation record
* against a nominated "requiring symbol". The presence of the
* nominated requiring symbol will drag in all of the symbols
* specified using REQUIRE_SYMBOL().
*/
#ifdef ASSEMBLY
#define REQUIRING_SYMBOL( symbol ) \
.equ __requiring_symbol__, symbol
#else
#define REQUIRING_SYMBOL( symbol ) \
__asm__ ( ".equ __requiring_symbol__, " #symbol )
#endif

/**
* Provide a file's requiring symbol
*
* If the file contains no symbols that can be used as the requiring
* symbol, you can provide a dummy one-byte-long symbol using
* PROVIDE_REQUIRING_SYMBOL().
*/
#ifdef ASSEMBLY
#define PROVIDE_REQUIRING_SYMBOL() \
.section ".tbl.requiring_symbols", "a", @progbits ; \
__requiring_symbol__: .byte 0 ; \
.size __requiring_symbol__, . - __requiring_symbol__ ; \
.previous
#else
#define PROVIDE_REQUIRING_SYMBOL() \
__asm__ ( ".section \".tbl.requiring_symbols\", " \
" \"a\", @progbits\n" \
"__requiring_symbol__:\t.byte 0\n" \
".size __requiring_symbol__, " \
" . - __requiring_symbol__\n" \
".previous" )
#endif

/** @} */

@@ -119,11 +166,29 @@
/** Always provide the symbol for the current object (defined by -DOBJECT) */
PROVIDE_SYMBOL ( OBJECT_SYMBOL );

/** Explicitly require another object */
#define REQUIRE_OBJECT( _obj ) REQUIRE_SYMBOL ( obj_ ## _obj )
/**
* Request an object
*
* @v object Object name
*
* Request an object to be included within the link. If the object
* cannot be found, the link will succeed anyway.
*/
#define REQUEST_OBJECT( object ) REQUEST_SYMBOL ( obj_ ## object )

/** Pull in another object if it exists */
#define REQUEST_OBJECT( _obj ) REQUEST_SYMBOL ( obj_ ## _obj )
/**
* Require an object
*
* @v object Object name
*
* Require an object to be included within the link. If the object
* cannot be found, the link will fail.
*
* To use this macro within a file, you must also specify the file's
* "requiring symbol" using the REQUIRING_SYMBOL() or
* PROVIDE_REQUIRING_SYMBOL() macros.
*/
#define REQUIRE_OBJECT( object ) REQUIRE_SYMBOL ( obj_ ## object )

/** @} */

@@ -685,8 +750,8 @@ int __debug_disable;

/** @} */

/* This file itself is under GPLv2-or-later */
FILE_LICENCE ( GPL2_OR_LATER );
/* This file itself is under GPLv2+/UBDL */
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <bits/compiler.h>

@@ -276,6 +276,7 @@ static inline void * legacy_isa_get_drvdata ( void *hwdev ) {
_name ## _isa_legacy_remove ( struct isa_device *isa ) { \
return legacy_remove ( isa, legacy_isa_get_drvdata, \
_name ## _disable ); \
}
} \
PROVIDE_REQUIRING_SYMBOL()

#endif /* NIC_H */
@@ -2827,5 +2827,8 @@ struct errortab common_wireless_errors[] __errortab = {
__einfo_errortab ( EINFO_ECONNREFUSED_AUTH_ALGO_UNSUPP ),
};

/* Drag in objects via net80211_ll_protocol */
REQUIRING_SYMBOL ( net80211_ll_protocol );

/* Drag in 802.11 configuration */
REQUIRE_OBJECT ( config_net80211 );

0 comments on commit fbc4ba4

Please sign in to comment.