Re: Some confusion on Stack operation



"Herbert Kleebauer" <klee@xxxxxxxxx> wrote in message
news:440EA74C.8F207801@xxxxxxxxxxxx
Rod Pemberton wrote:
"Frank Kotler" <fbkotler@xxxxxxxxxxx> wrote in message
<zhangyue.zl@xxxxxxxxx> wrote in message
news:1141539835.500432.269980@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Under protected mode, ...

Just a nit-pick... I assume you mean 32-bit pmode. There *is* a 16-bit
pmode, where "push ax" would be the "normal thing". Rarely used.

Technically, yes. But 32-bit protected mode is known as protected mode
(PM)
and 16-bit protected mod is called virtual 8086 (V86).

No. From the x86 manual:

The IA-32 processors function most efficiently when executing 32-bit
program modules. They
can, however, also execute 16-bit program modules, in any of the
following ways:
. In real-address mode.
. In virtual-8086 mode.
. System management mode (SMM).
. As a protected-mode task, when the code, data, and stack segments for
the task are all
configured as a 16-bit segments.
. By integrating 16-bit and 32-bit segments into a single protected-mode
task.
. By integrating 16-bit operations into 32-bit code segments.


Which was taken out of context:
"Real-address mode, virtual-8086 mode, and SMM are native 16-bit modes. A
legacy program
assembled and/or compiled to run on an Intel 8086 or Intel 286 processor
should run in real address
mode or virtual-8086 mode without modification. Sixteen-bit program modules
can also
be written to run in real-address mode for handling system initialization or
to run in SMM for
handling system management functions."

Since they are RM, we can cross the first three off that list. We can cross
the sixth off the last because it is done by using the "operand-size prefix
(66H)" and the "address-size prefix (67H)." We can cross the fourth off the
list, since it's unlikely the anyone would ever create a dedicated 16-bit PM
OS. What's the point, when you've got RM, V86, PM and SMM? This mode is
never used. That leaves the fifth case: a 16-bit TSS which Intel supports
but obsoleted.

Here are the warnings and obsoletion from "IA-32 Intel(C) Architecture
Software Developer's Manual Volume 3A: System Programming Guide, Part 1,
Order Number: 253668-018, Jan 2006"

1) Warning #1
"CHAPTER 16 8086 EMULATION"
"Intel Architecture processors (beginning with the Intel386 processor)
provide two ways to
execute new or legacy programs that are assembled and/or compiled to run on
an Intel 8086
processor:
* Real-address mode.
* Virtual-8086 mode."

2) Warning #2
"17.27.4. Using A 16-Bit TSS with 32-Bit Constructs
Task switches using 16-bit TSSs should be used only for pure 16-bit code.
Any new code written
using 32-bit constructs (operands, addressing, or the upper word of the
EFLAGS register)
should use only 32-bit TSSs. This is due to the fact that the 32-bit
processors do not save the
upper 16 bits of EFLAGS to a 16-bit TSS. A task switch back to a 16-bit task
that was executing
in virtual mode will never re-enable the virtual mode, as this flag was not
saved in the upper half
of the EFLAGS value in the TSS. Therefore, it is strongly recommended that
any code using
32-bit constructs use a 32-bit TSS to ensure correct behavior in a
multitasking environment."

3) Warning #3
"6.6 16-BIT TASK-STATE SEGMENT (TSS)
The 32-bit IA-32 processors also recognize a 16-bit TSS format like the one
used in Intel 286
processors (see Figure 6-10). This format is supported for compatibility
with software written
to run on earlier IA-32 processors.
The following information is important to know about the 16-bit TSS.
* Do not use a 16-bit TSS to implement a virtual-8086 task.
* The valid segment limit for a 16-bit TSS is 2CH.
* The 16-bit TSS does not contain a field for the base address of the page
directory, which is
loaded into control register CR3. A separate set of page tables for each
task is not
supported for 16-bit tasks. If a 16-bit task is dispatched, the page-table
structure for the
previous task is used.
* The I/O base address is not included in the 16-bit TSS. None of the
functions of the I/O
map are supported.
* When task state is saved in a 16-bit TSS, the upper 16 bits of the EFLAGS
register and the
EIP register are lost.
* When the general-purpose registers are loaded or saved from a 16-bit TSS,
the upper 16
bits of the registers are modified and not maintained."

4) Obsoletion (all "Reserved" for IA-32e)
"Table 3-2. System-Segment and Gate-Descriptor Types
Type Field Description
Decimal 11 10 9 8 32-Bit Mode IA-32e Mode
0 0 0 0 0 Reserved Upper 8 byte of an 16-byte descriptor
1 0 0 0 1 16-bit TSS (Available) Reserved
2 0 0 1 0 LDT LDT
3 0 0 1 1 16-bit TSS (Busy) Reserved
4 0 1 0 0 16-bit Call Gate Reserved
5 0 1 0 1 Task Gate Reserved
6 0 1 1 0 16-bit Interrupt Gate Reserved
7 0 1 1 1 16-bit Trap Gate Reserved
...."


if we do a Push operation,says PUSH AX,although
AX is a 16bit register,is there any possiblity that it will occupy 4
bytes in the stack?

I would have said "no", but apparently the correct answer is "not
unless
your assembler's broken"...

That's not true. There is nothing in the Intel spec's that requires an
assembler to differentiate between 'push ax' and 'push eax'. The actual
instruction coding is the same. The assembler must generate the same
instruction sequence for both. However, it can apply a size override
prefix
to do more of what the user expects.

'push ax' and 'push eax' are completely different instructions and if an
assembler generates the same opcode for both instructions, then the
assembler is "broken".

Incorrect, as previously stated.


Yes. In protected mode (32-bit), _all_ stack operations are 4 bytes
by
default. That includes pushing and popping 16-bit and 8-bit values.
They
are all converted to 4 bytes prior to pushing A byte can never be
pushed
onto the stack. A word, or 2 bytes, will only be pushed onto the
stack if
the assembler inserts a size override prefix (db 0x66) for the
instruction.
Some assemblers do this and some don't.

Which don't? I would consider this "silently emits bad code"!!!

I ported a large piece of assembly between GAS,WASM and NASM a while
ago.
IIRC (it was a while ago...), GAS won't emit, WASM (OpenWatcom) will
emit,
NASM does under certain situations.

You really know an assembler which generates the same opcode for 'push ax'
and
'push eax'? Can you please post the listing with the generated opcodes.

I do know some assemblers won't generate 'push eax' for 16-bit mode. And, I
know some do and some don't insert instruction prefixes for various
instructions. Anyway, I already told the OP how to tell if his is
generating the correct sequences or not. If he has a dissassembler, he
doesn't need to post here to found out...


As you can see from the table, "PUSH EAX" and "PUSH AX" have the same
binary
sequence. Some assemblers code to the Intel spec's and some code to
user
expectations...

FF /6 PUSH r/m16
FF /6 PUSH r/m32

You shouldn't stop reading after a few lines, read the complete
specification of the push instruction:

Operation
IF StackAddrSize = 32
THEN
IF OperandSize = 32
THEN
ESP <- ESP - 4;
SS:ESP <- SRC; (* push doubleword *)
ELSE (* OperandSize = 16*)
ESP <- ESP - 2;
SS:ESP <- SRC; (* push word *)
FI;
ELSE (* StackAddrSize = 16*)
IF OperandSize = 16
THEN
SP <- SP - 2;
SS:SP <- SRC; (* push word *)
ELSE (* OperandSize = 32*)
SP <- SP - 4;
SS:SP <- SRC; (* push doubleword *)
FI;
FI;


You shouldn't post without understanding what that means. That supports my
case, not yours.

What that says is:

1) if the default mode is 16-bit, "50+ rw PUSH r16" or "50+ rd PUSH r32",
will push 16-bits and decrement SP by 2.
2) if the default mode is 32-bit, "50+ rw PUSH r16" or "50+ rd PUSH r32",
will push 32-bits and decrement ESP by 4.
3) if the default mode is 16-bit and if "50+ rw PUSH r16" or "50+ rd PUSH
r32" is prefixed with an size overide prefix, it will push 32-bits and
decrement SP by 4.
4) if the default mode is 32-bit and if "50+ rw PUSH r16" or "50+ rd PUSH
r32" is prefixed with an size overide prefix, it will push 16-bits and
decrement ESP by 2.

Nowhere does it say that the instruction encoding includes an instruction
prefix. You might want to read section "2.2. INSTRUCTION PREFIXES" Intel
only says the intruction encoding for 'push eax' or 'push ax' is:

50+ rw PUSH r16
50+ rd PUSH r32

Since the encoding are the same for "50+ rw PUSH r16" and "50+ rd PUSH r32",
you only need to read one of the many another instruction descriptions which
covers the use identical encoding, duplicate mnemonics, and has an operand
size prefix in it's instruction flow sequence:

"The PUSHA (push all) and PUSHAD (push all double) mnemonics reference the
same opcode.
The PUSHA instruction is intended for use when the operand-size attribute is
16 and the
PUSHAD instruction for when the operand-size attribute is 32. Some
assemblers may force the
operand size to 16 when PUSHA is used and to 32 when PUSHAD is used. Others
may treat
these mnemonics as synonyms (PUSHA/PUSHAD) and use the current setting of
the operandsize
attribute to determine the size of values to be pushed from the stack,
regardless of the
mnemonic used."


In PM, db 0x66 ?

Again, in 32-bit protected mode...

32-bit PM, not V86 mode.

There is also a "16-bit PM, not V86 mode".

Obsolete or unused.

Right. Real mode is always 16-bit (although some people claim 32-bit
rmode *does* exist... I guess that's true, but it isn't useful)

I think it's the opposite: 32-bit rmode *does NOT* exist... but it would
be extremely useful (imagine a 32 bit real mode DOS).

(You're responding to Frank's comments.)


Maybe I'm just assuming that the way Nasm does things is a "law of
nature", but if I'm doing 32-bit code (how we inform the assemmbler of
this differs), and I write "push ax", I expect the assembler to emit
the
0x66, and I expect it to take two bytes on the stack. If other

How do you specify in NASM that you want to push the 16 bit DS in 32 bit
mode (or 32 bit DS in 16 bit mode)?
00000000: 66 1e move.w s0,-(sp)
00000002: 1e move.l s0,-(sp)

(Again, you're responding to Frank's comments.)

assemblers don't do it this way, I can see it would cause... the
subject
line...

That's a user expectation which isn't guaranteed.

Then it shouldn't be a problem for you, to show us a concrete
example (post the generated listing).

I don't have waste my time doing so. Intel agrees with me. My code is
littered
with comments on the problem for various instructions. And, I told the OP
how
to find out if he has an issue.


Rod Pemberton


.



Relevant Pages

  • Re: Some confusion on Stack operation
    ... By integrating 16-bit and 32-bit segments into a single protected-mode task. ... assembler to differentiate between 'push ax' and 'push eax'. ... instruction coding is the same. ...
    (alt.lang.asm)
  • Re: To Richard Heathfield: enoughs enough
    ... > A single CISC instruction that searches for a NUL byte takes Otime. ... language" in a typical machine with a typical stack. ... push intIndex1 ...
    (comp.programming)
  • Re: Linux, X, ld, gcc, linking, shared libraries and stuff
    ... To choose the most appropriate encoding for a given ... optimization only within a single instruction (choose the ... Therefore if you want to push a 10 onto the stack, RosAsm ...
    (alt.lang.asm)
  • Re: C++ Object Pointers
    ... I shoud add that on a RISC machine, a call is a control transfer, so the RISC equivalent ... because the call instruction will transfer control but the instruction following it will ... >push the return ...
    (microsoft.public.vc.mfc)

Loading