diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index 1e418e69b58c87998f7e0673e87f7fa2e38aa21c..f32359cffb01b93be0c74f0a23ac9c992ecee7bf 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -96,15 +96,27 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
 {
 	s64 sval = do_reloc(op, place, val);
 
+	/*
+	 * The ELF psABI for AArch64 documents the 16-bit and 32-bit place
+	 * relative relocations as having a range of [-2^15, 2^16) or
+	 * [-2^31, 2^32), respectively. However, in order to be able to detect
+	 * overflows reliably, we have to choose whether we interpret such
+	 * quantities as signed or as unsigned, and stick with it.
+	 * The way we organize our address space requires a signed
+	 * interpretation of 32-bit relative references, so let's use that
+	 * for all R_AARCH64_PRELxx relocations. This means our upper
+	 * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX.
+	 */
+
 	switch (len) {
 	case 16:
 		*(s16 *)place = sval;
-		if (sval < S16_MIN || sval > U16_MAX)
+		if (sval < S16_MIN || sval > S16_MAX)
 			return -ERANGE;
 		break;
 	case 32:
 		*(s32 *)place = sval;
-		if (sval < S32_MIN || sval > U32_MAX)
+		if (sval < S32_MIN || sval > S32_MAX)
 			return -ERANGE;
 		break;
 	case 64: