/*
* 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 {
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;
}