News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Noob question re: pushing 16bit values

Started by blakkkrabbit, October 29, 2010, 10:45:11 PM

Previous topic - Next topic

blakkkrabbit

This cropped up from trying to push the values from a SYSTEMTIME struc as the arguments to printf - Am I right in thinking there's no instruction to push a 16bit value from memory, ending up as a zero extended 32bit value on the stack? (all the members of the SYSTEMTIME struc are words)

Started off with:

xor eax,eax
mov ax,w[offset some_systemtime_member]
push eax


then switched to this:

movzx eax,w[offset some_systemtime_member]
push eax


which works, I'm just not sure if it's appropriate (mainly if there are any side effects from the zero extension)


dedndave

you could probably use
        push dword ptr some_systemtime_member
in this case, DWORD PTR is actually used as an "over-ride" of sorts
i believe the upper word is ignored in PRINTF
so whatever is there (above some_systemtime_member) will be pushed and ignored

blakkkrabbit

I'll have to try that, using push without any overrides was my initial attempt and confused printf totally.

dedndave

well - there is nothing wrong with your method of zero-extending into EAX, either
i was thinking of conserving the contents of EAX, which isn't necessary, as it will be trashed by PRINTF, anyways    :U

Yuri

There's a PUSHW instruction which pushes a 16-bit value, but it doesn't extend it, you should do it manually, PUSHW'ing 16-bit zero before it. Maybe it doesn't suit your purpose, but here's an example:

TestStruct  STRUCT
    a   DW
    b   DW
    c   DW
ENDS

.DATA

ts      TestStruct <1, 2, 3>

.CODE

Start:
    pushw 0,[ts.c],0,[ts.b],0,[ts.a]
    invoke msvcrt:printf, "%d %d %d"
    add esp,10h
    ret


Also you can instruct printf to only use the low 16 bits of the numbers pushed on the stack with the normal PUSH:

TestStruct  STRUCT
    a   DW
    b   DW
    c   DW
ENDS

.DATA

ts      TestStruct <1, 2, 3>

.CODE

Start:
    push [ts.c],[ts.b],[ts.a]
    invoke msvcrt:printf, "%hd %hd %hd"
    add esp,10h
    ret

dedndave

the important thing is to keep the stack 4-aligned in 32-bit programs   :bg
i.e. the lower 2 bits of the stack pointer should always be 0

Yuri

Yes, it's explained in the GoAsm help file:
Quote
Half stack operations

This applies only to 32-bit programming.

In Win32 data on the stack is held in dwords, and the value of ESP is always on a dword boundary after a PUSH or POP operation. GoAsm does support half stack operations, however, which push onto and pop from the stack only two bytes at a time instead of four. When using these instructions you must push or pop a second time to restore ESP to a dword boundary. To make the syntax obvious, GoAsm requires the use of PUSHW and POPW for these half-stack operations. PUSH and POP cannot be used - they always perform a dword stack operation.

blakkkrabbit

Cool, thanks for the responses - I'd initially discounted PUSHW because of the issue with leaving the stack pointer offset by 2 bytes for the next operation, and

movzx eax,w[offset value]
push eax


seemed better than

pushw [offset value]
sub esp,2


but

pushw 0,[offset value]

is clearer

Thanks all.

Magnum

Re: Noob question re: pushing 16bit values

Noob has dropped out of favor and has been replaced by "greenhorn."  :U



Have a great day,
                         Andy

clive

Quote from: blakkkrabbit
pushw [offset value]
sub esp,2


pushw 0,[offset value]

But neither are atomic. There is very little advantage to using 16-bit values in a 32-bit machine. You would do far better by either zero extending (MOVZX), or sign extending (MOVSX) to 32-bits, or masking the value to 16-bits when/if appropriate in your computation(s).
It could be a random act of randomness. Those happen a lot as well.

blakkkrabbit

Which takes us back to the original question - there's no atomic operation to achieve this.  A naive look at the clocks for each approach suggests that movzx reg32,mem16
push reg32
takes about the same time as pushw imm16
pushw mem16

so it looks like there's actually no clear benefit to preferring one over the other, unless I've missed something?

jj2007

Quote from: blakkkrabbit on October 30, 2010, 07:00:56 PM
so it looks like there's actually no clear benefit to preferring one over the other, unless I've missed something?

Depends on what you call a clear benefit...
Intel(R) Celeron(R) M CPU        420  @ 1.60GHz (SSE3)
101     cycles for 100*2*pushw
24      cycles for 100*movzx

102     cycles for 100*2*pushw
24      cycles for 100*movzx


clive

Breaking stack alignment, bad plan

Intel(R) Atom(TM) CPU N270   @ 1.60GHz (SSE4)
121     cycles for 100*2*pushw
28      cycles for 100*movzx

118     cycles for 100*2*pushw
29      cycles for 100*movzx
It could be a random act of randomness. Those happen a lot as well.


blakkkrabbit

Ok so the movzx route works out around 4 times faster than the pushw (under test conditions)... thanks for all the help guys!