After I create a Proc or Function in MASM, and I want to call it
from a C program, how do I manage that? Do I link the asm.obj
with the c.obj? Do I create a static funct.lib to include and reuse?
Is it better to have a DLL? When is it better? Inline Assembly?
If the external MASM Proc/func uses 2 DD addresses of 2 strings
to manipulate, a source and a target string I mean, how should I
declare the MASM proto function? How do I Assemble it?
Do I need a some.h file to include in the C program? Or I simple
have to declare the external function?
To be practical:
I have this small chunk of assembly that I use to reverse a 4 bytes
string
mov edx, p_str ; Pointer to first 4 bytes string - the one to reverse
mov ebx, p_str1 ; Pointer to second 4 bytes string - the one that holds the result
mov eax, [edx]
bswap eax
mov [ebx], eax
and a C program like this:
#include <stdio.h>
int main(void)
{
char str1[5] = "ABCD";
char str2[5] = "XXXX";
printf("original string = %s\n",str1);
reverse(&str1,&str2);
printf("reversed string = %s\n",str2);
getchar();
return 0;
}
I didn't check the C syntax, so it is probably uncorrect, in case
let me know what please.
I think it can be done at least in 4 different ways:
1 - inline assembly [do Pelle's C support it? I hope so]
Could anyone show me how to do it?
2 - adding the proper MASM lines to the chunk I propose and
compile without linking [how do I do both adding and compiling?]
into an obj file to LINK to the main C program.
3 - using a new lib created with the obj file and LIB command
to include during the linking process
4 - using a DLL
Please can you show me how do I perform these tasks using the
code I provided?
Thanks
Frank
P.S. well! it looks like Pelle's C has got an Inline Assembler:
#include <stdio.h>
int main(void)
{
char str1[5] = "ABCD";
char str2[5] = "XXXX";
char *p_str1, *p_str2;
p_str1 = str1;
p_str2 = str2;
printf("original string = %s\n",str1);
__asm
{
mov edx, p_str1 ; Pointer to first 4 bytes string - the one to reverse
mov ebx, p_str2 ; Pointer to second 4 bytes string - the one that holds the result
mov eax, [edx]
bswap eax
mov [ebx], eax
}
printf("reversed string = %s\n",str2);
getchar();
return 0;
}
:P
The only annoying thing is the exe of 30 Kb.
In MASM if should be less than 3 Kb I guess.
What about the other possibilities?
Frank
Generally I would do it statically, unless the code was really big. The advantage of a .LIB or a .OBJ is that the linker will only pull the functions it needs, so ideally you'd break down the functions one to an OBJ. Or use the CL command line option -Gy to separate functions for the linker.
If I'm prototyping something, or it doesn't need an ASM file, I'd use inline'd code.
rev_c.c
// ml -c -coff -Fl rev_a.asm
// cl -c -Ox rev_c.c
// link rev_a.obj rev_b.obj
// ml -c -coff -Fl rev_a.asm
// cl -Ox rev_c.c rev_a.obj
// cl -c -Ox rev_c.c
// ml -coff -Fl rev_a.asm rev_c.obj
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
extern void __cdecl TestRev1(char *, char *);
extern void __stdcall TestRev2(char *, char *);
int main(int argc, char **argv)
{
char str1[5] = "ABCD";
char str2[5] = "XXXX";
TestRev1(str1, str2);
TestRev2(str1, str2);
return(1);
}
rev_a.asm
.486
.MODEL FLAT
.CODE
TestRev1 PROC C USES ebx, p_str:PTR BYTE, p_str1:PTR BYTE
mov edx, p_str ; Pointer to first 4 bytes string - the one to reverse
mov ebx, p_str1 ; Pointer to second 4 bytes string - the one that holds the result
mov eax, [edx]
bswap eax
mov [ebx], eax
ret
TestRev1 ENDP
TestRev2 PROC STDCALL USES ebx, p_str:PTR BYTE, p_str1:PTR BYTE
mov edx, p_str ; Pointer to first 4 bytes string - the one to reverse
mov ebx, p_str1 ; Pointer to second 4 bytes string - the one that holds the result
mov eax, [edx]
bswap eax
mov [ebx], eax
ret
TestRev2 ENDP
END
To create a .LIB, use LIB to make the library and pull in the .OBJs you want. The use FOO.LIB in the command line to the C compiler, MASM, or LINK.
lib /OUT:foo.lib rev_a.obj
cl -Ox rev_c.c foo.lib
To create a DLL, you will need to add a DllMain function, and create a .DEF file containing the EXPORTS. Then using the linker the output will be a .DLL, .LIB and .EXP
revdll_a.asm
; ml -c -Fl -coff revdll_a.asm
; link revdll_a.obj /OUT:revdll.dll /DEF:revdll.def \masm32\lib\kernel32.lib
.486
.MODEL FLAT, STDCALL
GetModuleHandleA PROTO :DWORD
NULL equ 0
FALSE equ 0
TRUE equ -1
DLL_PROCESS_DETACH equ 0
DLL_PROCESS_ATTACH equ 1
DLL_THREAD_ATTACH equ 2
DLL_THREAD_DETACH equ 3
.DATA
hInstance dd ?
.CODE
align 4
TestRev1 PROC C USES ebx, p_str:PTR BYTE, p_str1:PTR BYTE
mov edx, p_str ; Pointer to first 4 bytes string - the one to reverse
mov ebx, p_str1 ; Pointer to second 4 bytes string - the one that holds the result
mov eax, [edx]
bswap eax
mov [ebx], eax
ret
TestRev1 ENDP
align 4
TestRev2 PROC STDCALL USES ebx, p_str:PTR BYTE, p_str1:PTR BYTE
mov edx, p_str ; Pointer to first 4 bytes string - the one to reverse
mov ebx, p_str1 ; Pointer to second 4 bytes string - the one that holds the result
mov eax, [edx]
bswap eax
mov [ebx], eax
ret
TestRev2 ENDP
align 4
_DllMainCRTStartup PROC public handle:dword, reason:dword, reserved:dword
.if reason == DLL_PROCESS_ATTACH
invoke GetModuleHandleA,NULL ; use the calling application's instance handle
mov hInstance, eax ; so that the icon from the caller can be used.
mov eax, TRUE ; put TRUE in EAX to continue loading the DLL
comment * ====================================
These can be used if there is thread specific
information that needs to be set up as the DLL
is called.
.elseif reason == DLL_THREAD_DETACH
.elseif reason == DLL_THREAD_ATTACH
================================== *
.elseif reason == DLL_PROCESS_DETACH
; ---------------------------------------
; perform any exit code you require here
; ---------------------------------------
.endif
ret
_DllMainCRTStartup ENDP
END _DllMainCRTStartup
revdll.def
LIBRARY revdll
EXPORTS
TestRev1
TestRev2
ml -c -Fl -coff revdll_a.asm
link revdll_a.obj /OUT:revdll.dll /DEF:revdll.def \masm32\lib\kernel32.lib
cl -Ox rev_c.c revdll.lib
That's great Clive, thanks a lot :bg
Very clear example. :U
Looking forward for your examples for LIB and DLL, that I cannot understand actually.
Frank
P.S. As I guessed, the MASM32 version [thanks Hutch] is 3 Kb more or less:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
str1 db 'ABCD',0
str2 db 'xxxx',0
.code
start:
mov edx, offset str1 ; Pointer to first 4 bytes string - the one to reverse
mov ebx, offset str2 ; Pointer to second 4 bytes string - the one that holds the result
mov eax, [edx]
bswap eax
mov [ebx], eax
print offset str1,13,10
print offset str2,13,10
inkey
exit
END start
If I don't use <stdio.h> and use the print MASM32 MACRO probably the
size of the EXE would be a lot smaller. What do you think?
Frank
Because you are writing something simple, you can specify to the linker to ignore the runtime library and also where the entrypoint of the program is.
/IGNORE:libcmt.lib /ENTRY:Main
As long as you only use C functions from dynamic runtime (msvcrt.dll) and other system dlls, you will have an executable which is free from bloat. Another option as well is to roll your own runtime by taking the functions you need from the VC source (it ships with every copy of VC++ afik) and compiling them into your own C library.
HR,
Ghandi
Quote from: Ghandi on May 27, 2010, 01:28:08 PM
As long as you only use C functions from dynamic runtime (msvcrt.dll) and other system dlls, you will have an executable which is free from bloat.
HR,
Ghandi
Do you mean "as long as I use only win32 API"?
Frank,
MSVCRT is a dynamic C runtime library, its just been around for so long that its now a "known" DLL. If you are really chasing the speed difference and that is if it exists, the static libraries may be faster but MSVCRT will certainly give you a much smaller file and probably lose little if any to the static libraries. If you were writing portable code it would matter but the window design is specifically API so paying the price of portability does not make sense here.
Quote from: hutch-- on May 27, 2010, 02:36:49 PM
Frank,
MSVCRT is a dynamic C runtime library, its just been around for so long that its now a "known" DLL. If you are really chasing the speed difference and that is if it exists, the static libraries may be faster but MSVCRT will certainly give you a much smaller file and probably lose little if any to the static libraries. If you were writing portable code it would matter but the window design is specifically API so paying the price of portability does not make sense here.
:U
there is a way to make exe file smaller inside PellesC
here is simlple example:
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "msvcrt.lib");
int main()s
{
__asm{
nop
nop
}
printf("hello\n");
return 0;
}
void __cdecl mainCRTStartup(void)
{
exit(main());
}
Quote from: Arash on May 27, 2010, 08:13:11 PM
there is a way to make exe file smaller inside PellesC
here is simlple example:
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "msvcrt.lib");
int main()s
{
__asm{
nop
nop
}
printf("hello\n");
return 0;
}
void __cdecl mainCRTStartup(void)
{
exit(main());
}
Well, probably
int main()s
should be
int main()
Anyway Pelle's C doesn't find the lib:
POLINK: fatal error: File not found: 'msvcrt.lib'.
::)
P.S. well I copied the msvcrt.lib from the vc2010 folder into Pelle's lib folder
and it works ok. Now the size is about 3 Kb. :U
You need to create msvcrt.lib It does not come with the Pelles C installation.
Quote from: Vortex on May 27, 2010, 09:08:31 PM
You need to create msvcrt.lib It does not come with the Pelles C installation.
Right! Read my previous post :U
I'd like to ask what these directives are:
#pragma comment(lib, "msvcrt.lib");
....
void __cdecl mainCRTStartup(void)
{
exit(main());
}
.....
and this chunk is just to say we can put some asm here?
{
__asm{
nop
nop
}
and last but not least, why the program freaks out if I put a
getchar();
after the printf ?
Thanks
Frank
frktons,
Pelle's C has it's own C Run-Time Library, but as you found out you can use Microsoft's library.
Quote from: Greg Lyon on May 27, 2010, 09:15:34 PM
frktons,
Pelle's C has it's own C Run-Time Library, but as you found out you can use Microsoft's library.
Yes Greg, I figured it out :U
Quote from: frktons on May 27, 2010, 09:11:53 PM
Quote from: Vortex on May 27, 2010, 09:08:31 PM
You need to create msvcrt.lib It does not come with the Pelles C installation.
Right! Read my previous post :U
I'd like to ask what these directives are:
#pragma comment(lib, "msvcrt.lib");
....
void __cdecl mainCRTStartup(void)
{
exit(main());
}
.....
and this chunk is just to say we can put some asm here?
{
__asm{
nop
nop
}
and last but not least, why the program freaks out if I put a
getchar();
after the printf ?
Thanks
Frank
What's happening in this prog? why is it 3 Kb instead of 30 Kb?
The includes for standard libraries are still there but... ::)
With a MASM32 install
#pragma comment(lib, "\\masm32\\lib\\msvcrt.lib")
Works with MSVC, executable 16KB, Microsoft doesn't like the trailing semicolon.
The #pragma stuffs a comment field in the object file, which the linker then takes as a parameter. ie LINK .. \masm32\lib\msvcrt.lib
The exit(main()); emulates the level above main() in the CRT which you don't normally see. I don't however care for it's command line parsing. The regular run time will actually parse the command line and environment.
QuoteWell, probably
Code:
int main()s
should be
Code:
int main()
yes you right, this is my mistake while i copy/paste code here :bg
QuoteAnyway Pelle's C doesn't find the lib:
well this source is from a little project that i write many years ago,
so i forgot what kinda file i copied to PellesC folder to making this code work :U
QuoteI'd like to ask what these directives are:
it's re-define mainCRTStartup that run befor main function
Quoteand this chunk is just to say we can put some asm here?
yes
Quoteand last but not least, why the program freaks out if I put a
Code:
getchar();
after the printf ?
it seem PellesC define some macro for getchar in stdio.h that make this problem
#define getchar() (__filetab[0]->ptr < __filetab[0]->getend ? *__filetab[0]->ptr++ : (fgetc)(__filetab[0]))
it can be solve with this code, this make PellesC to use getchar inside msvcrt.lib
#include <stdio.h>
#include <stdlib.h>
#undef getchar
Arash
Well, I used the suggested modifications to the previous code and:
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "\\masm32\\lib\\msvcrt.lib")
int main(void)
{
char str1[5] = "ABCD";
char str2[5] = "XXXX";
char *p_str1, *p_str2;
p_str1 = str1;
p_str2 = str2;
printf("original string = %s\n",str1);
__asm
{
mov edx, p_str1 ; Pointer to first 4 bytes string - the one to reverse
mov ebx, p_str2 ; Pointer to second 4 bytes string - the one that holds the result
mov eax, [edx]
bswap eax
mov [ebx], eax
}
printf("reversed string = %s\n",str2);
getchar();
return 0;
}
void __cdecl mainCRTStartup(void)
{
exit(main());
}
compiles 3 Kb size EXE. :U
The only thing I don't understand is:
Why the pgm stops with getchar() and I have to close the console windows
forcing it, and the pgm doesn't accept any char from the keyboard?
The same happens with #pragma comment(lib, "msvcrt.lib") that I copied
from vc 2010 folder. Something should be missing...
If I remove the getchar() function the pgm is ok. ::) and it compiles 2 Kb EXE.
see my previous post for solving getchar problem
Quote from: Arash on May 27, 2010, 10:04:52 PM
see my previous post for solving getchar problem
Thanks Arash! now the pgm is 2 Kb and works fine :U
This looks like a good start for making C/MASM programs small and fast :P
Maybe you can help me solve this problem too:
http://www.masm32.com/board/index.php?topic=14042.0
Thanks
Frank
Quote from: frktons
The same happens with #pragma comment(lib, "msvcrt.lib") that I copied
from vc 2010 folder. Something should be missing...
Libraries that link to DLL's contain no real code (an indirect jmp perhaps), so it doesn't really matter which library you use, the code loaded will be in \WINDOWS\SYSTEM32\MSVCRT.DLL (typically, or which every is better situated/pathed)
Quote from: clive on May 27, 2010, 11:05:48 PM
Quote from: frktons
The same happens with #pragma comment(lib, "msvcrt.lib") that I copied
from vc 2010 folder. Something should be missing...
Libraries that link to DLL's contain no real code (an indirect jmp perhaps), so it doesn't really matter which library you use, the code loaded will be in \WINDOWS\SYSTEM32\MSVCRT.DLL (typically, or which every is better situated/pathed)
The Pelle's C had this flaw about getchar()... well now it's ok.
Any idea why this project builds but won't run?
http://www.masm32.com/board/index.php?topic=14042.msg111608#msg111608
Let me give you an important tip, that I see plagued on the internet when it comes to visual studio 2003+ static lib linking. In those compilers microsoft introduced a new buffer overflow feature which is compiled in by default. As a result when you try and use the library in say masm you get errors talking about cookies and security and related. Now you can fix this either by linking to some random dll(forget the name) or by recompiling the library using the GS- flag in the linker settings. Theres also a checkbox in visual studio 2008 atleast that lets you uncheck buffer overflow protection.
Oddly enough if I use MSVC 2.0, the EXE is also 3KB, and it also crashes on the getchar(), looks to be a problem in how it references __iob, and the fact that nothing is getting initialized.
I tried MSVC 1.0 (32-bit), but things got somewhat bigger. Historically as Microsoft moved from 2.x, 4.x, 5.x, 6.x the executables got bigger, and bigger, I remember building a couple of control panel apps with the older versions because the size practically halved.
Something funny, I supply a couple of ancient SDK applications written in C under the licence that Microsoft have for redistributable code and by building them with the VCTOOLKIT and the libraries that were current when it was released, they are heaps smaller than the originals. I remember when MFC was first introduced that functionally identical apps from the SDK were over 3 times the size and were a lot slower than the C originals.
I have never had any beef with the VC compilers but the libraries were always a bit suspect so you tend to pick your way around them to get the results you want.
I'll try to stick with API and MASM, using a minimalistic approach to
standard C libraries.
By the way, if a pgm is 30 Kb bigger, it doesn't really matter, nowadays
we got Gbs of memory, don't we?
I am more concerned about speed, this could be a problem if I plan to
have millions of cycles to be done for some projects.
As far as C is just a tool to undestand how Windows APIs work, it is
worth to spend some time over it. :P
Frank
frktons,
The reason getchar() isn't working correctly is because you are replacing the CRT startup code with nothing.
void __cdecl mainCRTStartup(void)
{
exit(main());
}
Some of the CRT functions require the initialization that is done in the startup code to work properly. I would recommend that you just do it the normal way. Like you say, 30 Kb bigger, who cares?
Personally, i believe it's a matter of 'horses for courses'. I'm comfortable blending the two, whether it be an asm file in a VC project or a VC lib/obj in a MASM project, which i like to do sometimes. But that is me, there are others who would be more comfortable coding dlls to use with the other language or even keeping it to a single language. The answer is relative to each person who asks it, the only person who can truly answer it for each person is themselves.
HR,
Ghandi
You are absolutely right Ghandi.
Quote from: Greg Lyon on June 02, 2010, 09:23:33 PM
You are absolutely right Ghandi.
I agree as well, this is the approach I'm using at the moment. :P