david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[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>
This commit is contained in:
Michael Brown 2015-03-04 18:48:19 +00:00
parent 86ae6e6c18
commit fbc4ba4b4e
37 changed files with 185 additions and 46 deletions

View File

@ -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 */

View File

@ -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 );

View File

@ -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

View File

@ -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 )

View File

@ -118,4 +118,5 @@ struct self_test librm_test __self_test = {
.exec = librm_test_exec,
};
REQUIRING_SYMBOL ( librm_test );
REQUIRE_OBJECT ( test );

View File

@ -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 );

View File

@ -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 );

View File

@ -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 */

View File

@ -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
*

View File

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

View File

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

View File

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

View File

@ -25,6 +25,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
PROVIDE_REQUIRING_SYMBOL();
/*
* Drag in 802.11-specific commands
*

View File

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

View File

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

View File

@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
PROVIDE_REQUIRING_SYMBOL();
/*
* Drag in USB controllers
*/

View File

@ -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 );

View File

@ -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 );

View File

@ -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);

View File

@ -4,6 +4,7 @@ FILE_LICENCE(GPL2_OR_LATER);
#include <ipxe/pci.h>
PROVIDE_REQUIRING_SYMBOL();
REQUIRE_OBJECT(rtl818x);
REQUIRE_OBJECT(rtl8185_rtl8225);

View File

@ -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 */

View File

@ -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 );

View File

@ -57,54 +57,101 @@
* @{
*/
/** Provide a symbol within this object file */
#ifdef ASSEMBLY
#define PROVIDE_SYMBOL( _sym ) \
.section ".provided", "a", @nobits ; \
.hidden _sym ; \
.globl _sym ; \
_sym: ; \
.previous
#else /* ASSEMBLY */
#define PROVIDE_SYMBOL( _sym ) \
char _sym[0] \
__attribute__ (( section ( ".provided" ) ))
#endif /* ASSEMBLY */
/** Require a symbol within this object file
/**
* Provide a symbol within this object file
*
* The symbol is referenced by a relocation in a discarded section, so
* if it is not available at link time the link will fail.
* @v symbol Symbol name
*/
#ifdef ASSEMBLY
#define REQUIRE_SYMBOL( _sym ) \
.section ".discard", "a", @progbits ; \
.extern _sym ; \
.long _sym ; \
#define PROVIDE_SYMBOL( symbol ) \
.section ".provided", "a", @nobits ; \
.hidden symbol ; \
.globl symbol ; \
symbol: ; \
.previous
#else /* ASSEMBLY */
#define REQUIRE_SYMBOL( _sym ) \
extern char _sym; \
static char * _C2 ( _C2 ( __require_, _sym ), _C2 ( _, __LINE__ ) ) \
__attribute__ (( section ( ".discard" ), used )) \
= &_sym
#else
#define PROVIDE_SYMBOL( symbol ) \
char symbol[0] \
__attribute__ (( section ( ".provided" ) ))
#endif
/** Request that a symbol be available at runtime
/**
* Request 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
*
* Request a symbol to be included within the link. If the symbol
* cannot be found, the link will succeed anyway.
*/
#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 REQUEST_SYMBOL( symbol ) \
.equ __request_ ## symbol, symbol
#else
#define REQUEST_SYMBOL( symbol ) \
__asm__ ( ".equ __request_" #symbol ", " #symbol )
#endif
/**
* Require a symbol
*
* @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 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>

View File

@ -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 */

View File

@ -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 );

View File

@ -912,4 +912,5 @@ struct eapol_handler eapol_key_handler __eapol_handler = {
};
/* WPA always needs EAPOL in order to be useful */
REQUIRING_SYMBOL ( eapol_key_handler );
REQUIRE_OBJECT ( eapol );

View File

@ -239,6 +239,9 @@ struct net_device * alloc_etherdev ( size_t priv_size ) {
return netdev;
}
/* Drag in objects via ethernet_protocol */
REQUIRING_SYMBOL ( ethernet_protocol );
/* Drag in Ethernet configuration */
REQUIRE_OBJECT ( config_ethernet );

View File

@ -1940,5 +1940,8 @@ struct fc_ulp * fc_ulp_get_port_id_type ( struct fc_port *port,
return NULL;
}
/* Drag in objects via fc_ports */
REQUIRING_SYMBOL ( fc_ports );
/* Drag in Fibre Channel configuration */
REQUIRE_OBJECT ( config_fc );

View File

@ -999,6 +999,9 @@ struct ib_device * last_opened_ibdev ( void ) {
return ibdev;
}
/* Drag in objects via register_ibdev() */
REQUIRING_SYMBOL ( register_ibdev );
/* Drag in Infiniband configuration */
REQUIRE_OBJECT ( config_infiniband );

View File

@ -841,5 +841,8 @@ struct settings_applicator ipv4_settings_applicator __settings_applicator = {
.apply = ipv4_create_routes,
};
/* Drag in objects via ipv4_protocol */
REQUIRING_SYMBOL ( ipv4_protocol );
/* Drag in ICMPv4 */
REQUIRE_OBJECT ( icmpv4 );

View File

@ -1104,6 +1104,9 @@ struct net_driver ipv6_driver __net_driver = {
.remove = ipv6_remove,
};
/* Drag in objects via ipv6_protocol */
REQUIRING_SYMBOL ( ipv6_protocol );
/* Drag in ICMPv6 */
REQUIRE_OBJECT ( icmpv6 );

View File

@ -1474,6 +1474,7 @@ struct self_test cms_test __self_test = {
};
/* Drag in algorithms required for tests */
REQUIRING_SYMBOL ( cms_test );
REQUIRE_OBJECT ( rsa );
REQUIRE_OBJECT ( md5 );
REQUIRE_OBJECT ( sha1 );

View File

@ -1861,5 +1861,6 @@ struct self_test ocsp_test __self_test = {
};
/* Drag in algorithms required for tests */
REQUIRING_SYMBOL ( ocsp_test );
REQUIRE_OBJECT ( rsa );
REQUIRE_OBJECT ( sha1 );

View File

@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
/* Drag in all applicable self-tests */
PROVIDE_REQUIRING_SYMBOL();
REQUIRE_OBJECT ( memset_test );
REQUIRE_OBJECT ( memcpy_test );
REQUIRE_OBJECT ( string_test );

View File

@ -1109,6 +1109,7 @@ struct self_test x509_test __self_test = {
};
/* Drag in algorithms required for tests */
REQUIRING_SYMBOL ( x509_test );
REQUIRE_OBJECT ( rsa );
REQUIRE_OBJECT ( sha1 );
REQUIRE_OBJECT ( sha256 );

View File

@ -48,4 +48,5 @@ void route ( void ) {
}
/* Drag in routing management configuration */
REQUIRING_SYMBOL ( route );
REQUIRE_OBJECT ( config_route );

View File

@ -478,6 +478,9 @@ static void process_reloc ( bfd *bfd __attribute__ (( unused )),
/* Skip absolute symbols; the symbol value won't
* change when the object is loaded.
*/
} else if ( ( strcmp ( howto->name, "R_386_NONE" ) == 0 ) ||
( strcmp ( howto->name, "R_X86_64_NONE" ) == 0 ) ) {
/* Ignore dummy relocations used by REQUIRE_SYMBOL() */
} else if ( strcmp ( howto->name, "R_X86_64_64" ) == 0 ) {
/* Generate an 8-byte PE relocation */
generate_pe_reloc ( pe_reltab, offset, 8 );