digitalmars.D.bugs - Problem using small inout parameters with inline asm
- Sean Kelly (17/17) Dec 20 2005 I can workaround this by using a temporary pointer variable, but it
- Tiago Gasiba (69/90) Dec 21 2005 How about doing this:
- Sean Kelly (6/69) Dec 21 2005 I disagree :-) inout parameters are pointers and so will always be 32
- Tiago Gasiba (56/132) Dec 21 2005 Change the program to the following:
- Tiago Gasiba (14/51) Dec 21 2005 Oh! I have just realized that I have messed up a bit... shame on me.
- Chris Lajoie (7/9) Dec 26 2005 I don't know assembly, but I am really trying to understand this thread....
- Tiago Gasiba (14/26) Dec 27 2005 What Sean meant was that the argument that gets passed with an inout par...
I can workaround this by using a temporary pointer variable, but it doesn't seem like this should be necessary. C:\code\d>type test.d void fn( inout byte b ) { asm { mov EAX, b; } } int main() { byte b; fn( b ); } C:\code\d>dmd test test.d(5): bad type/size of operands 'mov'
Dec 20 2005
Sean Kelly schrieb:I can workaround this by using a temporary pointer variable, but it doesn't seem like this should be necessary. C:\code\d>type test.d void fn( inout byte b ) { asm { mov EAX, b; } } int main() { byte b; fn( b ); } C:\code\d>dmd test test.d(5): bad type/size of operands 'mov'How about doing this: mov EAX,0; mov AL, b; The input parameter is a single byte and should not be loaded directly into EAX. Note that there is no sign extension! The following is a dissasembled version of the program. <snip> Disassembly of section .gnu.linkonce.t_D5test12fnFKgZv: 0804bbe4 <_D5test12fnFKgZv>: 804bbe4: 55 push ebp 804bbe5: 8b ec mov ebp,esp 804bbe7: 83 ec 04 sub esp,0x4 804bbea: 89 45 fc mov DWORD PTR [ebp-4],eax 804bbed: b8 00 00 00 00 mov eax,0x0 804bbf2: 8a 45 fc mov al,BYTE PTR [ebp-4] 804bbf5: c9 leave 804bbf6: c3 ret 804bbf7: 90 nop Disassembly of section .gnu.linkonce.t_Dmain: 0804bbf8 <_Dmain>: 804bbf8: 55 push ebp 804bbf9: 8b ec mov ebp,esp 804bbfb: 83 ec 04 sub esp,0x4 804bbfe: c6 45 fc 00 mov BYTE PTR [ebp-4],0x0 804bc02: 8d 45 fc lea eax,[ebp-4] 804bc05: e8 da ff ff ff call 804bbe4 <_D5test12fnFKgZv> 804bc0a: b8 0d 00 00 00 mov eax,0xd 804bc0f: e8 04 00 00 00 call 804bc18 <_assert_5test1> 804bc14: c9 leave 804bc15: c3 ret 804bc16: 90 nop 804bc17: 90 nop <snip> At address 804bbfe only one byte is pushed into the stack - the other values are "trash". If you really want to do it, try this: mov EAX, int ptr b; Compiles well: <snip> 0804bbe4 <_D5test12fnFKgZv>: 804bbe4: 55 push ebp 804bbe5: 8b ec mov ebp,esp 804bbe7: 83 ec 04 sub esp,0x4 804bbea: 89 45 fc mov DWORD PTR [ebp-4],eax 804bbed: 8b 45 fc mov eax,DWORD PTR [ebp-4] 804bbf0: c9 leave 804bbf1: c3 ret 804bbf2: 90 nop 804bbf3: 90 nop Disassembly of section .gnu.linkonce.t_Dmain: 0804bbf4 <_Dmain>: 804bbf4: 55 push ebp 804bbf5: 8b ec mov ebp,esp 804bbf7: 83 ec 04 sub esp,0x4 804bbfa: c6 45 fc 00 mov BYTE PTR [ebp-4],0x0 804bbfe: 8d 45 fc lea eax,[ebp-4] 804bc01: e8 de ff ff ff call 804bbe4 <_D5test12fnFKgZv> 804bc06: b8 0d 00 00 00 mov eax,0xd 804bc0b: e8 04 00 00 00 call 804bc14 <_assert_5test1> 804bc10: c9 leave 804bc11: c3 ret 804bc12: 90 nop 804bc13: 90 nop <snip> Best, Tiago -- Tiago Gasiba (M.Sc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.
Dec 21 2005
Tiago Gasiba wrote:Sean Kelly schrieb:I disagree :-) inout parameters are pointers and so will always be 32 bits on x86.I can workaround this by using a temporary pointer variable, but it doesn't seem like this should be necessary. C:\code\d>type test.d void fn( inout byte b ) { asm { mov EAX, b; } } int main() { byte b; fn( b ); } C:\code\d>dmd test test.d(5): bad type/size of operands 'mov'How about doing this: mov EAX,0; mov AL, b; The input parameter is a single byte and should not be loaded directly into EAX.Note that there is no sign extension! The following is a dissasembled version of the program. <snip> Disassembly of section .gnu.linkonce.t_D5test12fnFKgZv: 0804bbe4 <_D5test12fnFKgZv>: 804bbe4: 55 push ebp 804bbe5: 8b ec mov ebp,esp 804bbe7: 83 ec 04 sub esp,0x4 804bbea: 89 45 fc mov DWORD PTR [ebp-4],eax 804bbed: b8 00 00 00 00 mov eax,0x0 804bbf2: 8a 45 fc mov al,BYTE PTR [ebp-4] 804bbf5: c9 leave 804bbf6: c3 ret 804bbf7: 90 nop Disassembly of section .gnu.linkonce.t_Dmain: 0804bbf8 <_Dmain>: 804bbf8: 55 push ebp 804bbf9: 8b ec mov ebp,esp 804bbfb: 83 ec 04 sub esp,0x4 804bbfe: c6 45 fc 00 mov BYTE PTR [ebp-4],0x0 804bc02: 8d 45 fc lea eax,[ebp-4] 804bc05: e8 da ff ff ff call 804bbe4 <_D5test12fnFKgZv> 804bc0a: b8 0d 00 00 00 mov eax,0xd 804bc0f: e8 04 00 00 00 call 804bc18 <_assert_5test1> 804bc14: c9 leave 804bc15: c3 ret 804bc16: 90 nop 804bc17: 90 nop <snip> At address 804bbfe only one byte is pushed into the stack - the other values are "trash".Really? I thought "byte ptr" meant that 'b' is a pointer to a byte. Shouldn't it be 32 bits then? Sean
Dec 21 2005
Sean Kelly schrieb:Tiago Gasiba wrote:Change the program to the following: <snip> void fn( inout byte b ){ static byte x; x = b; b = 0x12; } int main() { byte b; fn( b ); } <snip> compile and examine the assembly generated code. The function "fn" looks like this: <snip> 0804bbe4 <_D5test12fnFKgZv>: 804bbe4: 55 push ebp 804bbe5: 8b ec mov ebp,esp 804bbe7: 8a 08 mov cl,BYTE PTR [eax] 804bbe9: 88 0d 00 d8 05 08 mov ds:0x805d800,cl 804bbef: c6 00 12 mov BYTE PTR [eax],0x12 804bbf2: 5d pop ebp 804bbf3: c3 ret <snip> EAX contains the memory pointer and, as you can clearly see, CL is loaded with "b", i.e. a single byte. The output to "b" is also a single byte, namely 0x12. Therefore, I think that accessing it with "int ptr" is a bad idea. Proof of concept: <snip> void fn( inout byte x ){ int y; asm { mov EAX, int ptr[x]; inc byte ptr [EAX]; mov ECX, int ptr [EAX]; mov y, ECX; } printf("y=%x\n",y); } int main() { byte x = 0x12; fn( x ); printf("X=%x \n",x); return 0; } <snip> Output: y=400dad13 X=13 Clearly variable "y" is not being properly used! However, "x" is correctly incremented and 0x13 is displayed in the output. Best, Tiago -- Tiago Gasiba (M.Sc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.Sean Kelly schrieb:I disagree :-) inout parameters are pointers and so will always be 32 bits on x86.I can workaround this by using a temporary pointer variable, but it doesn't seem like this should be necessary. C:\code\d>type test.d void fn( inout byte b ) { asm { mov EAX, b; } } int main() { byte b; fn( b ); } C:\code\d>dmd test test.d(5): bad type/size of operands 'mov'How about doing this: mov EAX,0; mov AL, b; The input parameter is a single byte and should not be loaded directly into EAX.Note that there is no sign extension! The following is a dissasembled version of the program. <snip> Disassembly of section .gnu.linkonce.t_D5test12fnFKgZv: 0804bbe4 <_D5test12fnFKgZv>: 804bbe4: 55 push ebp 804bbe5: 8b ec mov ebp,esp 804bbe7: 83 ec 04 sub esp,0x4 804bbea: 89 45 fc mov DWORD PTR [ebp-4],eax 804bbed: b8 00 00 00 00 mov eax,0x0 804bbf2: 8a 45 fc mov al,BYTE PTR [ebp-4] 804bbf5: c9 leave 804bbf6: c3 ret 804bbf7: 90 nop Disassembly of section .gnu.linkonce.t_Dmain: 0804bbf8 <_Dmain>: 804bbf8: 55 push ebp 804bbf9: 8b ec mov ebp,esp 804bbfb: 83 ec 04 sub esp,0x4 804bbfe: c6 45 fc 00 mov BYTE PTR [ebp-4],0x0 804bc02: 8d 45 fc lea eax,[ebp-4] 804bc05: e8 da ff ff ff call 804bbe4 <_D5test12fnFKgZv> 804bc0a: b8 0d 00 00 00 mov eax,0xd 804bc0f: e8 04 00 00 00 call 804bc18 <_assert_5test1> 804bc14: c9 leave 804bc15: c3 ret 804bc16: 90 nop 804bc17: 90 nop <snip> At address 804bbfe only one byte is pushed into the stack - the other values are "trash".Really? I thought "byte ptr" meant that 'b' is a pointer to a byte. Shouldn't it be 32 bits then? Sean
Dec 21 2005
Sean Kelly schrieb:Tiago Gasiba wrote:Oh! I have just realized that I have messed up a bit... shame on me. That's what happens when I reply too fast. You're totally right - pointers are 32bit.Sean Kelly schrieb:I disagree :-) inout parameters are pointers and so will always be 32 bits on x86.I can workaround this by using a temporary pointer variable, but it doesn't seem like this should be necessary. C:\code\d>type test.d void fn( inout byte b ) { asm { mov EAX, b; } } int main() { byte b; fn( b ); } C:\code\d>dmd test test.d(5): bad type/size of operands 'mov'How about doing this: mov EAX,0; mov AL, b; The input parameter is a single byte and should not be loaded directly into EAX.Really? I thought "byte ptr" meant that 'b' is a pointer to a byte. Shouldn't it be 32 bits then?True! Although I have messed it up a little, I did manage to give the correct solution on my last message: mov EAX, int ptr[x]; // 32 bit pointer inc byte ptr [EAX]; // address a single byte Best, Tiago -- Tiago Gasiba (M.Sc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.
Dec 21 2005
I disagree :-) inout parameters are pointers and so will always be 32 bits on x86.I don't know assembly, but I am really trying to understand this thread. inout parameters are dereferenced implicitly.. so in the asm it is probably being dereferenced the same way it would in normal code (so it wouldn't be a 32 bit ptr, but a byte instead). Are you saying that is incorrect, and it should not be getting dereferenced if it is in asm { ... } context? Chris
Dec 26 2005
Chris Lajoie schrieb:What Sean meant was that the argument that gets passed with an inout parameter is a pointer, like in the following declaration: void fn( byte *ptn ){} The pointer itself (the container for the memory address) is 32bit long, while the pointer's memory address points to a byte (byte *). Therefore, the true argument that is passed is a 32bit value, which is why it must be loaded like: mov EAX, int ptr[x]; // 32 bit pointer inc byte ptr [EAX]; // address a single byte The first intruction takes a 32bit value into EAX (the memory address) and the second increments the byte that is pointed by it. Tiago -- Tiago Gasiba (M.Sc.) - http://www.gasiba.de Everything should be made as simple as possible, but not simpler.I disagree :-) inout parameters are pointers and so will always be 32 bits on x86.I don't know assembly, but I am really trying to understand this thread. inout parameters are dereferenced implicitly.. so in the asm it is probably being dereferenced the same way it would in normal code (so it wouldn't be a 32 bit ptr, but a byte instead). Are you saying that is incorrect, and it should not be getting dereferenced if it is in asm { ... } context? Chris
Dec 27 2005