From: Michael Brown Date: Fri, 9 May 2025 13:25:59 +0000 (+0100) Subject: [build] Formalise mechanism for accessing absolute symbols X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=134d76379e22d1554476cac3ef7baee14a3c27d3;p=thirdparty%2Fipxe.git [build] Formalise mechanism for accessing absolute symbols In a position-dependent executable, where all addresses are fixed at link time, we can use the standard technique as documented by GNU ld to get the value of an absolute symbol, e.g.: extern char _my_symbol[]; printf ( "Absolute symbol value is %x\n", ( ( int ) _my_symbol ) ); This technique may not work in a position-independent executable. When dynamic relocations are applied, the runtime addresses will no longer be equal to the link-time addresses. If the code to obtain the address of _my_symbol uses PC-relative addressing, then it will calculate the runtime "address" of the absolute symbol, which will no longer be equal the the link-time "address" (i.e. the correct value) of the absolute symbol. Define macros ABS_SYMBOL(), ABS_VALUE_INIT(), and ABS_VALUE() that provide access to the correct values of absolute symbols even in position-independent code, and use these macros wherever absolute symbols are accessed. Signed-off-by: Michael Brown --- diff --git a/src/arch/x86/include/librm.h b/src/arch/x86/include/librm.h index cbe7d7134..55feeffc9 100644 --- a/src/arch/x86/include/librm.h +++ b/src/arch/x86/include/librm.h @@ -365,7 +365,8 @@ extern char __text16_array ( sipi, [] ); #define sipi __use_text16 ( sipi ) /** Length of startup IPI real-mode handler */ -extern char sipi_len[]; +extern size_t ABS_SYMBOL ( sipi_len ); +#define sipi_len ABS_VALUE ( sipi_len ) /** Startup IPI real-mode handler copy of real-mode data segment */ extern uint16_t __text16 ( sipi_ds ); diff --git a/src/arch/x86/interface/pcbios/hidemem.c b/src/arch/x86/interface/pcbios/hidemem.c index 6983c1f4a..4063c0551 100644 --- a/src/arch/x86/interface/pcbios/hidemem.c +++ b/src/arch/x86/interface/pcbios/hidemem.c @@ -76,10 +76,10 @@ extern struct segoff __text16 ( int15_vector ); /* The linker defines these symbols for us */ extern char _textdata[]; extern char _etextdata[]; -extern char _text16_memsz[]; -#define _text16_memsz ( ( size_t ) _text16_memsz ) -extern char _data16_memsz[]; -#define _data16_memsz ( ( size_t ) _data16_memsz ) +extern size_t ABS_SYMBOL ( _text16_memsz ); +#define _text16_memsz ABS_VALUE ( _text16_memsz ) +extern size_t ABS_SYMBOL ( _data16_memsz ); +#define _data16_memsz ABS_VALUE ( _data16_memsz ) /** * Hide region of memory from system memory map diff --git a/src/arch/x86/interface/pxe/pxe_call.c b/src/arch/x86/interface/pxe/pxe_call.c index 2721d23e5..a530f919f 100644 --- a/src/arch/x86/interface/pxe/pxe_call.c +++ b/src/arch/x86/interface/pxe/pxe_call.c @@ -55,12 +55,12 @@ extern void pxe_int_1a ( void ); static int int_1a_hooked = 0; /** Real-mode code segment size */ -extern char _text16_memsz[]; -#define _text16_memsz ( ( size_t ) _text16_memsz ) +extern size_t ABS_SYMBOL ( _text16_memsz ); +#define _text16_memsz ABS_VALUE ( _text16_memsz ) /** Real-mode data segment size */ -extern char _data16_memsz[]; -#define _data16_memsz ( ( size_t ) _data16_memsz ) +extern size_t ABS_SYMBOL (_data16_memsz ); +#define _data16_memsz ABS_VALUE ( _data16_memsz ) /** PXENV_UNDI_TRANSMIT API call profiler */ static struct profiler pxe_api_tx_profiler __profiler = diff --git a/src/arch/x86/transitions/librm_mgmt.c b/src/arch/x86/transitions/librm_mgmt.c index 0328cb2a5..77aecdb7d 100644 --- a/src/arch/x86/transitions/librm_mgmt.c +++ b/src/arch/x86/transitions/librm_mgmt.c @@ -426,7 +426,7 @@ void setup_sipi ( unsigned int vector, uint32_t handler, memcpy ( &sipi_regs, regs, sizeof ( sipi_regs ) ); /* Copy real-mode handler */ - copy_to_real ( ( vector << 8 ), 0, sipi, ( ( size_t ) sipi_len ) ); + copy_to_real ( ( vector << 8 ), 0, sipi, sipi_len ); } PROVIDE_IOMAP_INLINE ( pages, io_to_bus ); diff --git a/src/core/version.c b/src/core/version.c index 22f444065..cd69a8762 100644 --- a/src/core/version.c +++ b/src/core/version.c @@ -49,16 +49,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); FEATURE_VERSION ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH ); /** Build timestamp (generated by linker) */ -extern char _build_timestamp[]; +extern unsigned long ABS_SYMBOL ( _build_timestamp ); /** Build ID (generated by linker) */ -extern char _build_id[]; +extern unsigned long ABS_SYMBOL ( _build_id ); /** Build timestamp */ -unsigned long build_timestamp = ( ( unsigned long ) _build_timestamp ); +unsigned long build_timestamp = ABS_VALUE_INIT ( _build_timestamp ); /** Build ID */ -unsigned long build_id = ( ( unsigned long ) _build_id ); +unsigned long build_id = ABS_VALUE_INIT ( _build_id ); /** Product major version */ const int product_major_version = VERSION_MAJOR; diff --git a/src/crypto/certstore.c b/src/crypto/certstore.c index 86f67a0af..81179f9cc 100644 --- a/src/crypto/certstore.c +++ b/src/crypto/certstore.c @@ -44,7 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #undef CERT #define CERT( _index, _path ) \ extern char stored_cert_ ## _index ## _data[]; \ - extern char stored_cert_ ## _index ## _len[]; \ + extern size_t ABS_SYMBOL ( stored_cert_ ## _index ## _len ); \ __asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t" \ "\nstored_cert_" #_index "_data:\n\t" \ ".incbin \"" _path "\"\n\t" \ @@ -59,7 +59,7 @@ CERT_ALL #undef CERT #define CERT( _index, _path ) { \ .data = stored_cert_ ## _index ## _data, \ - .len = ( size_t ) stored_cert_ ## _index ## _len, \ + .len = ABS_VALUE_INIT ( stored_cert_ ## _index ## _len ), \ }, static struct asn1_cursor certstore_raw[] = { CERT_ALL diff --git a/src/crypto/privkey.c b/src/crypto/privkey.c index c15edf130..cbe8deff3 100644 --- a/src/crypto/privkey.c +++ b/src/crypto/privkey.c @@ -53,7 +53,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /* Raw private key data */ extern char private_key_data[]; -extern char private_key_len[]; +extern size_t ABS_SYMBOL ( private_key_len ); __asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" #ifdef PRIVATE_KEY @@ -68,7 +68,7 @@ struct private_key private_key = { .refcnt = REF_INIT ( ref_no_free ), .builder = { .data = private_key_data, - .len = ( ( size_t ) private_key_len ), + .len = ABS_VALUE_INIT ( private_key_len ), }, }; diff --git a/src/image/embedded.c b/src/image/embedded.c index 76d256c9b..2934d4ee7 100644 --- a/src/image/embedded.c +++ b/src/image/embedded.c @@ -16,7 +16,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #undef EMBED #define EMBED( _index, _path, _name ) \ extern char embedded_image_ ## _index ## _data[]; \ - extern char embedded_image_ ## _index ## _len[]; \ + extern size_t ABS_SYMBOL ( embedded_image_ ## _index ## _len ); \ __asm__ ( ".section \".data\", \"aw\", " PROGBITS "\n\t" \ "\nembedded_image_" #_index "_data:\n\t" \ ".incbin \"" _path "\"\n\t" \ @@ -34,7 +34,7 @@ EMBED_ALL .name = _name, \ .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ .rwdata = embedded_image_ ## _index ## _data, \ - .len = ( size_t ) embedded_image_ ## _index ## _len, \ + .len = ABS_VALUE_INIT ( embedded_image_ ## _index ## _len ), \ }, static struct image embedded_images[] = { EMBED_ALL diff --git a/src/include/compiler.h b/src/include/compiler.h index 5685ab154..ec03f6f96 100644 --- a/src/include/compiler.h +++ b/src/include/compiler.h @@ -662,6 +662,97 @@ char __debug_disable(OBJECT) = ( DBGLVL_MAX & ~DBGLVL_DFLT ); #define ARRAY_SIZE(array) ( sizeof (array) / sizeof ( (array)[0] ) ) #endif /* ASSEMBLY */ +/** @defgroup abs Absolute symbols + * @{ + */ +#ifndef ASSEMBLY + +/** Declare an absolute symbol (e.g. a value defined by a linker script) + * + * Use as e.g.: + * + * extern int ABS_SYMBOL ( _my_symbol ); + * + */ +#define ABS_SYMBOL( name ) name[] + +/** Get value of an absolute symbol for use in a static initializer + * + * Use as e.g.: + * + * extern int ABS_SYMBOL ( _my_symbol ); + * static int my_symbol = ABS_VALUE_INIT ( _my_symbol ); + * + * Note that the declared type must be at least as large as a pointer + * type, since the compiler sees the absolute symbol as being an + * address. + */ +#define ABS_VALUE_INIT( name ) ( ( typeof ( name[0] ) ) name ) + +/** Get value of an absolute symbol + * + * In a position-dependent executable, where all addresses are fixed + * at link time, we can use the standard technique as documented by + * GNU ld, e.g.: + * + * extern char _my_symbol[]; + * + * printf ( "Absolute symbol value is %x\n", ( ( int ) _my_symbol ) ); + * + * This technique may not work in a position-independent executable. + * When dynamic relocations are applied, the runtime addresses will no + * longer be equal to the link-time addresses. If the code to obtain + * the address of _my_symbol uses PC-relative addressing, then it + * will calculate the runtime "address" of the absolute symbol, which + * will no longer be equal the the link-time "address" (i.e. the + * correct value) of the absolute symbol. + * + * We can work around this by instead declaring a static variable to + * contain the absolute value, and returning the contents of this + * static variable: + * + * extern char _my_symbol[]; + * static void * volatile my_symbol = _my_symbol; + * + * printf ( "Absolute symbol value is %x\n", ( ( int ) my_symbol ) ); + * + * The value of the static variable cannot possibly use PC-relative + * addressing (since there is no applicable program counter for + * non-code), and so will instead be filled in with the correct + * absolute value at link time. (No dynamic relocation will be + * generated that might change its value, since the symbol providing + * the value is an absolute symbol.) + * + * This second technique will work for both position-dependent and + * position-independent code, but incurs the unnecssary overhead of an + * additional static variable in position-dependent code. The + * ABS_VALUE() macro abstracts away these differences, using the most + * efficient available technique. Use as e.g.: + * + * extern int ABS_SYMBOL ( _my_symbol ); + * #define my_symbol ABS_VALUE ( _my_symbol ) + * + * printf ( "Absolute symbol value is %x\n", my_symbol ); + * + * The ABS_VALUE() macro uses the (otherwise redundant) type declared + * on the ABS_SYMBOL() array to automatically determine the correct + * type for the ABS_VALUE() expression. + * + * Unlike ABS_VALUE_INIT(), there is no restriction that the type must + * be at least as large as a pointer type. + */ +#ifndef __pie__ +#define ABS_VALUE( name ) ( ( typeof ( name[0] ) ) ( intptr_t ) name ) +#else +#define ABS_VALUE( name ) ( { \ + static void * volatile static_ ## name = name; \ + ( ( typeof ( name[0] ) ) ( intptr_t ) static_ ## name ); \ + } ) +#endif + +#endif /* ASSEMBLY */ +/** @} */ + /** * @defgroup licences Licence declarations *