1

The code below is contained in a FAT16 boot sector at offset 0x3E of the 512 byte sector. At boot time the sector is loaded to memory at location 0:0x7C00. The first three bytes of the sector are:

EB 3C 90

which translate to the following jump instruction:

JMP SHORT 0x3E

which jumps to the start of the code listed below.

My question is about the push and the pop instructions in the last two lines listed below.
The push pushes the byte 0x54 to location 0x7BFF. The pop instruction pops the bytes located at 0x7C00 & 0x7BFF into the ES register. So ES = 0xEB54. But isn't that a very unusual thing to do? It pops a byte that was never even pushed. Furthermore, the value in ES will eventually be used for a specific purpose later on in the boot sector code.

MY QUESTION: What value is popped into ES in the last line below?

xor ax,ax
mov ds,ax
mov ss,ax
mov sp,0x7c00
mov bp,sp
cld
sti
mov [bp+0x24],dl
mov al,[bp+0x10]
mul word [bp+0x16]
add ax,[bp+0xe]
adc dl,dh
add ax,[bp+0x1c]
adc dx,[bp+0x1e]
push byte +0x54
pop es
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
bilsch01
  • 31
  • 3

1 Answers1

3

Despite the naming, push byte +0x54 actually pushes a word, so the value in es at the end is simply 0x0054. x86 has no instruction to literally push just a single byte.

You didn't say what assembler you're using, but the byte probably tells the assembler to choose the push imm8 encoding (opcode 6a), with an 8-bit immediate which is sign-extended to a 16-bit word, instead of push imm16 (opcode 68). See https://www.felixcloutier.com/x86/push

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • Sane assemblers will already pick the smallest encoding for an instruction, so for a numeric literal (not something to be filled in by the linker) it's completely pointless (and confusing for some readers) to write `push byte`. In NASM, you'd write `push strict byte` or `strict word` to force the immediate encoding (and also operand-size), but there's almost never a reason to do that, except maybe to force a wider encoding for self-modifying code. But never a byte encoding, unless maybe `nasm -O0` doesn't bother to find the smallest encoding otherwise and you want to disable optimization. – Peter Cordes Jan 14 '21 at 08:01
  • If you did want an 8-bit symbol relocation for a push dword imm8, I'm not sure if there's a way to tell NASM about it if dword isn't already the default operand-size. e.g. `push dword strict byte symname` is just push dword imm32, treating it like "strict dword". https://godbolt.org/z/E6oe11. Anyway, related Q&A: [How many bytes does the push instruction push onto the stack when I don't specify the operand size?](https://stackoverflow.com/q/45127993) has more about the available operand-sizes in general. – Peter Cordes Jan 14 '21 at 08:02
  • 2
    Oh, I bet it's disassembler output. This is exactly the syntax that `ndisasm` produces, with the redundant `byte` and `+`. – Nate Eldredge Jan 14 '21 at 15:32
  • Thank you for explaining the answer. Bill S. – bilsch01 Jan 15 '21 at 16:26