flat assembler
Message board for the users of flat assembler.

flat assembler > Main > x86_64 cheat sheet?

Author
Thread Post new topic Reply to topic
redsock



Joined: 09 Oct 2009
Posts: 327
Location: Australia
When I was watching/participating in @Tomasz live streaming, one of the things that caught my eye was the instruction encodings when in long mode... I think I -incorrectly- assumed many years ago when I was learning it that when 64 bit mode was enabled, that the default encodings for 64 bit regs was better(smaller) than their now-32-bit-strangeness counterparts.

mov eax, ecx vs. mov rax, rcx

or:

lea rcx, [rax+rdx*2] vs. lea ecx, [eax+edx*2]

I am not aware of any document that specifically says: use 32 bit regs unless you really need the additional higher word, or what effect that really has on the underlying encodings.

Is this documented somewhere obvious in fasm documentation that I just missed?

Without revisiting the videos or actually trying the various encodings myself, I am -still- not sure, and was just having a conversation about whether, when in 64 bit mode, to use 64 bit regs or carry on with 32 bit regs.

of course, i could have done searches, but it is better to just ask, right? /lazy Smile

_________________
2 Ton Digital - https://2ton.com.au/
Post 28 Sep 2019, 07:35
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 16782
Location: In your JS exploiting you and your system
The REX prefixes say it all to me. I always saw those as modifying the following normal 32-bit encoding. Of course that isn't really 100% correct, but as a basic starting point it works fine.

It is easy to forget to go back to using 32-bit names when the result is still a valid full 64-bit value. And it makes doing search-and-replace a bit more tricky with needing to consider two names for the same register..

The following two instructions generate exactly the same result ...
Code:
xor eax,eax
xor rax,rax    
... but one of them has a longer encoding with REX.
Post 28 Sep 2019, 08:49
View user's profile Send private message Visit poster's website Reply with quote
sts-q



Joined: 29 Nov 2018
Posts: 26
redsock, i think you know about this cheat sheet:

https://www.felixcloutier.com/x86/xor
Post 28 Sep 2019, 09:28
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 7372
Location: Kraków, Poland
The documentation of fasm may not answer such questions, because it generally aims to define syntax, with focus on the details that may differ from the x86 dialects of other assemblers. The right place to go for such answers is in the official manuals of CPU (either Intel of AMD ones).

As noted by revolution above, the long mode mostly retains the meaning of legacy 32-bit instruction codes and REX prefix is needed to move outside of this operand space. This leads to a simple rule of thumb:
As long as the operands are such that the same instruction could be used in 32-bit mode, it does not require REX prefix.
For example:
Code:
; only legacy register names used, REX not needed:
        xor     cl,dl
        add     ax,1
        mov     eax,ebx

; some new register names used, REX required:
        xor     cl,sil
        add     r10w,1
        mov     rax,rbx    
In addition to that, register names that correspond to the high 8 bits of a 16-bit registers (that is: AH, CH, DH, BH) cannot be encoded when REX is present (because their corresponding codes are repurposed to refer to SPL, BPL, SIL and DIL). This means that it is not possible to mix them with any of the new registers:
Code:
; instructions that cannot be encoded:
        xor     ch,sil
        movzx   r10w,ah
        movzx   rax,bh    


Then we also have an exception to the above rule of thumb. Instructions that push to the stack of pop from it, use 64-bit operands and do not need REX for it:
Code:
; operations on stack that use 64-bit operand size without REX:
        push    rax
        retq
; (analogous 32-bit operations are not possible at all)

; However, REX is still needed to access new registers that do not correspond to legacy ones:
        push    r10    


Also, registers used in memory addressing are by default 64-bit, but in this case it is possible to turn them back to 32-bit ones with help of a 67h prefix:
Code:
; no REX and no 67h prefix required:
        mov     eax,[rbx]
; REX required, but no 67h prefix:
        mov     rax,[rbx]
        mov     r10d,[rbx]
; no REX, but 67h prefix required:
        mov     eax,[ebx]
; both REX and 67h prefix required:
        mov     rax,[ebx]
; (note that REX needs to be the last of prefixes, it has to be right next to the opcode )    


By the way, recently I've been working on some diagrams explaining x86 encodings. I may publish some of them on this board, at least the ones that do not get published elsewhere. Please keep an eye out for them!
Post 28 Sep 2019, 13:02
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
@redsock

Perhaps you're confusing data operands to pointer operands. In long mode, the best practice is to stick to 64-bit pointer because it's the default pointer size. I mean, always use 64-bit thingy when it comes to addressing and pointers in long mode.

This is especially crucial in pointer arithmetics. It's easy, for example, to get roll-over when using 32-bit operands because they are bound to 32-bit arithmetics.

Eg, Linux64 uses high-addresses. Win64 in some cases, uses high addresses as well, especially in LIB static linking. If your 64-bit pointer is close to a 32-bit boundary, any further 32-bit arithmetics upon it will trigger a roll-over (eg, your higher portion of RDI will be clearead) and your, say STOSB, will point to a hostile address.

Just sharing a nasty experience Sad


Last edited by fasmnewbie on 10 Oct 2019, 11:17; edited 1 time in total
Post 10 Oct 2019, 04:49
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
Btw, I am still not sure how to catch a rollover. Do Carry and Aux good enough for capturing a rollover? Havent actively coding for almost 6 months now and I already forgot how to program. Getting old...
Post 10 Oct 2019, 04:58
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 7372
Location: Kraków, Poland
fasmnewbie wrote:
Btw, I am still not sure how to catch a rollover. Do Carry and Aux good enough for capturing a rollover? Havent actively coding for almost 6 months now and I already forgot how to program. Getting old...
Flags like CF do catch a rollover, but when you have a 64-bit address in a register and then do a 32-bit operation on that register, which clears the upper 32 bits of the address, this is not a "rollover". You are then simply breaking your pointer by zeroing its upper bits.
Post 10 Oct 2019, 08:27
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 552
@Tomasz

Off-topic.

Is it safe to conclude that the CF+AF combo (both set) can be used to signal a rollover, at least for ADD instruction? Looks to me it gives consistent result for every possible addend that causes rollover.

Ex:
Code:
    mov rax,-1      ; populate all

    ;Alternate one of these...
    add rax,0       ; CF=0, AF=0
    add rax,1       ; CF=1, AF=1
    add rax,-2      ; CF=1, AF=1    


CF+OF means something else (in the manual) so I have this feeling that CF+AF combo does signal a rollover. Perhaps, CF or AF alone is enough?

Anyway...unfortunately, this doesn't work with MUL.
Post 10 Oct 2019, 10:22
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 7372
Location: Kraków, Poland
AF is similar to CF, but it does it for the number in the low 4 bits (low nibble) of the operand. Therefore it is very unlikely to do what you want. But if you just want to detect a "rollover", CF should be enough.

BTW, recently I've been planning to record a tutorial on mapping the 2-adic numbers to fixed-bit-count registers and how it translates to operation of CF, OF, etc. You just gave me additional motivation to work on it.
Post 10 Oct 2019, 11:07
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2019, Tomasz Grysztar.

Powered by rwasa.