NO

Author Topic: Inline assembly  (Read 9625 times)

Offline Vortex

  • Member
  • *
  • Posts: 797
    • http://www.vortex.masmcode.com
Inline assembly
« on: January 08, 2005, 12:01:36 PM »
Hi friends,

Here is an example of using inline assembly with Pelle's C. The original source code of szUpper comes with Hutch's masm32 package.
Code: [Select]

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

char *szUpper(char *text)
{
__asm{
mov eax, text
dec eax
@repeat:
add eax, 1
cmp BYTE PTR [eax], 0
je @end
cmp BYTE PTR [eax], "a"
jb @repeat
cmp BYTE PTR [eax], "z"
ja @repeat
sub BYTE PTR [eax], 32
jmp @repeat
@end:
}
return text;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
char msg[]="inline assembly programming";
MessageBox(0,szUpper(msg),"Hello!",MB_OK);
return 0;
}
Code it... That's all...

Offline Vortex

  • Member
  • *
  • Posts: 797
    • http://www.vortex.masmcode.com
Inline assembly
« Reply #1 on: January 08, 2005, 11:42:22 PM »
Here is another method, the C source code:

Code: [Select]

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

extern char *szUpper(char *text);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
char msg[]="inline assembly programming";
MessageBox(0,szUpper(msg),"Hello!",MB_OK);
return 0;
}


Pelle's C compiler, pocc.exe accepts asm source files based on a variant of NASM syntax:

Code: [Select]

[cpu 486]
[global _szUpper]
[section .text]
[function _szUpper]
_szUpper:
push ebp
mov ebp,esp
mov eax,[EBP+8]
dec eax
@restart:
add eax,1
cmp byte [eax],0
je near @end
cmp byte [eax],97
jb near @restart
cmp byte [eax],122
ja near @restart
sub byte [eax],32
jmp near @restart
@end:
mov eax,dword [ebp+8]
mov esp,ebp
pop ebp
ret
Code it... That's all...

Anonymous

  • Guest
Inline assembly
« Reply #2 on: January 10, 2005, 06:56:58 AM »
Hello Vortex,

Thanks for the asm code comparison.

I have a question for you: I believe you may have used the MASM32 Editor and possibly you're aware that in this tool  we have the  menu option Files-> Prompt. Do we have something similar in PelleĀ“s IDE ?


Gracias,

Ceci

Rainbow Sally

  • Guest
Inline assembly
« Reply #3 on: January 30, 2005, 04:08:01 AM »
Thanks for the working code, Vortex.  I tried something like this but it failed and I gave up ... probably had the __stdcall set and didn't include the @<bytes> or something, but now that I know it works... the universe is mine!  All mine!!  :-)  


Quote from: "Vortex"
Here is another method, the C source code:

Code: [Select]

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

extern char *szUpper(char *text);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
char msg[]="inline assembly programming";
MessageBox(0,szUpper(msg),"Hello!",MB_OK);
return 0;
}


Pelle's C compiler, pocc.exe accepts asm source files based on a variant of NASM syntax:

Code: [Select]

[cpu 486]
[global _szUpper]
[section .text]
[function _szUpper]
_szUpper:
push ebp
mov ebp,esp

<snip>



(What I'm gonna do with it, I have no idea.  ...The universe, I mean.  But the code?  That, I can use.)

.

Offline Vortex

  • Member
  • *
  • Posts: 797
    • http://www.vortex.masmcode.com
Inline assembly
« Reply #4 on: January 30, 2005, 11:49:53 AM »
Hi Sally,

Can you post your code?
Code it... That's all...

Rainbow Sally

  • Guest
Inline assembly
« Reply #5 on: January 30, 2005, 09:00:20 PM »
Quote from: "Vortex"
Hi Sally,

Can you post your code?


It's not really ready to post but here's the idea.  This program takes over the stack and dedicates esi and edi as IP and RP of a Foth VM.  It leaves C-world and enters Forth, does some functions and returns to C.  It doesn't use extermal asm files yet becuase we need a utility to do what these macros do.  

But since this is certainly on-topic for inline assembly, I'll go ahead and post this preliminary test.

Note the macros.  Not only can we put multiple mnemonics on a single line, we can also assign names to the registers.  That's the part I think will be the most interesting for most folks.  (The stack stuff is the most interesting to me.)

[edited soon after post to correct the ID field of the second struct.]

Code: [Select]

#include <windows.h>
#include <stdio.h>
#include <conio.h>

#define LOCODE __asm{
#define HICODE }
#define FORTH __declspec(naked) void __stdcall
#define CODE { __asm pop esi __asm {
#define ENDCODE } __asm jmp esi }
#define NL } __asm{

#define DOCOL CODE sub rp, 4 NL mov dword [rp], ip
#define DOSEMI mov ip, dword [rp] NL add rp, 4 ENDCODE

#define rp edi
#define ip esi
#define LIT push dword

void* paren0;
void* qp0;
void* tp0;

typedef struct _STARTUP_VALUES
{
int id;
#define STARTUP_ID startup_values+0
int stackblocks;
#define STARTUP_STACKBLOCKS startup_values+4
int nothing;
}STARTUP_VALUES;

STARTUP_VALUES startup_values =
{
0xDB1D0001,  // startup values id = 1
32,
0
};

typedef struct _USERVARS
{
int id;
int base;
char* code_origin;
void __stdcall (*Type)(char*, int);
void __stdcall (*Emit)(int ch);
void __stdcall (*Cr)(void);
void __stdcall (*dot)(int);
void __stdcall (*Key)(void);
void __stdcall (*Keyq)(void);


int nothing;
}USERVARS;

// PROTOS
FORTH F_CODEORIGIN(void);
void __stdcall con_Type(char* str, int len);
void __stdcall con_Emit(int ch);
void __stdcall con_Cr(void);
void __stdcall con_dot(int x);

void __stdcall con_Key(void);
void __stdcall con_Keyq(void);

USERVARS user =
{
0xDB1D0002, // uservars id = 2
10,
(char*)F_CODEORIGIN,
con_Type,
con_Emit,
con_Cr,
con_dot,
con_Key,
con_Keyq,
0
};

FORTH F_CODEORIGIN(void)
{
}

void __stdcall con_zType(char* str)
{
printf(str);
}

void __stdcall con_Emit(int ch)
{
printf("%c", ch&0xff);
}

void __stdcall con_Cr(void)
{
printf("\n");
}


FORTH con_Type(char* str, int len)
DOCOL
// if no count byte/word use zType
pop eax // str
cmp eax, 0xffff // max word
jle contype1
push eax
call con_zType
jmp short contype2:
contype1:
pop ecx
contypeloop:
test ecx, ecx
je contype2
push ecx
push eax
movzx eax, byte [eax]
call con_Emit
pop ecx
inc eax
dec ecx
jmp contypeloop
contype2:
DOSEMI

void __stdcall con_dot(int x)
{
switch(user.base)
{
case 10:
printf("%d ", x);
break;
case 16:
printf("%x ", x);
break;
default:
printf("bad base");
}
}

FORTH con_Key(void)
CODE
call getch
push eax
ENDCODE

FORTH con_Keyq(void)
CODE
call kbhit
push eax
ENDCODE


FORTH F_DECIMAL(void)
CODE
LIT 10
pop dword user.base
ENDCODE


FORTH F_HEX(void)
CODE
LIT 16
pop dword user.base
ENDCODE


FORTH F_AND(int b, int a)
CODE
pop eax
pop edx
and eax, edx
push eax
ENDCODE

FORTH F_DUP(int a)
CODE
push dword [esp]
ENDCODE

FORTH F_ZCOUNT(char* a)
{
LOCODE
pop esi
sub esp, 4
push ebp
mov ebp, esp
HICODE
for(char* p=a; ; p++)
{
if(*p == 0)
{
((long int*)&a)[-1]=p - a;
break;
}
}
LOCODE
mov esp, ebp
pop ebp
ret
HICODE
}



FORTH F_EXECUTE(void* p)
DOCOL
pop eax
call eax
DOSEMI


FORTH F_DOT(int n)
{
LOCODE
jmp [user.dot]
HICODE
}


FORTH F_KEY(int n)
{
LOCODE
jmp [user.Key]
HICODE
}


FORTH F_KEYQ(int n)
{
LOCODE
jmp [user.Keyq]
HICODE
}


FORTH F_CR(void)
{
LOCODE
jmp [user.Cr]
HICODE
}

FORTH F_TYPE(char* str, int len)
{
LOCODE
jmp [user.Type]
HICODE
}

FORTH F_EMIT(int ch)
{
LOCODE
jmp [user.Emit]
HICODE
}

FORTH F_TEST(void)
DOCOL
LIT 0xff
LIT 0x17
push F_AND
call F_EXECUTE
call F_DUP
call F_DOT
call F_HEX
call F_CR
call skip1
db "0x", 0
skip1:
call F_TYPE
call F_DOT
call F_CR
call skip2
db "Press any key ", 0
skip2:
call F_TYPE
call F_KEY
call F_CR
DOSEMI


__declspec(naked)
void init_stack(void)
{
__asm
{

pop eax // save return addr
mov ecx, dword [STARTUP_STACKBLOCKS] // stack blocks
@init_stack1:
sub esp, 1024
push eax
pop eax
dec ecx
jne @init_stack1
push eax // restore return addr

mov eax, dword [STARTUP_STACKBLOCKS]
mov ecx, 1024
mul ecx
shr eax, 1
add eax, esp
mov tp0, eax
add eax, 0x1000
mov qp0, eax
add eax, 0x1000
mov paren0, eax
add eax, 0x1000
mov edi, eax
ret
}
}

int __cdecl main(void)
{
char* espsav = NULL;
char* edisav = espsav;
char* espnew = edisav;
__asm
{
mov dword espsav, esp
mov dword edisav, edi
call init_stack
mov dword espnew, esp
}
F_TEST();
__asm
{
mov esp, dword espsav
mov edi, dword edisav
}
return 0;
}


Offline Vortex

  • Member
  • *
  • Posts: 797
    • http://www.vortex.masmcode.com
Inline assembly
« Reply #6 on: January 31, 2005, 09:06:17 PM »
Try to study the assembly output of your source code:
Code: [Select]
pocc /Tx86-asm source.c
Code it... That's all...