0

If I have an unsigned byte and I want push him in the stack, I must push a word." Why? I've read the x86 stack is word-based, but I don't understand...

For example, "push byte 0xa8" need the sign extension to word, so it's "push word 0x00a8". But with word, dword and qwords this don't happenn (more bytes to represent an unsigned).

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Rob
  • 99
  • 1
  • 9
  • 6
    "Why?". Because that's just how `PUSH` is implemented on x86 processors. Quoting from Intel's manual: _"The operand size (16, 32, or 64 bits) determines the amount by which the stack pointer is decremented (2, 4 or 8). If the source operand is an immediate and its size is less than the operand size, a sign-extended value is pushed on the stack."_ – Michael Jan 30 '15 at 10:32
  • Perfect! But has this some utility or purpose? Intel allow an unsigned word, dword and qword with a push, but if I want push an unsigned byte, I have push a word. I've see as a bug... – Rob Jan 30 '15 at 10:39
  • 4
    It is a simple counter-measure against mis-alignment. Pushing a byte will always misalign the subsequent data on the stack. Accessing misaligned data is expensive. – Hans Passant Jan 30 '15 at 11:23
  • possible duplicate of [PUSH unsigned dword in x86](http://stackoverflow.com/questions/28218021/push-unsigned-dword-in-x86) – Fifoernik Jan 31 '15 at 14:34
  • Related: [Why function parameter occupy at least 4 bytes stack on x86?](//stackoverflow.com/q/30679702) – Peter Cordes May 02 '18 at 11:53

1 Answers1

7

The general concept of a stack has a type, and you can push and pop items of that type. In case of x86, that type is the active operand size. It's not a bug.

"Intel allow" - no they don't. In 16 bit mode you can only push a word, nothing else. In 32 bit mode you can only push a dword, nothing else. In 64 bit mode you can only push a qword, nothing else (and you don't even get a 64 bit immediate version). That is without an override, but that's gonna get you into trouble fast. You don't get a 8 bit push because there is no 8 bit operation mode.

This also maintains the natural alignment of the stack. If you want to access byte data on the stack, you can treat it as general memory and use mov and other instructions as usual, after allocating an aligned chunk.

Jester
  • 56,577
  • 4
  • 81
  • 125
  • *That is without an override*: In case anyone's wondering what's actually encodeable, 16/32 bit mode: 16 and 32-bit. 64-bit mode: 16 and 64-bit, but not 32 (REX.W=0 doesn't work). See [How many bytes does the push instruction pushes onto the stack when I don't specify the operand size?](http://stackoverflow.com/q/45127993) As Jester says, you almost always should use `push` / `pop` with the default operand size for the mode you're in. Also: the manual: http://felixcloutier.com/x86/PUSH.html – Peter Cordes May 02 '18 at 11:50