Skip to main content
GameDev.net gamedev.net
🔒 Locked

Asm question..

Started by eq Sep 10, 2006 at 6:20 AM 18 replies 1.9k views
Original Post
eq
eq
I've been programming for 20+ years and quite a lot of x86 asm (albeit not that much for the last 5 years). Now I'm at it again and wrote something like this: mov DWORD PTR 0x12345678, ecx Hoping to write the content of the eax register to the address 0x12345678. I was very surprised that the code compiled into B8 00 00 00 00 which is equal to: mov eax, 0 I was dead certain that you could write to absoulte addresses on the x86. Could someone please confirm that it's impossible to write to an address directly like the above? Edit: I realize that there are plenty of ways to write to an address, just no way of doing it without using one register..or? [Edited by - eq on September 10, 2006 6:40:34 AM]
bakery2k1
bakery2k1
It is certainly possible to write to an absolute address. What assembler are you using?
eq
eq
I'm using the inline assembler to the Intel Cpp Compiler (v8).

I'm about to loose it right now :)

Trying to find some good explenation about the mod R/M byte in an opcode to construct the mov my self...

Hmm, maybe things get assembled to the right opcodes but the debugger is giving me something bad back...

I'll try to see if it writes things to the correct location..

Edit:
The following code:
	__asm	{		int 3;		mov 0, ecx		mov 0x12345678, ecx		mov DWORD PTR 0x12345678, ecx		int 3;	};


Gives the following diassembled code:
0072F7E6 CC                   int         30072F7E7 B8 00 00 00 00       mov         eax,00072F7EC B8 00 00 00 00       mov         eax,00072F7F1 B8 00 00 00 00       mov         eax,00072F7F6 CC                   int         3
Almonsin
Almonsin
In NASM it would be:
mov [0x12345678], ecx
eq
eq
Quote:

In NASM it would be:
mov [0x12345678], ecx


Interesting, what bytes does this generate?
Would be great if you could send me the code generates for a few of thoose, i.e:
mov [0x12345678], eaxmov [0x12345678], ebxmov [0x12345678], ecxmov [0x12345678], edxmov [0x12345678], edimov [0x12345678], esimov [0x12345678], axmov [0x12345678], bxmov [0x12345678], cxmov [0x12345678], dxmov [0x12345678], almov [0x12345678], blmov [0x12345678], clmov [0x12345678], dlmov [0x12345678], ahmov [0x12345678], bhmov [0x12345678], chmov [0x12345678], dh


Then I might be able to code a function that creates the opcode.

Tried:
	__asm	{		int 3;		mov [0], ecx		mov [0x12345678], ecx		mov DWORD PTR [0x12345678], ecx		int 3;	};


Gives exactly the same code produced as:

	__asm	{		int 3;		mov 0, ecx		mov 0x12345678, ecx		mov DWORD PTR 0x12345678, ecx		int 3;	};


eq
eq
I tried the same code with the good old MSVC6, got the following error on all 3 instructions:
error C2415: improper operand type

Using Intel CPP compiler v9 I got:
error: __asm 'mov' unsupported instruction form

freenit_
freenit_
Hi.

You can make something like this:

mov dword ptr DS:[01234567h], eax

or

mov dword ptr CS:[01234567h], eax

It works fine in MASM32

PS

It is translated to:
00401001 2E:A3 67452301 MOV DWORD PTR CS:[1234567],EAX
00401006 A3 67452301 MOV DWORD PTR DS:[1234567],EAX

---http://gamescreators.sf.net -- linux games programers community
eq
eq
	__asm	{		int 3;		mov ds:[0], ecx		mov ds:[0x12345678], ecx		mov DWORD PTR ds:[0x12345678], ecx		int 3;	};


Seems to work, translates into:

0072F7E6 CC                   int         30072F7E7 3E 89 0D 00 00 00 00 mov         dword ptr ds:[0],ecx0072F7EE 3E 89 0D 78 56 34 12 mov         dword ptr ds:[12345678h],ecx0072F7F5 3E 89 0D 78 56 34 12 mov         dword ptr ds:[12345678h],ecx0072F7FC CC                   int         3


Thanks all..
Almonsin
Almonsin
NASM generated:

00000000 A378563412 mov [0x12345678],eax
00000005 891D78563412 mov [0x12345678],ebx
0000000B 890D78563412 mov [0x12345678],ecx
00000011 891578563412 mov [0x12345678],edx
00000017 893D78563412 mov [0x12345678],edi
0000001D 893578563412 mov [0x12345678],esi

00000023 66A378563412 mov [0x12345678],ax
00000029 66891D78563412 mov [0x12345678],bx
00000030 66890D78563412 mov [0x12345678],cx
00000037 66891578563412 mov [0x12345678],dx

0000003E A278563412 mov [0x12345678],al
00000043 881D78563412 mov [0x12345678],bl
00000049 880D78563412 mov [0x12345678],cl
0000004F 881578563412 mov [0x12345678],dl

00000055 882578563412 mov [0x12345678],ah
0000005B 883D78563412 mov [0x12345678],bh
00000061 882D78563412 mov [0x12345678],ch
00000067 883578563412 mov [0x12345678],dh
Almonsin
Almonsin
Oh, as I see the problem has been already solved.

BTW, could you tell me how to make those beautiful code boxes in the post?
I can't do it, and when I include code source, it's so ugly.
Penten
Penten
Quote:
Original post by morgue
Oh, as I see the problem has been already solved.

BTW, could you tell me how to make those beautiful code boxes in the post?
I can't do it, and when I include code source, it's so ugly.


Tadaa (the source tag section)
Almonsin
Almonsin
Thank you, Penten
LessBread
LessBread
Quote:
Original post by eq
mov ds:[0], ecx


It seems to me that in 32 bit protected mode, this would throw an access violation exception. That is, it's trying to write to a null pointer.

"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
eq
eq
Quote:
Original post by LessBread
Quote:
Original post by eq
mov ds:[0], ecx


It seems to me that in 32 bit protected mode, this would throw an access violation exception. That is, it's trying to write to a null pointer.


Yes of course it would.
I just used 0 and 0x12345678 as an example!!

In my application I actually generates machine code on the fly,
I dynamically generate machine code and the address 0x12345678 or 0 could be replaced with the address of a variable for instance.
This is all about optimization to the extrema...

The mov ds:[address], reg works really good, I haven't profiled the code using this instruction though, are there some penelties involved in using the segment registers like this?

I.e would it be faster to do:
mov eax, 0x12345678 ; Again 0x12345678 is used as an examplemov [eax], ecx


The above should have a stall for using the address (eax) to close to the generation, right?

What about:
mov eax, 0x12345678 ; Again 0x12345678 is used as an example..do plenty of stuff to hide the stall..mov [eax], ecx


..is that faster than,
..do the same stuff as above..mov ds:[0x12345678], ecx ; Again 0x12345678 is used as an example

..because of some penelty?

I haven't bothered learning about stalls and pipelining since the Pentium Pro processor... shame on me :)
LessBread
LessBread
Quote:
Original post by eq
The mov ds:[address], reg works really good, I haven't profiled the code using this instruction though, are there some penelties involved in using the segment registers like this?


On Windows in user mode the segments are coterminus (except for %fs which is used for exception handling). That is, %cs,%ds, %es, %ss are all used to describe the full address range 0 -> 4 GB. Most of the time they are assumed, depending on how the address is used. Instruction addresses (in %eip) assume %cs, stack instructions assume %ss, and data addresses assume %ds or %es depending on whether the address is a source or a destination. Afaik, the penalty is adding an extra byte to the instruction. Kernel mode is another matter. Switching into kernel mode entails reloading the segment registers (the OS/CPU does that as part of the jump). If you're not going to be entering kernel mode, you shouldn't need to use the segment registers at all (unless you're coding your own exception handlers too in which case you would need to use %fs).

I'm not even certain if you can do that on XP anymore anyway.

Quote:
Original post by eq
I.e would it be faster to do:
*** Source Snippet Removed ***
The above should have a stall for using the address (eax) to close to the generation, right?


I don't know. I haven't tested that. But...

mov eax, 0x12345678;

is just moving a number into a register. It's not an address until you use it as one, for example, with

mov [eax], ecx

Quote:
Original post by eq
What about:
*** Source Snippet Removed ***
..is that faster than,
*** Source Snippet Removed ***
..because of some penelty?
I haven't bothered learning about stalls and pipelining since the Pentium Pro processor... shame on me :)


I haven't studied those things either. This might help with that: Software optimization resources.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
bakery2k1
bakery2k1
Quote:
Original post by eq
The mov ds:[address], reg works really good, I haven't profiled the code using this instruction though, are there some penelties involved in using the segment registers like this?


The use of the segment register in the instruction causes the assembler to generate a ds segment register override prefix - that is the only overhead. However, the prefix should not be necessary since ds is the default segment register for such an operation. Nasm, for example, is perfectly happy to generate the instruction without the prefix, but it seems that the Intel compiler, and MSVC++, both need the prefix.

If you are generating this machine code in your application, you should be safe to not generate the prefix byte in this case.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.