Skip to content

Commit

Permalink
[build] Fix the REQUIRE_SYMBOL mechanism
Browse files Browse the repository at this point in the history
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 fbc4ba4
Show file tree
Hide file tree
Showing 37 changed files with 182 additions and 43 deletions.
3 changes: 3 additions & 0 deletions src/arch/i386/include/bits/compiler.h
Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions src/arch/i386/interface/pxe/pxe_call.c
Expand Up @@ -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 );
Expand Down
1 change: 1 addition & 0 deletions src/arch/i386/prefix/kkkpxeprefix.S
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/arch/i386/prefix/romprefix.S
Expand Up @@ -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 )
1 change: 1 addition & 0 deletions src/arch/i386/transitions/librm_test.c
Expand Up @@ -118,4 +118,5 @@ struct self_test librm_test __self_test = {
.exec = librm_test_exec,
};

REQUIRING_SYMBOL ( librm_test );
REQUIRE_OBJECT ( test );
3 changes: 3 additions & 0 deletions src/arch/x86/drivers/hyperv/hyperv.c
Expand Up @@ -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 );
3 changes: 3 additions & 0 deletions src/arch/x86/drivers/xen/hvm.c
Expand Up @@ -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 );
3 changes: 3 additions & 0 deletions src/arch/x86_64/include/bits/compiler.h
@@ -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 */
Expand Down
2 changes: 2 additions & 0 deletions src/config/config.c
Expand Up @@ -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
*
Expand Down
2 changes: 2 additions & 0 deletions src/config/config_ethernet.c
Expand Up @@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in Ethernet-specific protocols
*/
Expand Down
2 changes: 2 additions & 0 deletions src/config/config_fc.c
Expand Up @@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in Fibre Channel-specific commands
*
Expand Down
2 changes: 2 additions & 0 deletions src/config/config_infiniband.c
Expand Up @@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in Infiniband-specific protocols
*/
Expand Down
2 changes: 2 additions & 0 deletions src/config/config_net80211.c
Expand Up @@ -25,6 +25,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in 802.11-specific commands
*
Expand Down
2 changes: 2 additions & 0 deletions src/config/config_romprefix.c
Expand Up @@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Provide UNDI loader if PXE stack is requested
*
Expand Down
2 changes: 2 additions & 0 deletions src/config/config_route.c
Expand Up @@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in routing management for relevant protocols
*
Expand Down
2 changes: 2 additions & 0 deletions src/config/config_usb.c
Expand Up @@ -29,6 +29,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/

PROVIDE_REQUIRING_SYMBOL();

/*
* Drag in USB controllers
*/
Expand Down
3 changes: 3 additions & 0 deletions src/crypto/x509.c
Expand Up @@ -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 );
3 changes: 3 additions & 0 deletions src/drivers/bus/usb.c
Expand Up @@ -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 );

Expand Down
1 change: 1 addition & 0 deletions src/drivers/net/rtl818x/rtl8180.c
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/drivers/net/rtl818x/rtl8185.c
Expand Up @@ -4,6 +4,7 @@ FILE_LICENCE(GPL2_OR_LATER);

#include <ipxe/pci.h>

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

Expand Down
1 change: 1 addition & 0 deletions src/drivers/net/vxge/vxge.c
Expand Up @@ -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 */
Expand Down
3 changes: 3 additions & 0 deletions src/hci/commands/image_trust_cmd.c
Expand Up @@ -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 );
Expand Down
149 changes: 107 additions & 42 deletions src/include/compiler.h
Expand Up @@ -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

/** @} */

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

/** @} */

Expand Down Expand Up @@ -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>

Expand Down
3 changes: 2 additions & 1 deletion src/include/nic.h
Expand Up @@ -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 */
3 changes: 3 additions & 0 deletions src/net/80211/net80211.c
Expand Up @@ -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.