The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: raleeper on June 28, 2011, 11:49:17 PM

Title: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: raleeper on June 28, 2011, 11:49:17 PM
Rejected, A2026: constant expected.

But  xor [pointer], 33 xor 44  assembles without problem, so offset addr1 and offset addr2 must not be recognized as constants.  Adding parentheses is no help.

What dumb mistake am I making?

Thanks.
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: xandaz on June 29, 2011, 12:13:42 AM
   I don't think u can use memory to memory.... Try. I don't really understand what you're trying to do.
   you want to xor [pointer], offset addr1+offset addr2? Why do you want to use the offsets? you should use xor after pointer as in a real ASM opcode and then + operator which tells the assembler you want to xor both offsets.
   Bye and later
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: xandaz on June 29, 2011, 12:18:18 AM
    sorry ... i tried bu it didnt work. try this.

mov eax,offset addr1
xor eax,offset addr2
xor [pointer],eax
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: jj2007 on June 29, 2011, 12:19:22 AM
Tested with ML and JWasm:

include \masm32\include\masm32rt.inc
.data?
buffer db 100 dup(?)
.code
start:
mov esi, offset buffer
xor dword ptr [esi], 123
xor dword ptr [esi], offset buffer
inkey "OK"
exit
end start
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: raleeper on June 29, 2011, 12:40:34 AM
Quote from: xandaz on June 29, 2011, 12:13:42 AM
  I don't think u can use memory to memory.... Try. I don't really understand what you're trying to do.
  you want to xor [pointer], offset addr1+offset addr2? Why do you want to use the offsets? you should use xor after pointer as in a real ASM opcode and then + operator which tells the assembler you want to xor both offsets.
  Bye and later

I'm sorry.  I should have provided more context, and a more precise question.

The actual code I want to use is

xor DWORD PTR [kyptp], OFFSET kyptbl xor OFFSET kyptb2

kyptbl and kyptb2 are translation tables.

kyptp is a pointer initialized to kyptbl.  The xor instruction is meant to flip the pointer between the two tables, so that mov ebx, [kyptp] loads whichever table the user has selected by his last flip.

Since my initial post I tried some equates:

= 00000578         KKK1   =   OFFSET kyptbl
= 00000587         KKK2   =   OFFSET kyptb2
            KKKK   =   KKK1 xor KKK2
g:\lfw\lfw.asm(37) : error A2026: constant expected

Why is "KKK1 xor KKK2" not a constant?

Thanks.

mov eax,offset addr1
xor eax,offset addr2
xor [pointer],eax

Yes, I know I can do it that way,  and I will if necessary, but that's 3 lines of code and changes eax.
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: dedndave on June 29, 2011, 11:35:42 AM
it seems to me that this ought to work...
        xor DWORD PTR kyptp, OFFSET kyptbl xor OFFSET kyptb2
if not, try an EQUate...
AddrMask EQU OFFSET kyptbl xor OFFSET kyptb2
;
;
        xor DWORD PTR kyptp, AddrMask


the error that is reported describes a problem where the assembler does not know the address of the 2 items
it tries to resolve them in the first pass and cannot, as the addresses have not yet been assigned

i always get upset when i see this error, because it could just put a 0 in there and resolve it on the second pass

another way to go is to put some 32-bit value in there, then modify the operand at program init
a little exercise in self-modifying code   :P
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: dedndave on June 29, 2011, 12:10:07 PM
;program init code (executed once)

        push    eax
        push    esp
        push    eax
        INVOKE  VirtualProtect,offset Oprand-4,sizeof Oprand,PAGE_EXECUTE_READWRITE,esp
        mov     edx,offset Oprand-4
        mov     eax,offset kyptbl
        xor     eax,offset kyptb2
        mov     [edx],eax
        push    sizeof Oprand
        push    edx
        CALL    VirtualProtect
        pop     eax

;execution code

        xor     kyptp,80000000h   ;too large for signed byte form
Oprand  LABEL   DWORD


the init code may need to appear "below" the execution code in the source file
(otherwise, the assembler may not recognize the label "Oprand")
if so, just make it a PROC and call it
;program init code (executed once)

        call    Oinit

;execution code

        xor     kyptp,80000000h   ;too large for signed byte form
Oprand  LABEL   DWORD
;
;
;
Oinit   PROC

        push    eax
        push    esp
        push    eax
        INVOKE  VirtualProtect,offset Oprand-4,sizeof Oprand,PAGE_EXECUTE_READWRITE,esp
        mov     edx,offset Oprand-4
        mov     eax,offset kyptbl
        xor     eax,offset kyptb2
        mov     [edx],eax
        push    sizeof Oprand
        push    edx
        CALL    VirtualProtect
        pop     eax
        ret

Oinit   ENDP
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: jj2007 on June 29, 2011, 12:17:04 PM
Quote from: raleeper on June 29, 2011, 12:40:34 AM
Why is "KKK1 xor KKK2" not a constant?

Because they are variable...
If you see xor eax, 00401000 in Olly, then 00401000 looks pretty much like an integer constant. However, it has been put there at runtime by the PE loader. Try to use your code as a dll, and you will see the "constant" change...
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: dedndave on June 29, 2011, 12:18:51 PM
i don't think offsets are always relocatable, Jochen
i think it's a pass 1/pass 2 assembler issue
i may be wrong (again) - lol
either way, the code i posted should fly
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: raleeper on June 29, 2011, 01:34:10 PM
OK, it looks as if I am stuck with using, instead of:

xor dword ptr [kyptp], offset kyptbl xor offset kyptb2

which in my humble opinion is elegant, efficient and ought to work, another approach.  In my initialize code, just before invoke winmain, I have:

mov eax, offset kyptbl
xor eax, offset kyptb2
mov dword ptr [kyxor], eax


and to flip the pointer:

mov  eax, [kyxor]
xor  [kyptp], eax


And this works as intended [so far - crossed fingers emoticon?].

Thanks to all who responded.
javascript:void(0);
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: qWord on June 29, 2011, 01:53:50 PM
what is the purpose of combining two pointers using XOR? What result do you expect to get?
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: dedndave on June 29, 2011, 02:05:49 PM
you can still use the single instruction during execution
i guess you missed my previous post
here's a little update on it....
;program init code (executed once)

        call    Oinit

;execution code

        xor     kyptp,80000000h   ;too large for signed byte form
Oprand  LABEL   DWORD
;
;
;
Oinit   PROC

        push    edi
        push    eax
        mov     edi,offset Oprand-4
        push    esp
        push    eax
        INVOKE  VirtualProtect,edi,sizeof Oprand,PAGE_EXECUTE_READWRITE,esp
        mov     eax,offset kyptbl
        xor     eax,offset kyptb2
        mov     [edi],eax
        push    sizeof Oprand
        push    edi
        CALL    VirtualProtect
        pop     eax
        pop     edi
        ret

Oinit   ENDP


as for it being elegant, maybe not so much - lol
        xor     kyptp,immediate
this is not pretty, no matter how you do it   :P
the CPU has to interogate the value first (i.e. load the kyptp value into a temp register)
then XOR the immediate onto it
then store it
i think it's a 9-byte instruction   :red
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: raleeper on June 29, 2011, 04:13:27 PM
dedndave:

I have filed your code for later study on how to do self-modifying code.  It's more complicated than I want to get into now.

Thanks!
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: dedndave on June 29, 2011, 04:58:07 PM
ok - i made it look complicated by stack usage   :bg
here is a more generalized form that may be used for any dword value in the code section
ModDw   PROTO   :DWORD,:DWORD

;---------------------------------------------------------------------------------------

ModDw   PROC    uses edi dwAddress:DWORD,dwValue:DWORD

;Modify a DWORD in the code section
;DednDave 6-2011
;
;Call With: dwAddress = address of DWORD to modify
;           dwValue   = new DWORD value
;
;  Returns: EAX = status:
;                 non-zero = the DWORD was successfully modified
;                 zero     = error, the DWORD was not modified
;           EDX = original DWORD value

        LOCAL   dwFlag1:DWORD
        LOCAL   dwFlag2:DWORD

;save the original value on the stack

        mov     edi,dwAddress
        push dword ptr [edi]

;enable code section write

        INVOKE  VirtualProtect,edi,sizeof DWORD,PAGE_EXECUTE_READWRITE,ADDR dwFlag1
        or      eax,eax
        jz      ModDw0

;modify the value

        push    dwValue
        pop dword ptr [edi]

;restore the original protect flag

        INVOKE  VirtualProtect,edi,sizeof DWORD,dwFlag1,ADDR dwFlag2
        or      eax,1

ModDw0: pop     edx
        ret

ModDw   ENDP

;---------------------------------------------------------------------------------------


to use it...
;program init code (executed once)

        mov     eax,offset kyptbl
        xor     eax,offset kyptb2
        INVOKE  ModDw,offset Oprand-4,eax
        or      eax,eax
        jz      modification_failed

;execution code

        xor     kyptp,80000000h   ;too large for signed byte form
Oprand  LABEL   DWORD
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: xandaz on June 29, 2011, 06:20:36 PM
    Oh yeah.... it seems jj is right. they're variable. however it seems strange. If it assigns different offset as an EXE and as a DLL it does an then they're not variable anymore right? It would give errors on jump and call instructions also. Am i right. NO!!! laterz
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: dedndave on June 29, 2011, 08:23:21 PM
it must resolve the values as hard offsets when you create the DLL
just a guess   :P
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: raleeper on June 29, 2011, 08:48:21 PM
dedndave:

Quoteok - i made it look complicated by stack usage   BigGrin
here is a more generalized form that may be used for any dword value in the code section

Thanks, this looks great.  But I wasn't complaining when I said it was more complicated than I want to get into now.  Self-modifying code is complicated no matter how clear the example.  I've filed this whole topic for later.

Incidentally,
In Topic: Self Modify vs Jump Table
http://www.masm32.com/board/index.php?topic=15215.msg123564#msg123564

Redskull said:

QuoteEvery single instruction you execute will be a cache miss and a pipeline flush.  It's the anti-optimization.

Would that apply to your
Quote;execution code

        xor     kyptp,80000000h
?

Thanks, ral
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: redskull on June 29, 2011, 09:15:14 PM
If my memory serves, the problem is that assemble time operators are evaluted only during the first pass, whereas data can be reevaulted on the second.  This means that while static operations on static addressess would end up being a constant, like you supposed, MASM doesn't know for sure what it is yet when the xor is computed.  I seem to recall hard to track down macro bugs back when this was allowed, because if MASM needed to switch around the data on the second pass, the resolved constant would be out of date and you ended up with the wrong result.  Or maybe i'm just going senile.  Perhaps some of the crusty old-timers can chime in...

Anytime you change something that's in the cache you will take a performance hit; self-modifying code is particularly bad, because if the instructions are close together you have to throw out all the work the CPU did starting to decode and execute it.  The jump table for a emulator is a particularly bad idea, because every instruction of the emulated code requires restarting from scratch.  If you only do it once, though, the hit will be negligable.

-r
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: dedndave on June 29, 2011, 11:25:10 PM
the idea here is to modify the immediate operand once at program initialization
not related to the cache hit/miss issue
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: Antariy on June 30, 2011, 04:33:12 AM

xor dword ptr [kyptp], offset kyptbl xor offset kyptb2




offset kyptbl xor offset kyptb2


offsets are 32 bit width values which will be setup at *link* time. At assembly time there is no way for assembler to know what content will have these 32 bit values. I.e. - this is not constant at all. Anything stuff, which is computed at link time is "out-of-horizon" for the assembler => assembler does not know values at all.

When assembler found something like:


mov eax,offset somelabel


it puts into object file the code:


db 0b8,0,0,0,0 = mov eax,0


and marks second byte as DWORD location for the linker to patch this place as pointer at link time, when base address is known, plus offset itself.


In short: offsets are not constants, unless you're building executable manually.
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: jj2007 on June 30, 2011, 06:38:30 AM
Quote from: Antariy on June 30, 2011, 04:33:12 AM
When assembler found something like:


mov eax,offset somelabel


it puts into object file the code:


db 0b8,0,0,0,0 = mov eax,0


and marks second byte as DWORD location for the linker to patch this place as pointer at link time, when base address is known, plus offset itself.

In short: offsets are not constants, unless you're building executable manually.

Thanks, Alex - we came to the same conclusion, but it seems your explanation is the correct one :U
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: redskull on June 30, 2011, 11:29:38 PM
It's worth pointing out that they are "constant enough" if you are only doing addition or subtraction.  The assembler can just store whatever you are adding on as the value itself, and the fix-up by the linker adds the memory address as it becomes known.

-r
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: Antariy on July 01, 2011, 12:29:28 AM
Quote from: redskull on June 30, 2011, 11:29:38 PM
It's worth pointing out that they are "constant enough" if you are only doing addition or subtraction.  The assembler can just store whatever you are adding on as the value itself, and the fix-up by the linker adds the memory address as it becomes known.

That's right, but this is possible only if labels are in the same segment.


.nolist
include \masm32\include\masm32rt.inc
.686
.xmm

.data?
dd1 dd ?
ddarr dd 4 dup (?)
dd2 dd ?

newseg segment dword public "DATA"

dd3 dd ?

newseg ends

.code
start:

mov eax,offset dd2-offset dd1
print hex$(eax),13,10,13,10

mov eax,offset dd3-offset1 dd1 ; this will not compile
print hex$(eax),13,10


inkey
jmp crt__exit

end start

Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: Ian on July 01, 2011, 05:01:26 PM
This is a nice one. Another poster says "They're constant enough, when you're only adding
or subtracting". There's the clue, though I don't know what "adding" two addresses means.
Look in your listing. The result of "OFFSET" is an address, with attribute of its segment.
To do multiplication or XOR, you need a "NUMBER" type variable. Using TASM (and in others
I hope), when two addresses ("labels") are subtracted, the result is a number, which can then
be the subject of other arithmetic. So I set a label right at offset 0 in the segment, thus ...
ca0: ; Use this to change addresses into numbers.
(ca0 will have an offset of 0 in your listing.)
(It doesn't seem to matter what sort of label it is, so use an instruction label, it takes less typing..)
Then you can write
xor [pointer], (addr1-ca0) XOR (addr2-ca0).
Make sure the ca0 you use is in the same segment as the addrn ..
..
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: jj2007 on July 01, 2011, 06:28:32 PM
Ian,
Great 2nd post :U
This works indeed:
include \masm32\include\masm32rt.inc

.data
AppName db "Masm32:", 0
a1 db "test1", 0
a2 db "test2", 0

.code

start: mov eax, offset AppName
xor [eax], dword ptr (offset a1-AppName) xor (offset a2-AppName)
exit

end start


But warning: AppName is not necessarily at offset 0 in its segment, as include files may contain .data, too.
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: qWord on July 01, 2011, 06:49:01 PM
I'm still confused: What is the purpose of combining two pointers using XOR? - pleas clarify me.
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: dedndave on July 01, 2011, 07:15:40 PM
by XOR'ing the XOR of the 2 addresses, you can toggle the pointer back and forth between the two

who knows - it might be faster to....
Pointer1 dd Address1
Pointer2 dd Address2
;
;
;
        push    Pointer1
        push    Pointer2
        pop     Pointer1
        pop     Pointer2

then use Pointer1 as the "pointer in use"
XCHG with memory operands is slow   :P
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: Antariy on July 05, 2011, 02:06:18 AM
Quote from: Ian on July 01, 2011, 05:01:26 PM
Look in your listing. The result of "OFFSET" is an address, with attribute of its segment.

The point was: why are offsets not constants, and that is all - as the point of the listing.
Offset is an address which will be setup at link stage, and intersegment linking may have any layout. For DOS this is the segments of the executable, for Win32 this is sections...
Title: Re: Assembler: xor [pointer], offset addr1 xor offset addr2
Post by: Kopi on October 18, 2011, 01:13:49 PM
(Code to get what the asker wants)

Quote from: jj2007 on July 01, 2011, 06:28:32 PM
Ian,
Great 2nd post :U
This works indeed:
include \masm32\include\masm32rt.inc

.data
AppName db "Masm32:", 0
a1 db "test1", 0
a2 db "test2", 0

.code

start: mov eax, offset AppName
xor [eax], dword ptr (offset a1-AppName) xor (offset a2-AppName)
exit

end start


But warning: AppName is not necessarily at offset 0 in its segment, as include files may contain .data, too.


I think that the problem is solved by the post I've quoted, nonetheless I wish to summarize, since I've occourred in the same problem and I couldn't figure out what was going on, until I found the "Reply #19", wich stated that address are resolved at *link* time.
Right! When a .asm (with its includes) is compiled, all address calculated are relative to the beginning of its segment, taking into account of "org" statements and if the same segment appears more than once in the same asm and its includes, BUT NOT taking into account of other (or repeated) segments that appear in other asm. Thus, the actual absolute address where a certain "location" in the asm files will be loaded in memory, and even the offset relative to a segment (in case of a segment who appears in more than one asm, ie in more than one obj intermediate file), it's not known at assembly time, but only at link time: masm states (see error A2026) that expression must be resolved at assembly time.

To experiment and have a visual perception of what happends, try to compile this two sources and link them toghether with that command:

ml /AT /Fl /Sa 1.asm 2.asm

(The output will be a .com file, and so the executable contains only the compiled code and it's always loaded at offset 100h)

1.asm

c_ segment
org 100h
g proc
call main
mov ah, 4ch
int 21h
g endp
c_ ends

a segment
b db 1
off_d = $ - a
a ends

c_ segment
main proc near
mov al, off_d
mov bx, offset d + 1
mov cl, off_d XOR 0
ret
main endp
c_ ends

a segment
d db 1
a ends

end g


2.asm

a segment
off_last = $ - a ; Doesn't work good: off_last is relative to the beginning of this segment, not to the beginning of "a" in "1.asm"
last db 0ffh
a ends

h segment
i db 0eeh
h ends

end


Eventually, the .com files will contain:
c_segment (proc g, proc main, padding untill the end of paragraph).
a segment(b, d, padding untill the end of paragraph).
a segment(last, padding untill the end of paragraph).
h segment (i, no padding)


I've incurred in the same problem  with "offset" when I was trying to compute the memory needed to allocate a variable in a .com file with INT 21h / AH = 4Ah,
where the new size for the specified segment is expressed in "paragraphs", and so I'd liked to compute the paragraphs needed with: (Offset LastVariable + MyVarSize) / 10h + 1.
As I realized that the error "A2026: constant expected" was not because I used the OFFSET operand (OFFSET alone was not considered a constant), but because I also used the operand "/" (but using "+" or "-" was fine), I eventually reached that tutorial that explains MASM behaviour with great precision:
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_8/CH08-4.html#HEADING4-101

To summarize, the point is that a memory offset/address is not a constant nor a variable (see my example above), but it's a "reloc": a symbol that refers to a memory location. Since these symbols are converted in numeric values at link time, only some arithmetics are allowed on theese address symbols:
- Addition or subtraction of a constant from an offset: it produces just a "shift" in the address, that is stored in the obj file (see .lst files), and the definitive address is computed at link time.
- Subtraction of one address symbol from another address symbol: the result is a regular constant (not a reloc) and can be used in further calculations. That's the way to obtain what we want.



And so here's the work-around to obtain the effective address (relative offset in the segment) of a variable at assembly time, and make caclulations on it.
Keep in mind that, for all that is said, if the program consists of more .asm sources linked toghether, and the other sources contain the same sagment, and that source is put before in the linking order, that work-around doesn't work correctly.


Code SEGMENT

ORG 100h
Main PROC
MOV BX, 5
ADD BX, MyVarOff / 10h ; or XOR or any other operator
Main ENDP

Code ENDS

Variables SEGMENT
Any_Var DB 1
Any_OtherVar DD ?
MyVarOff = $ - Variables
MyVar DW 4 DUP (0EFh)
Variables ENDS

END main