From 1df11ccceb1a5baea6fd27e2933e94fdeeb69e5f Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 2 Feb 2026 09:04:18 +0100 Subject: [PATCH] symbols: check table sizes don't change between linking passes 2 and 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While sizes (and possibly positions) of the symbol table related symbols (and as a result other ones) are expected to change from linking pass 1 to pass 2, no such change should happen anymore from pass 2 to pass 3, or else the internally recorded symbol table wouldn't represent the ELF or PE/COFF ones. For comparing to be actually useful, i.e. most notably also covering the last of the arrays emitted, symbol sizes need establishing. Make use of the xen/linkage.h machinery to achieve that. Suggested-by: Roger Pau Monné Signed-off-by: Jan Beulich Acked-by: Roger Pau Monné --- xen/arch/x86/Makefile | 3 ++ xen/scripts/Kbuild.include | 13 ++++++ xen/tools/symbols.c | 89 ++++++++++++++++++-------------------- 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 5bf3578983..477e3cbe7a 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -139,6 +139,7 @@ $(TARGET)-syms: $(objtree)/prelink.o $(obj)/xen.lds | $(objtree)/tools/symbols $(all_symbols) --sysv --sort $(syms-warn-dup-y) \ > $(dot-target).2.S $(MAKE) $(build)=$(@D) $(dot-target).2.o + $(call compare-symbol-tables, $(dot-target).1.o, $(dot-target).2.o) $(LD) $(XEN_LDFLAGS) -T $(obj)/xen.lds $< $(build_id_linker) \ $(orphan-handling-y) $(dot-target).2.o -o $@ $(NM) -pa --format=sysv $@ \ @@ -221,6 +222,8 @@ endif | $(objtree)/tools/symbols $(all_symbols) --sysv --sort \ > $(dot-target).2s.S $(MAKE) $(build)=$(@D) .$(@F).2r.o .$(@F).2s.o + $(call compare-symbol-tables, $(dot-target).1r.o, $(dot-target).2r.o) + $(call compare-symbol-tables, $(dot-target).1s.o, $(dot-target).2s.o) $(LD) $(call EFI_LDFLAGS,$(VIRT_BASE)) -T $(obj)/efi.lds $< \ $(dot-target).2r.o $(dot-target).2s.o $(orphan-handling-y) \ $(note_file_option) -o $@ diff --git a/xen/scripts/Kbuild.include b/xen/scripts/Kbuild.include index c2e4ec811b..d5e36e7f55 100644 --- a/xen/scripts/Kbuild.include +++ b/xen/scripts/Kbuild.include @@ -56,6 +56,19 @@ define filechk fi endef +### +# Compare the symbol tables of two object files. As diff's -I option isn't +# standardized, the name difference of the two object files needs abstracting +# out. +define compare-symbol-tables + ln -f $(1) $(@D)/.cst.$$$$; \ + $(OBJDUMP) -t $(@D)/.cst.$$$$ > $(1).sym; \ + ln -f $(2) $(@D)/.cst.$$$$; \ + $(OBJDUMP) -t $(@D)/.cst.$$$$ > $(2).sym; \ + rm -f $(@D)/.cst.$$$$ + diff -u $(1).sym $(2).sym +endef + # as-insn: Check whether assembler supports an instruction. # Usage: cflags-y += $(call as-insn,CC FLAGS,"insn",option-yes,option-no) as-insn = $(if $(shell echo 'void _(void) { asm volatile ( $(2) ); }' \ diff --git a/xen/tools/symbols.c b/xen/tools/symbols.c index 509394d5a4..7afe301d3c 100644 --- a/xen/tools/symbols.c +++ b/xen/tools/symbols.c @@ -260,17 +260,26 @@ static void read_map(FILE *in) } } -static void output_label(char *label) +static void output_label(const char *label, bool keep) { - if (symbol_prefix_char) - printf(".globl %c%s\n", symbol_prefix_char, label); - else - printf(".globl %s\n", label); - printf("\tALGN\n"); - if (symbol_prefix_char) - printf("%c%s:\n", symbol_prefix_char, label); - else - printf("%s:\n", label); + static bool pending; + + if (pending && !keep) { + printf("END(CURRENT)\n"); + printf("#undef CURRENT\n\n"); + } + + pending = label; + if (!label) + return; + + if (symbol_prefix_char) { + printf("DATA(%c%s, ALGN)\n", symbol_prefix_char, label); + printf("#define CURRENT %c%s\n", symbol_prefix_char, label); + } else { + printf("DATA(%s, ALGN)\n", label); + printf("#define CURRENT %s\n", label); + } } /* uncompress a compressed symbol. When this function is called, the best table @@ -338,22 +347,22 @@ static void write_src(void) return; } - printf("#include \n"); + printf("#include \n"); printf("#if BITS_PER_LONG == 64 && !defined(SYMBOLS_ORIGIN)\n"); printf("#define PTR .quad\n"); - printf("#define ALGN .balign 8\n"); + printf("#define ALGN 8\n"); printf("#else\n"); printf("#define PTR .long\n"); - printf("#define ALGN .balign 4\n"); + printf("#define ALGN 4\n"); printf("#endif\n"); printf("\t.section .rodata, \"a\"\n"); printf("#ifndef SYMBOLS_ORIGIN\n"); printf("#define SYMBOLS_ORIGIN 0\n"); - output_label("symbols_addresses"); + output_label("symbols_addresses", false); printf("#else\n"); - output_label("symbols_offsets"); + output_label("symbols_offsets", true); printf("#endif\n"); for (i = 0, ends = 0; i < table_cnt; i++) { printf("\tPTR\t%#llx - SYMBOLS_ORIGIN\n", table[i].addr); @@ -377,17 +386,15 @@ static void write_src(void) printf("\tPTR\t%#llx - SYMBOLS_ORIGIN\n", table[i].addr + table[i].size); } - printf("\n"); - output_label("symbols_num_addrs"); + output_label("symbols_num_addrs", false); printf("\t.long\t%d\n", table_cnt + ends); - printf("\n"); /* table of offset markers, that give the offset in the compressed stream * every 256 symbols */ markers = malloc(sizeof(*markers) * ((table_cnt + ends + 255) >> 8)); - output_label("symbols_names"); + output_label("symbols_names", false); for (i = 0, off = 0, ends = 0; i < table_cnt; i++) { if (((i + ends) & 0xFF) == 0) markers[(i + ends) >> 8] = off; @@ -411,15 +418,12 @@ static void write_src(void) printf("\t.byte 0\n"); ++off; } - printf("\n"); - output_label("symbols_markers"); + output_label("symbols_markers", false); for (i = 0; i < ((table_cnt + ends + 255) >> 8); i++) printf("\t.long\t%d\n", markers[i]); - printf("\n"); - - output_label("symbols_token_table"); + output_label("symbols_token_table", false); off = 0; for (i = 0; i < 256; i++) { best_idx[i] = off; @@ -427,34 +431,27 @@ static void write_src(void) printf("\t.asciz\t\"%s\"\n", buf); off += strlen(buf) + 1; } - printf("\n"); - output_label("symbols_token_index"); + output_label("symbols_token_index", false); for (i = 0; i < 256; i++) printf("\t.short\t%d\n", best_idx[i]); - printf("\n"); - if (!sort_by_name) { - free(markers); - return; + if (sort_by_name) { + output_label("symbols_num_names", false); + printf("\t.long\t%d\n", table_cnt); + + /* Sorted by original symbol names and type. */ + qsort(table, table_cnt, sizeof(*table), compare_name_orig); + + /* A fixed sized array with two entries: offset in the + * compressed stream (for symbol name), and offset in + * symbols_addresses (or symbols_offset). */ + output_label("symbols_sorted_offsets", false); + for (i = 0; i < table_cnt; i++) + printf("\t.long %u, %u\n", table[i].stream_offset, table[i].addr_idx); } - output_label("symbols_num_names"); - printf("\t.long\t%d\n", table_cnt); - printf("\n"); - - /* Sorted by original symbol names and type. */ - qsort(table, table_cnt, sizeof(*table), compare_name_orig); - - output_label("symbols_sorted_offsets"); - /* A fixed sized array with two entries: offset in the - * compressed stream (for symbol name), and offset in - * symbols_addresses (or symbols_offset). */ - for (i = 0; i < table_cnt; i++) { - printf("\t.long %u, %u\n", table[i].stream_offset, table[i].addr_idx); - } - printf("\n"); - + output_label(NULL, false); free(markers); }