#endif
 #endif
 
+/*
+ * Some symbol definitions will not exist yet during the first pass of the
+ * link, but are guaranteed to exist in the final link. Provide preliminary
+ * definitions that will be superseded in the final link to avoid having to
+ * rely on weak external linkage, which requires a GOT when used in position
+ * independent code.
+ */
+#define PRELIMINARY_SYMBOL_DEFINITIONS                                 \
+       PROVIDE(kallsyms_addresses = .);                                \
+       PROVIDE(kallsyms_offsets = .);                                  \
+       PROVIDE(kallsyms_names = .);                                    \
+       PROVIDE(kallsyms_num_syms = .);                                 \
+       PROVIDE(kallsyms_relative_base = .);                            \
+       PROVIDE(kallsyms_token_table = .);                              \
+       PROVIDE(kallsyms_token_index = .);                              \
+       PROVIDE(kallsyms_markers = .);                                  \
+       PROVIDE(kallsyms_seqs_of_names = .);
+
 /*
  * Read only Data
  */
 #define RO_DATA(align)                                                 \
        . = ALIGN((align));                                             \
+       PRELIMINARY_SYMBOL_DEFINITIONS                                  \
        .rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {           \
                __start_rodata = .;                                     \
                *(.rodata) *(.rodata.*)                                 \
 
        unsigned long symbol_start = 0, symbol_end = 0;
        unsigned long i, low, high, mid;
 
-       /* This kernel should never had been booted. */
-       if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
-               BUG_ON(!kallsyms_addresses);
-       else
-               BUG_ON(!kallsyms_offsets);
-
        /* Do a binary search on the sorted kallsyms_addresses array. */
        low = 0;
        high = kallsyms_num_syms;
 
 #include <linux/types.h>
 
 /*
- * These will be re-linked against their real values
- * during the second link stage.
+ * These will be re-linked against their real values during the second link
+ * stage. Preliminary values must be provided in the linker script using the
+ * PROVIDE() directive so that the first link stage can complete successfully.
  */
-extern const unsigned long kallsyms_addresses[] __weak;
-extern const int kallsyms_offsets[] __weak;
-extern const u8 kallsyms_names[] __weak;
+extern const unsigned long kallsyms_addresses[];
+extern const int kallsyms_offsets[];
+extern const u8 kallsyms_names[];
 
-/*
- * Tell the compiler that the count isn't in the small data section if the arch
- * has one (eg: FRV).
- */
-extern const unsigned int kallsyms_num_syms
-__section(".rodata") __attribute__((weak));
-
-extern const unsigned long kallsyms_relative_base
-__section(".rodata") __attribute__((weak));
+extern const unsigned int kallsyms_num_syms;
+extern const unsigned long kallsyms_relative_base;
 
-extern const char kallsyms_token_table[] __weak;
-extern const u16 kallsyms_token_index[] __weak;
+extern const char kallsyms_token_table[];
+extern const u16 kallsyms_token_index[];
 
-extern const unsigned int kallsyms_markers[] __weak;
-extern const u8 kallsyms_seqs_of_names[] __weak;
+extern const unsigned int kallsyms_markers[];
+extern const u8 kallsyms_seqs_of_names[];
 
 #endif // LINUX_KALLSYMS_INTERNAL_H_