Alignment and AMD64 fixes
authorRobert Pengelly <robertapengelly@hotmail.com>
Sat, 27 Jun 2026 07:30:14 +0000 (08:30 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Sat, 27 Jun 2026 07:30:14 +0000 (08:30 +0100)
amd64.c
parse.c

diff --git a/amd64.c b/amd64.c
index 2c84230ccd39822f149a34f47e46046a5940c14b..e1b74d1c76fc8cd47dff84cf456a2b66954dffb8 100644 (file)
--- a/amd64.c
+++ b/amd64.c
@@ -12296,11 +12296,23 @@ static void emit_load_const32_to_reg_now (const char *reg, int64_s v) {
     
     /*
      * A 32-bit integer constant loaded through the dword register form
-     * zero-extends the upper half of the AMD64 register.  Do not use a
-     * qword immediate move here: assemblers may choose a sign-extended
-     * imm32 encoding for values with bit 31 set, which is wrong for plain
-     * unsigned 32-bit constants promoted into a 64-bit register.
+     * zero-extends the upper half of the AMD64 register.  That is only
+     * correct when the folded value really fits in 32 bits.  Macro-expanded
+     * EFI status constants such as:
+     *
+     *     (0x8000000000000000LLU | 5)
+     *
+     * reach this helper through the generic foldable-expression path.  The
+     * old code always used the dword register name and silently discarded
+     * v.high, turning EFI_BUFFER_TOO_SMALL into plain 5 in comparisons.
      */
+    if ((v.high & U32_MASK) != 0) {
+    
+        amd64_emit_mov_i64_to_qword_reg_now (reg, v);
+        return;
+    
+    }
+    
     if (state->syntax & ASM_SYNTAX_INTEL) {
         fprintf (state->ofp, "    mov %s, %lu\n", dreg, v.low & U32_MASK);
     } else {
diff --git a/parse.c b/parse.c
index 7a8084d0835d463c5351537bacf9626f3450f443..447c0427c4d0b4d2a0967c983dee57d50fb3de4b 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -2359,6 +2359,21 @@ int type_alignment (int size) {
         return 2;
     }
     
+    /*
+     * Keep 64-bit scalar members naturally aligned.
+     *
+     * The old code capped aggregate member alignment at DATA_PTR, which
+     * makes i386 lay out uint64_t / EFI_LBA fields on 4-byte boundaries.
+     * That is wrong for PE/UEFI-style structures such as
+     * EFI_BLOCK_IO_MEDIA, where LastBlock must be read after the padding
+     * inserted before the 64-bit field.  Without this, code reads the
+     * preceding IoAlign field as the low half of LastBlock, which is how
+     * values such as 5 can appear for a disk size.
+     */
+    if (size == 8) {
+        return 8;
+    }
+    
     if (size >= DATA_PTR) {
         return DATA_PTR;
     }