]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[build] Formalise mechanism for accessing absolute symbols
authorMichael Brown <mcb30@ipxe.org>
Fri, 9 May 2025 13:25:59 +0000 (14:25 +0100)
committerMichael Brown <mcb30@ipxe.org>
Fri, 9 May 2025 14:14:03 +0000 (15:14 +0100)
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 <mcb30@ipxe.org>
src/arch/x86/include/librm.h
src/arch/x86/interface/pcbios/hidemem.c
src/arch/x86/interface/pxe/pxe_call.c
src/arch/x86/transitions/librm_mgmt.c
src/core/version.c
src/crypto/certstore.c
src/crypto/privkey.c
src/image/embedded.c
src/include/compiler.h

index cbe7d7134909904b256722bf927f3794fe435c73..55feeffc9c3e735af877a54881c2579077166df4 100644 (file)
@@ -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 );
index 6983c1f4aa3e2f0475b30d7023b4ef6a73946ded..4063c055160acfe49f5c7663fcf864a4528a8ff4 100644 (file)
@@ -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
index 2721d23e57b52da62634c7a3f9ef75bfe06a690a..a530f919f4b5aa23a061d349b59e312207395bef 100644 (file)
@@ -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 =
index 0328cb2a5111f980ba41c86f28278ff009e60aa0..77aecdb7d6122141ed4b20801f1c85443855ecb1 100644 (file)
@@ -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 );
index 22f4440652e5dd153d73e370552611b85c960623..cd69a8762fbe6fdcdff8887be132d55d36687bfb 100644 (file)
@@ -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;
index 86f67a0af817210f6bc7071d509ded4f34cba520..81179f9cc8205dfdd7699b68cc29f017754b215c 100644 (file)
@@ -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
index c15edf1304d9cc89d742026dd717ce3ccb2f141b..cbe8deff3afea75374f6bf6487db4bccbb86eed0 100644 (file)
@@ -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 ),
        },
 };
 
index 76d256c9b55d186f6bb4e1af17fe1b0f7b30e3b6..2934d4ee79511a8604d96e6095cbe91e2cd6e6d9 100644 (file)
@@ -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
index 5685ab1544680fbc2d914d4cb656dd0eca775f67..ec03f6f96455ee44ee45b499db7ac9002acef41b 100644 (file)
@@ -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
  *