Merge branch '2022-06-23-fuzzing-and-asan-for-sandbox' into next

To quote the author:
This series introduces ASAN and a basic fuzzing infrastructure that
works with sandbox. The example fuzz test towards the end of the series
will find something pretty quickly. That something is fixed by the
series "virtio: Harden and test vring" that needs to be applied for the
final patch in this series.

There is some refactoring to stop using '.' prefixed sections. ELF
defines sections with names that contain anything that isn't
alphanumeric or an underscore as being for system use which means
clang's ASAN instrumentation happily add redzones between the contained
objects. That's not what we want for things like linker lists where the
linker script has carefully placed the sections contiguously. By
renaming the sections, clang sees them as user sections and doesn't add
instrumentation.

ASAN is left disabled by default as there are still some tests that it
triggers on and will need some more investigation to fix. It can be
enabled with CONFIG_ASAN or passing `-a ASAN` to buildman.
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml
index ad540ea..915d511 100644
--- a/.azure-pipelines.yml
+++ b/.azure-pipelines.yml
@@ -473,6 +473,12 @@
           BUILDMAN: "imx8"
         keystone2_keystone3:
           BUILDMAN: "k2 k3"
+        sandbox_asan:
+          BUILDMAN: "sandbox"
+          OVERRIDE: "-a ASAN"
+        sandbox_clang_asan:
+          BUILDMAN: "sandbox"
+          OVERRIDE: "-O clang-13 -a ASAN"
         samsung_socfpga:
           BUILDMAN: "samsung socfpga"
         sun4i:
diff --git a/Kconfig b/Kconfig
index 429b5f9..991b260 100644
--- a/Kconfig
+++ b/Kconfig
@@ -154,6 +154,22 @@
 	  Enabling this option will pass "--coverage" to gcc to compile
 	  and link code instrumented for coverage analysis.
 
+config ASAN
+	bool "Enable AddressSanitizer"
+	depends on SANDBOX
+	help
+	  Enables AddressSanitizer to discover out-of-bounds accesses,
+	  use-after-free, double-free and memory leaks.
+
+config FUZZ
+	bool "Enable fuzzing"
+	depends on CC_IS_CLANG
+	depends on DM_FUZZING_ENGINE
+	select ASAN
+	help
+	  Enables the fuzzing infrastructure to generate fuzzing data and run
+          fuzz tests.
+
 config CC_HAS_ASM_INLINE
 	def_bool $(success,echo 'void foo(void) { asm inline (""); }' | $(CC) -x c - -c -o /dev/null)
 
diff --git a/arch/Kconfig b/arch/Kconfig
index b396263..eab89f2 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -135,6 +135,7 @@
 	select BZIP2
 	select CMD_POWEROFF
 	select DM
+	select DM_FUZZING_ENGINE
 	select DM_GPIO
 	select DM_I2C
 	select DM_KEYBOARD
@@ -170,6 +171,7 @@
 	imply CRC32_VERIFY
 	imply FAT_WRITE
 	imply FIRMWARE
+	imply FUZZING_ENGINE_SANDBOX
 	imply HASH_VERIFY
 	imply LZMA
 	imply TEE
diff --git a/arch/arc/cpu/u-boot.lds b/arch/arc/cpu/u-boot.lds
index e12145c..9f2973d 100644
--- a/arch/arc/cpu/u-boot.lds
+++ b/arch/arc/cpu/u-boot.lds
@@ -39,8 +39,8 @@
 	}
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/arch/arm/config.mk b/arch/arm/config.mk
index b107b1a..b3548ce 100644
--- a/arch/arm/config.mk
+++ b/arch/arm/config.mk
@@ -141,11 +141,11 @@
 # limit ourselves to the sections we want in the .bin.
 ifdef CONFIG_ARM64
 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .data \
-		-j .u_boot_list -j .rela.dyn -j .got -j .got.plt \
+		-j __u_boot_list -j .rela.dyn -j .got -j .got.plt \
 		-j .binman_sym_table -j .text_rest
 else
 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .hash \
-		-j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn \
+		-j .data -j .got -j .got.plt -j __u_boot_list -j .rel.dyn \
 		-j .binman_sym_table -j .text_rest
 endif
 
diff --git a/arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds b/arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds
index 9a000ac..c108736 100644
--- a/arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds
+++ b/arch/arm/cpu/arm926ejs/sunxi/u-boot-spl.lds
@@ -29,8 +29,8 @@
 	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	} > .sram
 
 	. = ALIGN(4);
diff --git a/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds b/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds
index 942c29f..306a4dd 100644
--- a/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds
+++ b/arch/arm/cpu/armv7/sunxi/u-boot-spl.lds
@@ -38,8 +38,8 @@
 	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	} > .sram
 
 	. = ALIGN(4);
diff --git a/arch/arm/cpu/armv8/u-boot-spl.lds b/arch/arm/cpu/armv8/u-boot-spl.lds
index 730eb93..d02b788 100644
--- a/arch/arm/cpu/armv8/u-boot-spl.lds
+++ b/arch/arm/cpu/armv8/u-boot-spl.lds
@@ -46,9 +46,9 @@
 	} >.sram
 #endif
 
-	.u_boot_list : {
+	__u_boot_list : {
 		. = ALIGN(8);
-		KEEP(*(SORT(.u_boot_list*)));
+		KEEP(*(SORT(__u_boot_list*)));
 	} >.sram
 
 	.image_copy_end : {
diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds
index 2554980..8fe4682 100644
--- a/arch/arm/cpu/armv8/u-boot.lds
+++ b/arch/arm/cpu/armv8/u-boot.lds
@@ -109,8 +109,8 @@
 	. = .;
 
 	. = ALIGN(8);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(8);
diff --git a/arch/arm/cpu/u-boot-spl.lds b/arch/arm/cpu/u-boot-spl.lds
index 97899a5..fb2189d 100644
--- a/arch/arm/cpu/u-boot-spl.lds
+++ b/arch/arm/cpu/u-boot-spl.lds
@@ -32,8 +32,8 @@
 	}
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index 0eb164d..f25f72b 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -15,7 +15,7 @@
 SECTIONS
 {
 #ifndef CONFIG_CMDLINE
-	/DISCARD/ : { *(.u_boot_list_2_cmd_*) }
+	/DISCARD/ : { *(__u_boot_list_2_cmd_*) }
 #endif
 #if defined(CONFIG_ARMV7_SECURE_BASE) && defined(CONFIG_ARMV7_NONSEC)
 	/*
@@ -149,8 +149,8 @@
 	. = .;
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds b/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds
index 74f6355..1a8bf94 100644
--- a/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds
+++ b/arch/arm/mach-at91/arm926ejs/u-boot-spl.lds
@@ -29,7 +29,7 @@
 	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
 
 	. = ALIGN(4);
-	.u_boot_list : { KEEP(*(SORT(.u_boot_list*))) } > .sram
+	__u_boot_list : { KEEP(*(SORT(__u_boot_list*))) } > .sram
 
 	. = ALIGN(4);
 	__image_copy_end = .;
diff --git a/arch/arm/mach-at91/armv7/u-boot-spl.lds b/arch/arm/mach-at91/armv7/u-boot-spl.lds
index 950ea55..6ca725f 100644
--- a/arch/arm/mach-at91/armv7/u-boot-spl.lds
+++ b/arch/arm/mach-at91/armv7/u-boot-spl.lds
@@ -36,7 +36,7 @@
 	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
 
 	. = ALIGN(4);
-	.u_boot_list : { KEEP(*(SORT(.u_boot_list*))) } > .sram
+	__u_boot_list : { KEEP(*(SORT(__u_boot_list*))) } > .sram
 
 	. = ALIGN(4);
 	__image_copy_end = .;
diff --git a/arch/arm/mach-omap2/u-boot-spl.lds b/arch/arm/mach-omap2/u-boot-spl.lds
index 88d81f9..1d6e5d4 100644
--- a/arch/arm/mach-omap2/u-boot-spl.lds
+++ b/arch/arm/mach-omap2/u-boot-spl.lds
@@ -33,8 +33,8 @@
 	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	} >.sram
 
 	. = ALIGN(4);
diff --git a/arch/arm/mach-orion5x/u-boot-spl.lds b/arch/arm/mach-orion5x/u-boot-spl.lds
index a537fe0..154bb12 100644
--- a/arch/arm/mach-orion5x/u-boot-spl.lds
+++ b/arch/arm/mach-orion5x/u-boot-spl.lds
@@ -41,8 +41,8 @@
 	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.nor
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	} > .nor
 
 	. = ALIGN(4);
diff --git a/arch/arm/mach-rockchip/u-boot-tpl-v8.lds b/arch/arm/mach-rockchip/u-boot-tpl-v8.lds
index 9869972..74618eb 100644
--- a/arch/arm/mach-rockchip/u-boot-tpl-v8.lds
+++ b/arch/arm/mach-rockchip/u-boot-tpl-v8.lds
@@ -39,9 +39,9 @@
 		*(.data*)
 	}
 
-	.u_boot_list : {
+	__u_boot_list : {
 		. = ALIGN(8);
-		KEEP(*(SORT(.u_boot_list*)));
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	.image_copy_end : {
diff --git a/arch/arm/mach-zynq/u-boot-spl.lds b/arch/arm/mach-zynq/u-boot-spl.lds
index 106d2e3..8c18d3f 100644
--- a/arch/arm/mach-zynq/u-boot-spl.lds
+++ b/arch/arm/mach-zynq/u-boot-spl.lds
@@ -37,8 +37,8 @@
 	} > .sram
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	} > .sram
 
 	. = ALIGN(4);
diff --git a/arch/arm/mach-zynq/u-boot.lds b/arch/arm/mach-zynq/u-boot.lds
index 91c32e8..a5169fd 100644
--- a/arch/arm/mach-zynq/u-boot.lds
+++ b/arch/arm/mach-zynq/u-boot.lds
@@ -54,8 +54,8 @@
 	. = .;
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/arch/m68k/cpu/u-boot.lds b/arch/m68k/cpu/u-boot.lds
index affb2d9..133f791 100644
--- a/arch/m68k/cpu/u-boot.lds
+++ b/arch/m68k/cpu/u-boot.lds
@@ -60,8 +60,8 @@
 	. = .;
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = .;
diff --git a/arch/microblaze/cpu/u-boot-spl.lds b/arch/microblaze/cpu/u-boot-spl.lds
index 7883a64..4ac5a21 100644
--- a/arch/microblaze/cpu/u-boot-spl.lds
+++ b/arch/microblaze/cpu/u-boot-spl.lds
@@ -37,8 +37,8 @@
 	}
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 	__init_end = . ;
 
diff --git a/arch/microblaze/cpu/u-boot.lds b/arch/microblaze/cpu/u-boot.lds
index 2b316cc..8bd515b 100644
--- a/arch/microblaze/cpu/u-boot.lds
+++ b/arch/microblaze/cpu/u-boot.lds
@@ -41,8 +41,8 @@
 	}
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 	__init_end = . ;
 
diff --git a/arch/mips/config.mk b/arch/mips/config.mk
index faf4129..04f3627 100644
--- a/arch/mips/config.mk
+++ b/arch/mips/config.mk
@@ -65,6 +65,6 @@
 KBUILD_LDFLAGS			+= -G 0 -static -n -nostdlib
 PLATFORM_RELFLAGS		+= -ffunction-sections -fdata-sections
 LDFLAGS_FINAL			+= --gc-sections
-OBJCOPYFLAGS			+= -j .text -j .rodata -j .data -j .u_boot_list
+OBJCOPYFLAGS			+= -j .text -j .rodata -j .data -j __u_boot_list
 
 LDFLAGS_STANDALONE		+= --gc-sections
diff --git a/arch/mips/cpu/u-boot-spl.lds b/arch/mips/cpu/u-boot-spl.lds
index 28ea4f2..194398b 100644
--- a/arch/mips/cpu/u-boot-spl.lds
+++ b/arch/mips/cpu/u-boot-spl.lds
@@ -29,8 +29,8 @@
 
 #if defined(CONFIG_SPL_DM) || defined(CONFIG_SPL_LOADER_SUPPORT)
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	} > .spl_mem
 #endif
 
diff --git a/arch/mips/cpu/u-boot.lds b/arch/mips/cpu/u-boot.lds
index 8649673..9a4ebcd 100644
--- a/arch/mips/cpu/u-boot.lds
+++ b/arch/mips/cpu/u-boot.lds
@@ -33,8 +33,8 @@
 	}
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/arch/nios2/cpu/u-boot.lds b/arch/nios2/cpu/u-boot.lds
index cbf54b4..5b9e27d 100644
--- a/arch/nios2/cpu/u-boot.lds
+++ b/arch/nios2/cpu/u-boot.lds
@@ -32,8 +32,8 @@
 	 */
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	/* INIT DATA sections - "Small" data (see the gcc -G option)
diff --git a/arch/powerpc/cpu/mpc83xx/u-boot.lds b/arch/powerpc/cpu/mpc83xx/u-boot.lds
index d10f528..1a1e537 100644
--- a/arch/powerpc/cpu/mpc83xx/u-boot.lds
+++ b/arch/powerpc/cpu/mpc83xx/u-boot.lds
@@ -42,8 +42,8 @@
   . = .;
 
   . = ALIGN(4);
-  .u_boot_list : {
-	KEEP(*(SORT(.u_boot_list*)));
+  __u_boot_list : {
+	KEEP(*(SORT(__u_boot_list*)));
   }
 
 
diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds b/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds
index 1b4d1e0..06a70ff 100644
--- a/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds
+++ b/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds
@@ -50,8 +50,8 @@
 	_edata  =  .;
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = .;
diff --git a/arch/powerpc/cpu/mpc85xx/u-boot.lds b/arch/powerpc/cpu/mpc85xx/u-boot.lds
index e1bbee4..8bbe319 100644
--- a/arch/powerpc/cpu/mpc85xx/u-boot.lds
+++ b/arch/powerpc/cpu/mpc85xx/u-boot.lds
@@ -67,8 +67,8 @@
   . = .;
 
   . = ALIGN(4);
-  .u_boot_list : {
-	KEEP(*(SORT(.u_boot_list*)));
+  __u_boot_list : {
+	KEEP(*(SORT(__u_boot_list*)));
   }
 
   . = .;
diff --git a/arch/riscv/cpu/u-boot-spl.lds b/arch/riscv/cpu/u-boot-spl.lds
index d0495ce..9935363 100644
--- a/arch/riscv/cpu/u-boot-spl.lds
+++ b/arch/riscv/cpu/u-boot-spl.lds
@@ -40,8 +40,8 @@
 
 	. = ALIGN(4);
 
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	} > .spl_mem
 
 	. = ALIGN(4);
diff --git a/arch/riscv/cpu/u-boot.lds b/arch/riscv/cpu/u-boot.lds
index c00d17c..1c937ae 100644
--- a/arch/riscv/cpu/u-boot.lds
+++ b/arch/riscv/cpu/u-boot.lds
@@ -44,8 +44,8 @@
 
 	. = ALIGN(4);
 
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk
index 02a3ba0..3e2c7f9 100644
--- a/arch/sandbox/config.mk
+++ b/arch/sandbox/config.mk
@@ -15,8 +15,19 @@
 PLATFORM_CPPFLAGS += $(shell $(SDL_CONFIG) --cflags)
 endif
 
+SANITIZERS :=
+ifdef CONFIG_ASAN
+SANITIZERS	+= -fsanitize=address
+endif
+ifdef CONFIG_FUZZ
+SANITIZERS	+= -fsanitize=fuzzer
+endif
+KBUILD_CFLAGS	+= $(SANITIZERS)
+
 cmd_u-boot__ = $(CC) -o $@ -Wl,-T u-boot.lds $(u-boot-init) \
-	$(KBUILD_LDFLAGS:%=-Wl,%)$(LTO_FINAL_LDFLAGS) \
+	$(KBUILD_LDFLAGS:%=-Wl,%) \
+	$(SANITIZERS) \
+	$(LTO_FINAL_LDFLAGS) \
 	-Wl,--whole-archive \
 		$(u-boot-main) \
 		$(u-boot-keep-syms-lto) \
@@ -24,7 +35,9 @@
 	$(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map
 
 cmd_u-boot-spl = (cd $(obj) && $(CC) -o $(SPL_BIN) -Wl,-T u-boot-spl.lds \
-	$(KBUILD_LDFLAGS:%=-Wl,%) $(LTO_FINAL_LDFLAGS) \
+	$(KBUILD_LDFLAGS:%=-Wl,%) \
+	$(SANITIZERS) \
+	$(LTO_FINAL_LDFLAGS) \
 	$(patsubst $(obj)/%,%,$(u-boot-spl-init)) \
 	-Wl,--whole-archive \
 		$(patsubst $(obj)/%,%,$(u-boot-spl-main)) \
@@ -44,13 +57,13 @@
 else ifeq ($(HOST_ARCH),$(HOST_ARCH_AARCH64))
 EFI_LDS := ${SRCDIR}/../../../arch/arm/lib/elf_aarch64_efi.lds
 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .data \
-		-j .u_boot_list -j .rela.dyn -j .got -j .got.plt \
+		-j __u_boot_list -j .rela.dyn -j .got -j .got.plt \
 		-j .binman_sym_table -j .text_rest \
 		-j .efi_runtime -j .efi_runtime_rel
 else ifeq ($(HOST_ARCH),$(HOST_ARCH_ARM))
 EFI_LDS := ${SRCDIR}/../../../arch/arm/lib/elf_arm_efi.lds
 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .hash \
-		-j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn \
+		-j .data -j .got -j .got.plt -j __u_boot_list -j .rel.dyn \
 		-j .binman_sym_table -j .text_rest \
 		-j .efi_runtime -j .efi_runtime_rel
 else ifeq ($(HOST_ARCH),$(HOST_ARCH_RISCV32))
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 5ea5417..3b23060 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -8,6 +8,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <pthread.h>
 #include <getopt.h>
 #include <setjmp.h>
 #include <signal.h>
@@ -26,7 +27,9 @@
 #include <linux/compiler_attributes.h>
 #include <linux/types.h>
 
+#include <asm/fuzzing_engine.h>
 #include <asm/getopt.h>
+#include <asm/main.h>
 #include <asm/sections.h>
 #include <asm/state.h>
 #include <os.h>
@@ -1001,3 +1004,76 @@
 	execv(argv[0], argv);
 	os_exit(1);
 }
+
+
+#ifdef CONFIG_FUZZ
+static void *fuzzer_thread(void * ptr)
+{
+	char cmd[64];
+	char *argv[5] = {"./u-boot", "-T", "-c", cmd, NULL};
+	const char *fuzz_test;
+
+	/* Find which test to run from an environment variable. */
+	fuzz_test = getenv("UBOOT_SB_FUZZ_TEST");
+	if (!fuzz_test)
+		os_abort();
+
+	snprintf(cmd, sizeof(cmd), "fuzz %s", fuzz_test);
+
+	sandbox_main(4, argv);
+	os_abort();
+	return NULL;
+}
+
+static bool fuzzer_initialized = false;
+static pthread_mutex_t fuzzer_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t fuzzer_cond = PTHREAD_COND_INITIALIZER;
+static const uint8_t *fuzzer_data;
+static size_t fuzzer_size;
+
+int sandbox_fuzzing_engine_get_input(const uint8_t **data, size_t *size)
+{
+	if (!fuzzer_initialized)
+		return -ENOSYS;
+
+	/* Tell the main thread we need new inputs then wait for them. */
+	pthread_mutex_lock(&fuzzer_mutex);
+	pthread_cond_signal(&fuzzer_cond);
+	pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex);
+	*data = fuzzer_data;
+	*size = fuzzer_size;
+	pthread_mutex_unlock(&fuzzer_mutex);
+	return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+	static pthread_t tid;
+
+	pthread_mutex_lock(&fuzzer_mutex);
+
+	/* Initialize the sandbox on another thread. */
+	if (!fuzzer_initialized) {
+		fuzzer_initialized = true;
+		if (pthread_create(&tid, NULL, fuzzer_thread, NULL))
+			os_abort();
+		pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex);
+	}
+
+	/* Hand over the input. */
+	fuzzer_data = data;
+	fuzzer_size = size;
+	pthread_cond_signal(&fuzzer_cond);
+
+	/* Wait for the inputs to be finished with. */
+	pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex);
+	pthread_mutex_unlock(&fuzzer_mutex);
+
+	return 0;
+}
+#else
+int main(int argc, char *argv[])
+{
+	return sandbox_main(argc, argv);
+}
+#endif
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c
index 0f5a873..90a84e9 100644
--- a/arch/sandbox/cpu/start.c
+++ b/arch/sandbox/cpu/start.c
@@ -453,7 +453,7 @@
 	os_relaunch(os_argv);
 }
 
-int main(int argc, char *argv[])
+int sandbox_main(int argc, char *argv[])
 {
 	struct sandbox_state *state;
 	void * text_base;
diff --git a/arch/sandbox/cpu/u-boot-spl.lds b/arch/sandbox/cpu/u-boot-spl.lds
index 206e265..ef885fd 100644
--- a/arch/sandbox/cpu/u-boot-spl.lds
+++ b/arch/sandbox/cpu/u-boot-spl.lds
@@ -9,8 +9,8 @@
 {
 
 	. = ALIGN(32);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	/* Private data for devices with OF_PLATDATA_RT */
@@ -22,9 +22,9 @@
 	}
 
 	_u_boot_sandbox_getopt : {
-		*(.u_boot_sandbox_getopt_start)
-		KEEP(*(.u_boot_sandbox_getopt))
-		*(.u_boot_sandbox_getopt_end)
+		*(_u_boot_sandbox_getopt_start)
+		KEEP(*(_u_boot_sandbox_getopt))
+		*(_u_boot_sandbox_getopt_end)
 	}
 }
 
diff --git a/arch/sandbox/cpu/u-boot.lds b/arch/sandbox/cpu/u-boot.lds
index 92e834a..ba8dee5 100644
--- a/arch/sandbox/cpu/u-boot.lds
+++ b/arch/sandbox/cpu/u-boot.lds
@@ -9,42 +9,40 @@
 {
 
 	. = ALIGN(32);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	_u_boot_sandbox_getopt : {
-		*(.u_boot_sandbox_getopt_start)
-		*(.u_boot_sandbox_getopt)
-		*(.u_boot_sandbox_getopt_end)
+		*(_u_boot_sandbox_getopt_start)
+		*(_u_boot_sandbox_getopt)
+		*(_u_boot_sandbox_getopt_end)
 	}
 
-	.__efi_runtime_start : {
-		*(.__efi_runtime_start)
+	efi_runtime_start : {
+		*(___efi_runtime_start)
 	}
 
-	.efi_runtime : {
+	efi_runtime : {
 		*(efi_runtime_text)
 		*(efi_runtime_data)
 	}
 
-	.__efi_runtime_stop : {
-		*(.__efi_runtime_stop)
+	efi_runtime_stop : {
+		*(___efi_runtime_stop)
 	}
 
-	.efi_runtime_rel_start :
-	{
-		*(.__efi_runtime_rel_start)
+	efi_runtime_rel_start : {
+		*(___efi_runtime_rel_start)
 	}
 
-	.efi_runtime_rel : {
+	efi_runtime_rel : {
 		*(.relefi_runtime_text)
 		*(.relefi_runtime_data)
 	}
 
-	.efi_runtime_rel_stop :
-	{
-		*(.__efi_runtime_rel_stop)
+	efi_runtime_rel_stop : {
+		*(___efi_runtime_rel_stop)
 	}
 
 	.dynsym :
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index e068d0c..0194b9b 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -92,6 +92,10 @@
 		};
 	};
 
+	fuzzing-engine {
+		compatible = "sandbox,fuzzing-engine";
+	};
+
 	reboot-mode0 {
 		compatible = "reboot-mode-gpio";
 		gpios = <&gpio_c 0 GPIO_ACTIVE_HIGH>, <&gpio_c 1 GPIO_ACTIVE_HIGH>;
diff --git a/arch/sandbox/include/asm/fuzzing_engine.h b/arch/sandbox/include/asm/fuzzing_engine.h
new file mode 100644
index 0000000..cf63963
--- /dev/null
+++ b/arch/sandbox/include/asm/fuzzing_engine.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022 Google, Inc.
+ * Written by Andrew Scull <ascull@google.com>
+ */
+
+#ifndef __ASM_FUZZING_ENGINE_H
+#define __ASM_FUZZING_ENGINE_H
+
+/** Function to get fuzzing engine input data. */
+/**
+ * sandbox_fuzzing_engine_get_input() - get an input from the sandbox fuzzing
+ * 					engine
+ *
+ * The function will return a pointer to the input data and the size of the
+ * data pointed to. The pointer will remain valid until the next invocation of
+ * this function.
+ *
+ * @data:	output pointer to input data
+ * @size	output size of input data
+ * Return:	0 if OK, -ve on error
+ */
+int sandbox_fuzzing_engine_get_input(const uint8_t **data, size_t *size);
+
+#endif /* __ASM_FUZZING_ENGINE_H */
diff --git a/arch/sandbox/include/asm/getopt.h b/arch/sandbox/include/asm/getopt.h
index d2145ad..df30572 100644
--- a/arch/sandbox/include/asm/getopt.h
+++ b/arch/sandbox/include/asm/getopt.h
@@ -44,7 +44,7 @@
 		.callback = sandbox_cmdline_cb_##f, \
 	}; \
 	/* Ppointer to the struct in a special section for the linker script */ \
-	static __used __section(".u_boot_sandbox_getopt") \
+	static __used __section("_u_boot_sandbox_getopt") \
 		struct sandbox_cmdline_option \
 			*sandbox_cmdline_option_##f##_ptr = \
 			&sandbox_cmdline_option_##f
diff --git a/arch/sandbox/include/asm/main.h b/arch/sandbox/include/asm/main.h
new file mode 100644
index 0000000..7a2f0d3
--- /dev/null
+++ b/arch/sandbox/include/asm/main.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022 Google, Inc.
+ * Written by Andrew Scull <ascull@google.com>
+ */
+
+#ifndef __ASM_SANDBOX_MAIN_H
+#define __ASM_SANDBOX_MAIN_H
+
+/**
+ * sandbox_main() - main entrypoint for sandbox
+ *
+ * @argc:	the number of arguments passed to the program
+ * @argv:	array of argc+1 pointers, of which the last one is null
+ */
+int sandbox_main(int argc, char *argv[]);
+
+#endif /* __ASM_SANDBOX_MAIN_H */
diff --git a/arch/sandbox/include/asm/sections.h b/arch/sandbox/include/asm/sections.h
index f4351ae..88837bb 100644
--- a/arch/sandbox/include/asm/sections.h
+++ b/arch/sandbox/include/asm/sections.h
@@ -17,7 +17,7 @@
 __u_boot_sandbox_option_start(void)
 {
 	static char start[0] __aligned(4) __attribute__((unused))
-		__section(".u_boot_sandbox_getopt_start");
+		__section("_u_boot_sandbox_getopt_start");
 
 	return (struct sandbox_cmdline_option **)&start;
 }
@@ -26,7 +26,7 @@
 __u_boot_sandbox_option_end(void)
 {
 	static char end[0] __aligned(4) __attribute__((unused))
-		__section(".u_boot_sandbox_getopt_end");
+		__section("_u_boot_sandbox_getopt_end");
 
 	return (struct sandbox_cmdline_option **)&end;
 }
diff --git a/arch/sandbox/lib/sections.c b/arch/sandbox/lib/sections.c
index 2559eee..2f2f3fb 100644
--- a/arch/sandbox/lib/sections.c
+++ b/arch/sandbox/lib/sections.c
@@ -5,9 +5,9 @@
  */
 #include <linux/compiler.h>
 
-char __efi_runtime_start[0] __section(".__efi_runtime_start");
-char __efi_runtime_stop[0] __section(".__efi_runtime_stop");
+char __efi_runtime_start[0] __section("___efi_runtime_start");
+char __efi_runtime_stop[0] __section("___efi_runtime_stop");
 char __efi_runtime_rel_start[0]
-		__section(".__efi_runtime_rel_start");
+		__section("___efi_runtime_rel_start");
 char __efi_runtime_rel_stop[0]
-		__section(".__efi_runtime_rel_stop");
+		__section("___efi_runtime_rel_stop");
diff --git a/arch/sh/cpu/u-boot.lds b/arch/sh/cpu/u-boot.lds
index 4cc9773..ff80ce7 100644
--- a/arch/sh/cpu/u-boot.lds
+++ b/arch/sh/cpu/u-boot.lds
@@ -70,8 +70,8 @@
 	} >ram
 	PROVIDE (_egot = .);
 
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	} >ram
 
 	PROVIDE (__init_end = .);
diff --git a/arch/x86/cpu/u-boot-64.lds b/arch/x86/cpu/u-boot-64.lds
index 92a30c2..53c5604 100644
--- a/arch/x86/cpu/u-boot-64.lds
+++ b/arch/x86/cpu/u-boot-64.lds
@@ -12,7 +12,7 @@
 SECTIONS
 {
 #ifndef CONFIG_CMDLINE
-	/DISCARD/ : { *(.u_boot_list_2_cmd_*) }
+	/DISCARD/ : { *(__u_boot_list_2_cmd_*) }
 #endif
 
 #ifdef CONFIG_SYS_TEXT_BASE
@@ -41,8 +41,8 @@
 	. = ALIGN(4);
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds
index 346f60b..a0a2a06 100644
--- a/arch/x86/cpu/u-boot-spl.lds
+++ b/arch/x86/cpu/u-boot-spl.lds
@@ -12,7 +12,7 @@
 SECTIONS
 {
 #ifndef CONFIG_CMDLINE
-	/DISCARD/ : { *(.u_boot_list_2_cmd_*) }
+	/DISCARD/ : { *(__u_boot_list_2_cmd_*) }
 #endif
 
 	. = IMAGE_TEXT_BASE;	/* Location of bootcode in flash */
@@ -25,8 +25,8 @@
 	. = ALIGN(4);
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds
index 22fde01..7c87209 100644
--- a/arch/x86/cpu/u-boot.lds
+++ b/arch/x86/cpu/u-boot.lds
@@ -12,7 +12,7 @@
 SECTIONS
 {
 #ifndef CONFIG_CMDLINE
-	/DISCARD/ : { *(.u_boot_list_2_cmd_*) }
+	/DISCARD/ : { *(__u_boot_list_2_cmd_*) }
 #endif
 
 	. = CONFIG_SYS_TEXT_BASE;	/* Location of bootcode in flash */
@@ -39,8 +39,8 @@
 	. = ALIGN(4);
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/arch/x86/lib/elf_ia32_efi.lds b/arch/x86/lib/elf_ia32_efi.lds
index aad61e7..6d89c1f 100644
--- a/arch/x86/lib/elf_ia32_efi.lds
+++ b/arch/x86/lib/elf_ia32_efi.lds
@@ -51,7 +51,7 @@
 
 		/* U-Boot lists and device tree */
 		. = ALIGN(8);
-		*(SORT(.u_boot_list*));
+		*(SORT(__u_boot_list*));
 		. = ALIGN(8);
 		*(.dtb*);
 	}
@@ -69,7 +69,7 @@
 		*(.data.rel.local)
 		*(.data.rel.ro)
 		*(.data.rel*)
-		*(.rel.u_boot_list*)
+		*(.rel__u_boot_list*)
 	}
 	. = ALIGN(4096);
 		.reloc :	/* This is the PECOFF .reloc section! */
diff --git a/arch/x86/lib/elf_x86_64_efi.lds b/arch/x86/lib/elf_x86_64_efi.lds
index 7572740..ada024c 100644
--- a/arch/x86/lib/elf_x86_64_efi.lds
+++ b/arch/x86/lib/elf_x86_64_efi.lds
@@ -50,7 +50,7 @@
 
 		/* U-Boot lists and device tree */
 		. = ALIGN(8);
-		*(SORT(.u_boot_list*));
+		*(SORT(__u_boot_list*));
 		. = ALIGN(8);
 		*(.dtb*);
 	}
@@ -63,7 +63,7 @@
 		*(.rela.data*)
 		*(.rela.got)
 		*(.rela.stab)
-                *(.rela.u_boot_list*)
+                *(.rela__u_boot_list*)
 	}
 
 	. = ALIGN(4096);
diff --git a/arch/xtensa/cpu/u-boot.lds b/arch/xtensa/cpu/u-boot.lds
index 493f3fd..84ba32c 100644
--- a/arch/xtensa/cpu/u-boot.lds
+++ b/arch/xtensa/cpu/u-boot.lds
@@ -49,7 +49,7 @@
     RELOCATE1(text);
     RELOCATE1(rodata);
     RELOCATE1(data);
-    RELOCATE1(u_boot_list);
+    RELOCATE_USER1(__u_boot_list);
     __reloc_table_end = ABSOLUTE(.);
   }
 
@@ -78,7 +78,7 @@
   SECTION_text(XTENSA_SYS_TEXT_ADDR, FOLLOWING(.DoubleExceptionVector.text))
   SECTION_rodata(ALIGN(16), FOLLOWING(.text))
   SECTION_u_boot_list(ALIGN(16), FOLLOWING(.rodata))
-  SECTION_data(ALIGN(16), FOLLOWING(.u_boot_list))
+  SECTION_data(ALIGN(16), FOLLOWING(__u_boot_list))
 
   __reloc_end = .;
   __init_end = .;
diff --git a/arch/xtensa/include/asm/ldscript.h b/arch/xtensa/include/asm/ldscript.h
index 08f5d01..78a0b23 100644
--- a/arch/xtensa/include/asm/ldscript.h
+++ b/arch/xtensa/include/asm/ldscript.h
@@ -41,6 +41,11 @@
 	LONG(_##_sym_##_##_sec_##_end);					\
 	LONG(LOADADDR(.##_sym_##.##_sec_));
 
+#define RELOCATE_USER1(_sec_)						\
+	LONG(_##_sec_##_start);						\
+	LONG(_##_sec_##_end);						\
+	LONG(LOADADDR(_sec_));
+
 #define SECTION_VECTOR(_sym_, _sec_, _vma_, _lma_)			\
 .##_sym_##.##_sec_ _vma_ : _lma_					\
 {									\
@@ -100,11 +105,11 @@
 	}
 
 #define SECTION_u_boot_list(_vma_, _lma_)				\
-	.u_boot_list _vma_ : _lma_					\
+	__u_boot_list _vma_ : _lma_					\
 	{								\
-		_u_boot_list_start = ABSOLUTE(.);			\
-		KEEP(*(SORT(.u_boot_list*)));				\
-		_u_boot_list_end = ABSOLUTE(.);				\
+		___u_boot_list_start = ABSOLUTE(.);			\
+		KEEP(*(SORT(__u_boot_list*)));				\
+		___u_boot_list_end = ABSOLUTE(.);			\
 	}
 
 #define SECTION_data(_vma_, _lma_)					\
diff --git a/board/compulab/cm_t335/u-boot.lds b/board/compulab/cm_t335/u-boot.lds
index b00e466..4993880 100644
--- a/board/compulab/cm_t335/u-boot.lds
+++ b/board/compulab/cm_t335/u-boot.lds
@@ -36,8 +36,8 @@
 	. = .;
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/board/cssi/MCR3000/u-boot.lds b/board/cssi/MCR3000/u-boot.lds
index 70aef32..24b535e 100644
--- a/board/cssi/MCR3000/u-boot.lds
+++ b/board/cssi/MCR3000/u-boot.lds
@@ -59,8 +59,8 @@
 	. = .;
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = .;
diff --git a/board/davinci/da8xxevm/u-boot-spl-da850evm.lds b/board/davinci/da8xxevm/u-boot-spl-da850evm.lds
index f6b9de2..7e0f09f 100644
--- a/board/davinci/da8xxevm/u-boot-spl-da850evm.lds
+++ b/board/davinci/da8xxevm/u-boot-spl-da850evm.lds
@@ -36,7 +36,7 @@
 	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
 
 	. = ALIGN(4);
-	.u_boot_list : { KEEP(*(SORT(.u_boot_list*))); } >.sram
+	__u_boot_list : { KEEP(*(SORT(__u_boot_list*))); } >.sram
 
 	. = ALIGN(4);
 	.rel.dyn : {
diff --git a/board/qualcomm/dragonboard820c/u-boot.lds b/board/qualcomm/dragonboard820c/u-boot.lds
index dcf8256..5251b59 100644
--- a/board/qualcomm/dragonboard820c/u-boot.lds
+++ b/board/qualcomm/dragonboard820c/u-boot.lds
@@ -49,8 +49,8 @@
 	. = .;
 
 	. = ALIGN(8);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(8);
diff --git a/board/samsung/common/exynos-uboot-spl.lds b/board/samsung/common/exynos-uboot-spl.lds
index 5b32f7f..73cd97a 100644
--- a/board/samsung/common/exynos-uboot-spl.lds
+++ b/board/samsung/common/exynos-uboot-spl.lds
@@ -32,8 +32,8 @@
 	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
 	. = ALIGN(4);
 
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	} >.sram
 	. = ALIGN(4);
 
diff --git a/board/synopsys/iot_devkit/u-boot.lds b/board/synopsys/iot_devkit/u-boot.lds
index 5aff100..e82e498 100644
--- a/board/synopsys/iot_devkit/u-boot.lds
+++ b/board/synopsys/iot_devkit/u-boot.lds
@@ -40,8 +40,8 @@
 	} > ROM
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 
 		/* Mark RAM's LMA */
 		. = ALIGN(4);
diff --git a/board/ti/am335x/u-boot.lds b/board/ti/am335x/u-boot.lds
index 03c1d5f..087dee8 100644
--- a/board/ti/am335x/u-boot.lds
+++ b/board/ti/am335x/u-boot.lds
@@ -72,8 +72,8 @@
 	. = .;
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/board/vscom/baltos/u-boot.lds b/board/vscom/baltos/u-boot.lds
index 315ba5b..cb2ee67 100644
--- a/board/vscom/baltos/u-boot.lds
+++ b/board/vscom/baltos/u-boot.lds
@@ -53,8 +53,8 @@
 	. = .;
 
 	. = ALIGN(4);
-	.u_boot_list : {
-		KEEP(*(SORT(.u_boot_list*)));
+	__u_boot_list : {
+		KEEP(*(SORT(__u_boot_list*)));
 	}
 
 	. = ALIGN(4);
diff --git a/doc/api/linker_lists.rst b/doc/api/linker_lists.rst
index 7063fdc..3cd447f 100644
--- a/doc/api/linker_lists.rst
+++ b/doc/api/linker_lists.rst
@@ -13,7 +13,7 @@
 
 ::
 
-  .u_boot_list_ + 2_ + @_list + _2_ + @_entry
+  __u_boot_list_ + 2_ + @_list + _2_ + @_entry
 
 and the C variable name is
 
@@ -23,7 +23,7 @@
 
 This ensures uniqueness for both input section and C variable name.
 
-Note that the names differ only in the first character, "." for the
+Note that the names differ only in the characters, "__" for the
 section and "_" for the variable, so that the linker cannot confuse
 section and symbol names. From now on, both names will be referred
 to as
@@ -63,11 +63,11 @@
 
 ::
 
-  .u_boot_list_2_array_1
-  .u_boot_list_2_array_2_first
-  .u_boot_list_2_array_2_second
-  .u_boot_list_2_array_2_third
-  .u_boot_list_2_array_3
+  __u_boot_list_2_array_1
+  __u_boot_list_2_array_2_first
+  __u_boot_list_2_array_2_second
+  __u_boot_list_2_array_2_third
+  __u_boot_list_2_array_3
 
 If lists must be divided into sublists (e.g. for iterating only on
 part of a list), one can simply give the list a name of the form
@@ -129,17 +129,17 @@
 
 In the first case, an 8-byte 'fill' region is added::
 
-   .u_boot_list_2_driver_2_testbus_drv
+   __u_boot_list_2_driver_2_testbus_drv
                0x0000000000270018       0x80 test/built-in.o
                0x0000000000270018                _u_boot_list_2_driver_2_testbus_drv
-   .u_boot_list_2_driver_2_testfdt1_drv
+   __u_boot_list_2_driver_2_testfdt1_drv
                0x0000000000270098       0x80 test/built-in.o
                0x0000000000270098                _u_boot_list_2_driver_2_testfdt1_drv
    *fill*         0x0000000000270118        0x8
-   .u_boot_list_2_driver_2_testfdt_drv
+   __u_boot_list_2_driver_2_testfdt_drv
                0x0000000000270120       0x80 test/built-in.o
                0x0000000000270120                _u_boot_list_2_driver_2_testfdt_drv
-   .u_boot_list_2_driver_2_testprobe_drv
+   __u_boot_list_2_driver_2_testprobe_drv
                0x00000000002701a0       0x80 test/built-in.o
                0x00000000002701a0                _u_boot_list_2_driver_2_testprobe_drv
 
diff --git a/doc/develop/commands.rst b/doc/develop/commands.rst
index c72d1b0..ede880d 100644
--- a/doc/develop/commands.rst
+++ b/doc/develop/commands.rst
@@ -169,8 +169,8 @@
 
 .. code-block:: c
 
-    .u_boot_list : {
-        KEEP(*(SORT(.u_boot_list*)));
+    __u_boot_list : {
+        KEEP(*(SORT(__u_boot_list*)));
     }
 
 Writing tests
diff --git a/doc/develop/driver-model/of-plat.rst b/doc/develop/driver-model/of-plat.rst
index 237af38..b454f7b 100644
--- a/doc/develop/driver-model/of-plat.rst
+++ b/doc/develop/driver-model/of-plat.rst
@@ -707,9 +707,9 @@
 Sometimes dtoc does not find the problem for you, but something is wrong and
 you get a link error, e.g.::
 
-   :(.u_boot_list_2_udevice_2_spl_test5+0x0): undefined reference to
+   :(__u_boot_list_2_udevice_2_spl_test5+0x0): undefined reference to
       `_u_boot_list_2_driver_2_sandbox_spl_test'
-   /usr/bin/ld: dts/dt-uclass.o:(.u_boot_list_2_uclass_2_misc+0x8):
+   /usr/bin/ld: dts/dt-uclass.o:(__u_boot_list_2_uclass_2_misc+0x8):
         undefined reference to `_u_boot_list_2_uclass_driver_2_misc'
 
 The first one indicates that the device cannot find its driver. This means that
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b26ca8c..8b6fead 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -40,6 +40,8 @@
 
 source "drivers/firmware/Kconfig"
 
+source "drivers/fuzz/Kconfig"
+
 source "drivers/fpga/Kconfig"
 
 source "drivers/gpio/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 67c8af7..d63fd1c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -115,6 +115,7 @@
 obj-$(CONFIG_W1_EEPROM) += w1-eeprom/
 
 obj-$(CONFIG_MACH_PIC32) += ddr/microchip/
+obj-$(CONFIG_FUZZ) += fuzz/
 obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/
 obj-$(CONFIG_DM_RNG) += rng/
 endif
diff --git a/drivers/fuzz/Kconfig b/drivers/fuzz/Kconfig
new file mode 100644
index 0000000..6311385
--- /dev/null
+++ b/drivers/fuzz/Kconfig
@@ -0,0 +1,17 @@
+config DM_FUZZING_ENGINE
+	bool "Driver support for fuzzing engine devices"
+	depends on DM
+	help
+	  Enable driver model for fuzzing engine devices. This interface is
+	  used to get fuzzing inputs from a fuzzing engine.
+
+if DM_FUZZING_ENGINE
+
+config FUZZING_ENGINE_SANDBOX
+	bool "Sanbox fuzzing engine"
+	depends on SANDBOX
+	default y
+	help
+	  Enable fuzzing engine for sandbox.
+
+endif
diff --git a/drivers/fuzz/Makefile b/drivers/fuzz/Makefile
new file mode 100644
index 0000000..073743b
--- /dev/null
+++ b/drivers/fuzz/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2022 Google, Inc.
+# Written by Andrew Scull <ascull@google.com>
+#
+
+obj-$(CONFIG_DM_FUZZING_ENGINE) += fuzzing_engine-uclass.o
+obj-$(CONFIG_FUZZING_ENGINE_SANDBOX) += sandbox_fuzzing_engine.o
diff --git a/drivers/fuzz/fuzzing_engine-uclass.c b/drivers/fuzz/fuzzing_engine-uclass.c
new file mode 100644
index 0000000..b16f1c4
--- /dev/null
+++ b/drivers/fuzz/fuzzing_engine-uclass.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022 Google, Inc.
+ * Written by Andrew Scull <ascull@google.com>
+ */
+
+#define LOG_CATEGORY UCLASS_FUZZING_ENGINE
+
+#include <common.h>
+#include <dm.h>
+#include <fuzzing_engine.h>
+
+int dm_fuzzing_engine_get_input(struct udevice *dev,
+				const uint8_t **data,
+				size_t *size)
+{
+	const struct dm_fuzzing_engine_ops *ops = device_get_ops(dev);
+
+	if (!ops->get_input)
+		return -ENOSYS;
+
+	return ops->get_input(dev, data, size);
+}
+
+UCLASS_DRIVER(fuzzing_engine) = {
+	.name = "fuzzing_engine",
+	.id = UCLASS_FUZZING_ENGINE,
+};
diff --git a/drivers/fuzz/sandbox_fuzzing_engine.c b/drivers/fuzz/sandbox_fuzzing_engine.c
new file mode 100644
index 0000000..ebb938e
--- /dev/null
+++ b/drivers/fuzz/sandbox_fuzzing_engine.c
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022 Google, Inc.
+ * Written by Andrew Scull <ascull@google.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fuzzing_engine.h>
+#include <asm/fuzzing_engine.h>
+
+static int get_input(struct udevice *dev,
+		     const uint8_t **data,
+		     size_t *size)
+{
+	return sandbox_fuzzing_engine_get_input(data, size);
+}
+
+static const struct dm_fuzzing_engine_ops sandbox_fuzzing_engine_ops = {
+	.get_input = get_input,
+};
+
+static const struct udevice_id sandbox_fuzzing_engine_match[] = {
+	{
+		.compatible = "sandbox,fuzzing-engine",
+	},
+	{},
+};
+
+U_BOOT_DRIVER(sandbox_fuzzing_engine) = {
+	.name = "sandbox-fuzzing-engine",
+	.id = UCLASS_FUZZING_ENGINE,
+	.of_match = sandbox_fuzzing_engine_match,
+	.ops = &sandbox_fuzzing_engine_ops,
+};
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c
index e726e19..13b5492 100644
--- a/drivers/serial/sandbox.c
+++ b/drivers/serial/sandbox.c
@@ -114,7 +114,7 @@
 	struct sandbox_serial_priv *priv = dev_get_priv(dev);
 	ssize_t ret;
 
-	if (s[len - 1] == '\n')
+	if (len && s[len - 1] == '\n')
 		priv->start_of_line = true;
 
 	if (sandbox_serial_enabled) {
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 3ba69ad..a432e43 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -56,6 +56,7 @@
 	UCLASS_ETH,		/* Ethernet device */
 	UCLASS_ETH_PHY,		/* Ethernet PHY device */
 	UCLASS_FIRMWARE,	/* Firmware */
+	UCLASS_FUZZING_ENGINE,	/* Fuzzing engine */
 	UCLASS_FS_FIRMWARE_LOADER,		/* Generic loader */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
 	UCLASS_HASH,		/* Hash device */
diff --git a/include/fuzzing_engine.h b/include/fuzzing_engine.h
new file mode 100644
index 0000000..357346e
--- /dev/null
+++ b/include/fuzzing_engine.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022 Google, Inc.
+ * Written by Andrew Scull <ascull@google.com>
+ */
+
+#ifndef __FUZZING_ENGINE_H
+#define __FUZZING_ENGINE_H
+
+struct udevice;
+
+/**
+ * dm_fuzzing_engine_get_input() - get an input from the fuzzing engine device
+ *
+ * The function will return a pointer to the input data and the size of the
+ * data pointed to. The pointer will remain valid until the next invocation of
+ * this function.
+ *
+ * @dev:	fuzzing engine device
+ * @data:	output pointer to input data
+ * @size	output size of input data
+ * Return:	0 if OK, -ve on error
+ */
+int dm_fuzzing_engine_get_input(struct udevice *dev,
+				const uint8_t **data,
+				size_t *size);
+
+/**
+ * struct dm_fuzzing_engine_ops - operations for the fuzzing engine uclass
+ *
+ * This contains the functions implemented by a fuzzing engine device.
+ */
+struct dm_fuzzing_engine_ops {
+	/**
+	 * @get_input() - get an input
+	 *
+	 * The function will return a pointer to the input data and the size of
+	 * the data pointed to. The pointer will remain valid until the next
+	 * invocation of this function.
+	 *
+	 * @get_input.dev:	fuzzing engine device
+	 * @get_input.data:	output pointer to input data
+	 * @get_input.size	output size of input data
+	 * @get_input.Return:	0 if OK, -ve on error
+	 */
+	int (*get_input)(struct udevice *dev,
+			 const uint8_t **data,
+			 size_t *size);
+};
+
+#endif /* __FUZZING_ENGINE_H */
diff --git a/include/linker_lists.h b/include/linker_lists.h
index 0575164..d3da9d4 100644
--- a/include/linker_lists.h
+++ b/include/linker_lists.h
@@ -70,7 +70,7 @@
 #define ll_entry_declare(_type, _name, _list)				\
 	_type _u_boot_list_2_##_list##_2_##_name __aligned(4)		\
 			__attribute__((unused))				\
-			__section(".u_boot_list_2_"#_list"_2_"#_name)
+			__section("__u_boot_list_2_"#_list"_2_"#_name)
 
 /**
  * ll_entry_declare_list() - Declare a list of link-generated array entries
@@ -93,7 +93,7 @@
 #define ll_entry_declare_list(_type, _name, _list)			\
 	_type _u_boot_list_2_##_list##_2_##_name[] __aligned(4)		\
 			__attribute__((unused))				\
-			__section(".u_boot_list_2_"#_list"_2_"#_name)
+			__section("__u_boot_list_2_"#_list"_2_"#_name)
 
 /*
  * We need a 0-byte-size type for iterator symbols, and the compiler
@@ -110,7 +110,7 @@
  * @_list:	Name of the list in which this entry is placed
  *
  * This function returns ``(_type *)`` pointer to the very first entry of a
- * linker-generated array placed into subsection of .u_boot_list section
+ * linker-generated array placed into subsection of __u_boot_list section
  * specified by _list argument.
  *
  * Since this macro defines an array start symbol, its leftmost index
@@ -126,7 +126,7 @@
 ({									\
 	static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN)	\
 		__attribute__((unused))					\
-		__section(".u_boot_list_2_"#_list"_1");			\
+		__section("__u_boot_list_2_"#_list"_1");			\
 	(_type *)&start;						\
 })
 
@@ -137,7 +137,7 @@
  *		(with underscores instead of dots)
  *
  * This function returns ``(_type *)`` pointer after the very last entry of
- * a linker-generated array placed into subsection of .u_boot_list
+ * a linker-generated array placed into subsection of __u_boot_list
  * section specified by _list argument.
  *
  * Since this macro defines an array end symbol, its leftmost index
@@ -152,7 +152,7 @@
 #define ll_entry_end(_type, _list)					\
 ({									\
 	static char end[0] __aligned(4) __attribute__((unused))		\
-		__section(".u_boot_list_2_"#_list"_3");			\
+		__section("__u_boot_list_2_"#_list"_3");			\
 	(_type *)&end;							\
 })
 /**
@@ -161,7 +161,7 @@
  * @_list:	Name of the list of which the number of elements is computed
  *
  * This function returns the number of elements of a linker-generated array
- * placed into subsection of .u_boot_list section specified by _list
+ * placed into subsection of __u_boot_list section specified by _list
  * argument. The result is of an unsigned int type.
  *
  * Example:
@@ -246,7 +246,7 @@
 #define ll_start(_type)							\
 ({									\
 	static char start[0] __aligned(4) __attribute__((unused))	\
-		__section(".u_boot_list_1");				\
+		__section("__u_boot_list_1");				\
 	(_type *)&start;						\
 })
 
@@ -269,7 +269,7 @@
 #define ll_end(_type)							\
 ({									\
 	static char end[0] __aligned(4) __attribute__((unused))		\
-		__section(".u_boot_list_3");				\
+		__section("__u_boot_list_3");				\
 	(_type *)&end;							\
 })
 
diff --git a/include/test/fuzz.h b/include/test/fuzz.h
new file mode 100644
index 0000000..d4c5754
--- /dev/null
+++ b/include/test/fuzz.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022 Google, Inc.
+ * Written by Andrew Scull <ascull@google.com>
+ */
+
+#ifndef __TEST_FUZZ_H
+#define __TEST_FUZZ_H
+
+#include <linker_lists.h>
+#include <linux/types.h>
+
+/**
+ * struct fuzz_test - Information about a fuzz test
+ *
+ * @name: Name of fuzz test
+ * @func: Function to call to perform fuzz test on an input
+ * @flags: Flags indicate pre-conditions for fuzz test
+ */
+struct fuzz_test {
+	const char *name;
+	int (*func)(const uint8_t * data, size_t size);
+	int flags;
+};
+
+/**
+ * FUZZ_TEST() - register a fuzz test
+ *
+ * The fuzz test function must return 0 as other values are reserved for future
+ * use.
+ *
+ * @_name:	the name of the fuzz test function
+ * @_flags:	an integer field that can be evaluated by the fuzzer
+ * 		implementation
+ */
+#define FUZZ_TEST(_name, _flags)					\
+	ll_entry_declare(struct fuzz_test, _name, fuzz_tests) = {	\
+		.name = #_name,						\
+		.func = _name,						\
+		.flags = _flags,					\
+	}
+
+/** Get the start of the list of fuzz tests */
+#define FUZZ_TEST_START() \
+	ll_entry_start(struct fuzz_test, fuzz_tests)
+
+/** Get the number of elements in the list of fuzz tests */
+#define FUZZ_TEST_COUNT() \
+	ll_entry_count(struct fuzz_test, fuzz_tests)
+
+#endif /* __TEST_FUZZ_H */
diff --git a/test/Makefile b/test/Makefile
index abd605a..1dfd567 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -16,6 +16,7 @@
 obj-$(CONFIG_$(SPL_)CMDLINE) += command_ut.o
 obj-$(CONFIG_$(SPL_)UT_COMPRESSION) += compression.o
 obj-y += dm/
+obj-$(CONFIG_FUZZ) += fuzz/
 obj-$(CONFIG_$(SPL_)CMDLINE) += print_ut.o
 obj-$(CONFIG_$(SPL_)CMDLINE) += str_ut.o
 obj-$(CONFIG_UT_TIME) += time_ut.o
diff --git a/test/fuzz/Makefile b/test/fuzz/Makefile
new file mode 100644
index 0000000..663b79c
--- /dev/null
+++ b/test/fuzz/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2022 Google, Inc.
+# Written by Andrew Scull <ascull@google.com>
+#
+
+obj-$(CONFIG_$(SPL_)CMDLINE) += cmd_fuzz.o
+obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o
diff --git a/test/fuzz/cmd_fuzz.c b/test/fuzz/cmd_fuzz.c
new file mode 100644
index 0000000..0cc01dc
--- /dev/null
+++ b/test/fuzz/cmd_fuzz.c
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022 Google, Inc.
+ * Written by Andrew Scull <ascull@google.com>
+ */
+
+#include <command.h>
+#include <common.h>
+#include <dm.h>
+#include <fuzzing_engine.h>
+#include <test/fuzz.h>
+
+static struct fuzz_test *find_fuzz_test(const char *name)
+{
+	struct fuzz_test *fuzzer = FUZZ_TEST_START();
+	size_t count = FUZZ_TEST_COUNT();
+	size_t i;
+
+	for (i = 0; i < count; ++i) {
+		if (strcmp(name, fuzzer->name) == 0)
+			return fuzzer;
+		++fuzzer;
+	}
+
+	return NULL;
+}
+
+static struct udevice *find_fuzzing_engine(void)
+{
+	struct udevice *dev;
+
+	if (uclass_first_device(UCLASS_FUZZING_ENGINE, &dev))
+		return NULL;
+
+	return dev;
+}
+
+static int do_fuzz(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	struct fuzz_test *fuzzer;
+	struct udevice *dev;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	fuzzer = find_fuzz_test(argv[1]);
+	if (!fuzzer) {
+		printf("Could not find fuzzer: %s\n", argv[1]);
+		return 1;
+	}
+
+	dev = find_fuzzing_engine();
+	if (!dev) {
+		puts("No fuzzing engine available\n");
+		return 1;
+	}
+
+	while (1) {
+		const uint8_t *data;
+		size_t size;
+
+		if (dm_fuzzing_engine_get_input(dev, &data, &size)) {
+			puts("Fuzzing engine failed\n");
+			return 1;
+		}
+
+		fuzzer->func(data, size);
+	}
+
+	return 1;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char fuzz_help_text[] =
+	"[fuzz-test-name] - execute the named fuzz test\n"
+	;
+#endif /* CONFIG_SYS_LONGHELP */
+
+U_BOOT_CMD(
+	fuzz, CONFIG_SYS_MAXARGS, 1, do_fuzz,
+	"fuzz tests", fuzz_help_text
+);
diff --git a/test/fuzz/virtio.c b/test/fuzz/virtio.c
new file mode 100644
index 0000000..e5363d5
--- /dev/null
+++ b/test/fuzz/virtio.c
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2022 Google, Inc.
+ * Written by Andrew Scull <ascull@google.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <virtio.h>
+#include <virtio_ring.h>
+#include <test/fuzz.h>
+
+static int fuzz_vring(const uint8_t *data, size_t size)
+{
+	struct udevice *bus, *dev;
+	struct virtio_dev_priv *uc_priv;
+	struct virtqueue *vq;
+	struct virtio_sg sg[2];
+	struct virtio_sg *sgs[2];
+	unsigned int len;
+	u8 buffer[2][32];
+
+	/* hackily hardcode vring sizes */
+	size_t num = 4;
+	size_t desc_size = (sizeof(struct vring_desc) * num);
+	size_t avail_size = (3 + num) * sizeof(u16);
+	size_t used_size = (3 * sizeof(u16)) + (sizeof(struct vring_used_elem) * num);
+
+	if (size < (desc_size + avail_size + used_size))
+		return 0;
+
+	/* check probe success */
+	if (uclass_first_device(UCLASS_VIRTIO, &bus) || !bus)
+		panic("Could not find virtio bus\n");
+
+	/* check the child virtio-rng device is bound */
+	if (device_find_first_child(bus, &dev) || !dev)
+		panic("Could not find virtio device\n");
+
+	/*
+	 * fake the virtio device probe by filling in uc_priv->vdev
+	 * which is used by virtio_find_vqs/virtio_del_vqs.
+	 */
+	uc_priv = dev_get_uclass_priv(bus);
+	uc_priv->vdev = dev;
+
+	/* prepare the scatter-gather buffer */
+	sg[0].addr = buffer[0];
+	sg[0].length = sizeof(buffer[0]);
+	sg[1].addr = buffer[1];
+	sg[1].length = sizeof(buffer[1]);
+	sgs[0] = &sg[0];
+	sgs[1] = &sg[1];
+
+	if (virtio_find_vqs(dev, 1, &vq))
+		panic("Could not find vqs\n");
+	if (virtqueue_add(vq, sgs, 0, 1))
+		panic("Could not add to virtqueue\n");
+	/* Simulate device writing to vring */
+	memcpy(vq->vring.desc, data, desc_size);
+	memcpy(vq->vring.avail, data + desc_size, avail_size);
+	memcpy(vq->vring.used, data + desc_size + avail_size, used_size);
+	/* Make sure there is a response */
+	if (vq->vring.used->idx == 0)
+		vq->vring.used->idx = 1;
+	virtqueue_get_buf(vq, &len);
+	if (virtio_del_vqs(dev))
+		panic("Could not delete vqs\n");
+
+	return 0;
+}
+FUZZ_TEST(fuzz_vring, 0);
diff --git a/test/py/tests/test_stackprotector.py b/test/py/tests/test_stackprotector.py
index b009437..b87392c 100644
--- a/test/py/tests/test_stackprotector.py
+++ b/test/py/tests/test_stackprotector.py
@@ -5,6 +5,7 @@
 import signal
 
 @pytest.mark.buildconfigspec('cmd_stackprotector_test')
+@pytest.mark.notbuildconfigspec('asan')
 def test_stackprotector(u_boot_console):
     """Test that the stackprotector function works."""
 
diff --git a/tools/mips-relocs.c b/tools/mips-relocs.c
index 6252580..5db610f 100644
--- a/tools/mips-relocs.c
+++ b/tools/mips-relocs.c
@@ -312,7 +312,7 @@
 		goto out_free_relocs;
 	}
 
-	rel_pfx = is_64 ? ".rela." : ".rel.";
+	rel_pfx = is_64 ? ".rela" : ".rel";
 
 	for (i = 0; i < ehdr_field(e_shnum); i++) {
 		sh_type = shdr_field(i, sh_type);
@@ -321,10 +321,11 @@
 
 		sh_name = shstr(shdr_field(i, sh_name));
 		if (strncmp(sh_name, rel_pfx, strlen(rel_pfx))) {
-			if (strcmp(sh_name, ".rel") && strcmp(sh_name, ".rel.dyn"))
-				fprintf(stderr, "WARNING: Unexpected reloc section name '%s'\n", sh_name);
+			fprintf(stderr, "WARNING: Unexpected reloc section name '%s'\n", sh_name);
 			continue;
 		}
+		if (!strcmp(sh_name, ".rel") || !strcmp(sh_name, ".rel.dyn"))
+			continue;
 
 		/*
 		 * Skip reloc sections which either don't correspond to another
@@ -334,7 +335,7 @@
 		 */
 		skip = true;
 		for (j = 0; j < ehdr_field(e_shnum); j++) {
-			if (strcmp(&sh_name[strlen(rel_pfx) - 1], shstr(shdr_field(j, sh_name))))
+			if (strcmp(&sh_name[strlen(rel_pfx)], shstr(shdr_field(j, sh_name))))
 				continue;
 
 			skip = !(shdr_field(j, sh_flags) & SHF_ALLOC);