Is there a macro for MASM/MASM32 that lets you pass plain strings like this to a function



invoke funcname, "This is a string"




Just like in C?

Also is there anything like a printf or something like that for MASM?
Posted on 2004-02-13 16:43:31 by x86asm
look for CSTR and stay away from whatever "jmp skip_data" style junk hutch as made ^_^
Posted on 2004-02-13 17:01:22 by f0dder
CTEXT, even. I dunno who made this macro originally, I snatched it and forgot to write down the author name - wouldn't be surprised if it's bitRAKE though ^_^



CTEXT MACRO y:VARARG
LOCAL sym

CONST segment
IFIDNI <y>,<>
sym db 0
ELSE
sym db y,0
ENDIF
CONST ends

EXITM <OFFSET sym>
ENDM
Posted on 2004-02-13 17:02:26 by f0dder
And my trace macro, used as follows:
trace "eax is %d and this string is %s",eax,ebx


trace macro What1:REQ,What2:VARARG
ifndef trace_buffer1
.data?
trace_buffer1 db 400 dup (?)
.code
endif
invoke wsprintf,addr trace_buffer1,CTEXT(What1),What2
invoke DebugPrint,addr trace_buffer1
endm
Posted on 2004-02-13 18:46:03 by Ultrano
that's pretty neat, Ultrano - and for people who don't know, check out http://www.sysinternals.com/ntw2k/freeware/debugview.shtml
Posted on 2004-02-13 19:11:44 by f0dder
Hello, as any shoud known there is a macro in the macro directory of the masm32, and could be used like this:

invoke MessageBox,NULL,SADD("Cant open file"),SADD("Error"),MB_OK
invoke MessageBox,NULL,SADD("Sorry option not allowed"),SADD("Error"),MB_OK
...
..
and so on.


I been check the macro reference for masm and i make my own macros, with my macros i can do this:

invoke MessageBox,NULL,_T("Cant open file"),_T("Error"),MB_OK
invoke MessageBox,NULL,_T("Sorry option not allowed"),_T("Error"),MB_OK
...
..
and so on.


????#@ I don't understand, what is the new feature?
Easy my friend, i will explain, with the sadd macro in the two lines of the messagebox invokes, whe declare 4 strings.
but with the _T macro whe just declare 3 strings, and reuse 1.

WARNING:
I found a bug, and i dont know how to solve, the errors come when i put on a string the character '\', like this:
mov eax,_T("c:\blabla")
mov ecx,_T("file:///c:\")

the error came in the second instruction
if any macro expert found the bug let me know

so here is the macros:
Posted on 2004-02-13 23:55:47 by mauricioprado
You could just switch to GoAsm, it allows that syntax and doesn't create a new section if you don't have a .data section it puts it in .const, if .data already exists it puts it in .data. Actually it's about the only high level construct that it does have but it makes up for it with USEDATA and USES FLAGS etc... as well as internal unicode support.

Then again if you're looking for C like constructs GoAsm isn't likely to be for you, no high level constructs like .IF/.WHILE and jumps and data size are explicit. Nice when you get used to it but it certainly takes a while to loose the high level crutches.
Posted on 2004-02-14 00:29:32 by donkey
Try my string macros. Syntax and examples are inside.
Posted on 2004-02-14 06:13:01 by Four-F
x86asm,

In the latest service pack for MASM32 there is a macro that does exactly that.


fn MessageBox,hWnd,"Text Message","Title",MB_OK

You can in fact use it on any API call that uses an initialised string.


look for CSTR and stay away from whatever "jmp skip_data" style junk hutch as made ^_^

:tongue:

f0dder,

You will have to learn some assembler one day and give up using a C compiler as a crutch.

Regards,
http://www.asmcommunity.net/board/cryptmail.php?tauntspiders=in.your.face@nomail.for.you&id=2f46ed9f24413347f14439b64bdc03fd
Posted on 2004-02-14 07:51:13 by hutch--
Heh, using a C compiler as a crutch? I don't see what the CTEXT I posted has to do with using C compilers. And the "jmp skipdata" approach used in the SADD macro is just plain... SAD. Anyway, mauricioprado's (and other similar macros that's been presented before, probably by bitRAKE) beats them both.
Posted on 2004-02-14 10:27:39 by f0dder
f0dder,

You will have to learn some assembler one day and give up using a C compiler as a crutch.


Actually f0dder is the one making sense here, from an assembly point-of-view. Or at least, from a CPU-architecture point-of-view. If you read some recent Intel optimization manuals (or probably AMD or others), you will find that the code and data cache are mutually exclusive. This means that embedded data in a code-page is explicitly not cached, and therefore it will cause a cache-miss.
So, yes, assembly programmers should know that putting data in the code and jumping over it is indeed... 'junk'.
Posted on 2004-02-14 10:45:27 by Henk-Jan
mauricioprado,
It appears that your MACROs are getting confused with the line continuation character \ . Your method appears to concatenate several strings into one big string and use the INSTR function to see if the string was used before. There might be a limit to how long the string can be, in which case the method fails. In any case, it makes your MACROs quite complicated. See if you don't like how I do it better. It is much simpler and does not have your backslash problem. Ratch




;-------------------------------------------------------------------------------
BYTER MACRO P1:VARARG ;inline code for BYTE string and implicit label
LOCAL L1
.DATA
L1 BYTE P1
.CODE
EXITM <OFFSET L1>
ENDM
;-------------------------------------------------------------------------------
LBYTER MACRO P1,P2:VARARG ;inline code for BYTE string and explicit label
.DATA
P1 BYTE P2
.CODE
EXITM <OFFSET P1>
ENDM
;-------------------------------------------------------------------------------
00000008 1 .DATA
00000008 41 6C 6C 20 74 1 ??0019 BYTE 'All things happen\\to those who wait',0
68 69 6E 67 73
20 68 61 70 70
65 6E 5C 5C 74
6F 20 74 68 6F
73 65 20 77 68
6F 20 77 61 69
74 00
00000037 1 .CODE
0000002D 1 .DATA
0000002D 4E 55 4D 42 45 1 TAG1 BYTE 'NUMBER ONE',0
52 20 4F 4E 45
00
00000037 1 .CODE
INVOKE MessageBox,0,BYTER('All things happen\\to those who wait',0),LBYTER(TAG1,'NUMBER ONE',0),MB_OK
00000037 6A 00 * push +000000000h
00000039 68 0000002D R * push dword ptr OFFSET FLAT:TAG1
0000003E 68 00000008 R * push dword ptr OFFSET FLAT:??0019
00000043 6A 00 * push +000000000h
00000045 E8 00000000 E * call MessageBoxA
00000038 1 .DATA
00000038 54 72 79 20 69 1 ??001A BYTE 'Try it this // way',0
74 20 74 68 69
73 20 2F 2F 20
77 61 79 00
0000004A 1 .CODE
INVOKE MessageBox,0,BYTER('Try it this // way',0),OFFSET TAG1,MB_OK
0000004A 6A 00 * push +000000000h
0000004C 68 0000002D R * push dword ptr OFFSET FLAT:TAG1
00000051 68 00000038 R * push dword ptr OFFSET FLAT:??001A
00000056 6A 00 * push +000000000h
00000058 E8 00000000 E * call MessageBoxA
END MAIN
Posted on 2004-02-14 16:41:33 by Ratch
Guess who does not do his research before opening his mouth ? The SADD macro writes initialised data to the initialised data section, the macro name is in fact a reuse of an older technical term which meant STRING ADDRESS.

Henk,

Data in the code section is built into the processor design with immediate operands like


mov eax, 1

Fortunately the designers of the PE specification that Microsoft uses a subset of were not cloned by the ANSI C standard and wrote a file format that used FLAT memory model which can contain both code and data set out by the requirements of the program in mch the same way as old dos COM files.

Many people confuse data written into the code section as being read into the code cache but as you would be aware, data cannot normally be executed and the code simply jumps over it. When the address of the embedded data is referenced as data, it resides in the data cache.

It is a left over with many C programmers who don't seem to be familiar with PE specifications when they insist that code and data be seperated as it had to be in the old dos segmented memory models. There are in fact a lot of things from the dos day that can well be forgotten and assumptions based on segmented architecture are among them.

For f0dder, code is code and data is data and the processor is smart enough to know which is which and what gets loaded into which cache. When you jump over data, it does NOT end up in the code cache.

Now in areas where cache usage is actually critical in terms of performance, Intel recommend that data be local which means STACK based, not data section or code section static data as it is closer in terms of cache load. The other requirement when performance matters is data alignment to ensure the processor does not have to fetch twice across a 4 byte boundary.

Perhaps f0dder should take his foot out of his mouth before making smartarse comments when he is out of date and short of the facts.

Regards,
http://www.asmcommunity.net/board/cryptmail.php?tauntspiders=in.your.face@nomail.for.you&id=2f46ed9f24413347f14439b64bdc03fd
Posted on 2004-02-14 17:31:59 by hutch--



Actually f0dder is the one making sense here, from an assembly point-of-view. Or at least, from a CPU-architecture point-of-view. If you read some recent Intel optimization manuals (or probably AMD or others), you will find that the code and data cache are mutually exclusive. This means that embedded data in a code-page is explicitly not cached, and therefore it will cause a cache-miss.
So, yes, assembly programmers should know that putting data in the code and jumping over it is indeed... 'junk'.


I tried to put code in the data segment as a temp storage in my Z80 CPU emu and I was unable to access it, it causes a fault.
Posted on 2004-02-14 20:55:17 by x86asm
Many people confuse data written into the code section as being read into the code cache but as you would be aware, data cannot normally be executed and the code simply jumps over it. When the address of the embedded data is referenced as data, it resides in the data cache.


Firstly, immediate operands are a different case, and you cannot use strings as immediate operands.
Secondly, you are wrong here, as I said before. Read the manuals and see that data and code cache are mutually exclusive. So if you are accessing data from a page that is currently in code-cache (such as the code you are currently executing), it is NOT in the data-cache, because the CPU-designers assumed that code does not contain data, and vice versa, and can therefore make the caching more efficient, by eliminating redundant caching of pages.
So yes you DO get a cache miss the first time. If you don't believe me, read the manuals.
Other than that, it's ugly too, and it can be error-prone, since code pages don't have the same rights as data pages.

By the way, the P4 doesn't actually cache code at all anymore, in its L1 cache. It grabs on an L2-level, and predecodes everything to trace-cache.
So your data is at most in L2-cache, it is not in L1-cache at all, not as data, and not as code.

code is code and data is data and the processor is smart enough to know which is which and what gets loaded into which cache. When you jump over data, it does NOT end up in the code cache.


Whether it ends up in the code cache or not, is not that relevant. Ofcourse as you know, caches don't work on a byte-level granularity, but on a cacheline level, which is usually 32 or 64 bytes. So as you will understand, SOME of the data will be in code-cache (assuming no trace-cache here), unless it happens to be just outside any cacheline boundaries.
But the relevant part is: it will not end up in data-cache either, not unless you access it for the first time.
So you always get a cache miss, while normally you would group data together, and (some of) it will be prefetched by earlier operations on nearby data.
Also, you won't have the problem of polluting part of your data cachelines with code, and vice versa.
So in short, you never want to do this. And defending it is just silly.
Posted on 2004-02-15 06:35:48 by Henk-Jan
Henk,


Firstly, immediate operands are a different case, and you cannot use strings as immediate operands.



mov eax, "sihT"
mov ebx, " si "
mov ecx, " ton"
mov edx, "eurt"

In a portable executable file there is no mechanical seperation between data and code and the sections are defined by the read / write / execute attributes only. You can copy binary data into GlobalAlloc() memory and run it from there.

A common method of avoiding a seperate initialised data section in very small programs is to write it as follows,


.code
align 4
MyVar dd 125
AnotherVar dd 500
mybytes db "This is a test",0
start:
; your user code here.

This is clearly data in the code section yet it is NEVER read into the code cache. If you need to to both read and write the data in the code section, you change the file attributes so the code section is writable.

First pass on ANY information is slow, data or code so its no great loss that the first pass at data embedded in the code section is slow. Conditional jumps have problems first pass even if the jump prediction direction is correct, data reads from the data section are slow first pass as they are not yet in the data cache. When you are running large sections of code that is too big to fit into the code section you have fetch delays and this pattern works across all data and code run by modern hardware.

It is a side effect of pipeline length and cached data and code access. We all know the theory of data and code seperation but it also needs to be put into the context of what the code is doing.

Most code is not critical and the code that is has to be set up in a particular way in any case. Data alignment, procedure and label alignment and of couse instruction sequencing.

Put against the clock, most of these leftover theories from segmented architecture don't perform so there is little point to insisting on them in an assembler environment where you don't have to suffer restriction of this type.

Regards,

http://www.asmcommunity.net/board/cryptmail.php?tauntspiders=in.your.face@nomail.for.you&id=2f46ed9f24413347f14439b64bdc03fd
Posted on 2004-02-15 19:00:50 by hutch--
Putting 4-byte ASCII values in registers is not the same as the null-terminated by-reference strings that most functions require.

This is clearly data in the code section yet it is NEVER read into the code cache. If you need to to both read and write the data in the code section, you change the file attributes so the code section is writable.


That's not the same as the case under discussion, which is more like:


.code
lea eax, mystring
jmp endofstring
mystring db "hello",0
invoke printf, eax


Argue about other code all you want, that's not what I was talking about (I keep wondering why you throw in that useless segmented crap and C-compiler crap anyway, it is completely unrelated to the cache-issue).
Besides, since when do asm programmers accept anything less than optimal cache-usage and top performance?

Stop trying to cover up with silly evasions. The above example is BAD, do NOT do it, EVER. Why not? I mentioned that earlier.
Posted on 2004-02-15 19:29:44 by Henk-Jan
I occasionally inline strings to keep them with the procedures they belong to, I reuse the procs and it is just easier that way, each one comes with it's own data. I just put inline string constants after the return and never use them outside of a procedure. The cache is blown anyway and it does not adversely affect anything. After all if you're trying to flub up the decompiler that is a pretty easy trick to get around and a hex editor will let you quickly see what's up so there is absolutely no code security advantage.

.

.
.
xor eax,eax
RET

ENV_upd_url: DB "upd_url",0
ENV_upd_script: DB "upd_script",0
ENV_upd_root: DB "upd_root",0
ENV_upd_title: DB "upd_title",0
ENV_upd_textovl: DB "upd_textovl",0
ENV_upd_textbtn: DB "upd_textbtn",0
ENV_upd_bitmap: DB "upd_bitmap",0
ENV_upd_process: DB "upd_process",0
ENV_upd_rsparams: DB "upd_rsparams",0

ENDF


Ofcourse the advantage is that if I do not have a .DATA section in the application that I am using it in then none is created. Besides that I can think of no real advantage.

For example in the following code, putting icc in the data section would add 512 bytes to the executable, there are many even large apps that I write that have very little initialized data and it is a waste to put in a few 10s of bytes when there is no reason:

#Define WM_INITDIALOG 110h

#Define WM_COMMAND 111h
#Define WM_CLOSE 10h

.DATA
hInstance DD ?
; icc DQ 3FFF00000008h

.CODE
icc: DQ 3FFF00000008h
Start:
invoke InitCommonControlsEx,OFFSET icc
invoke GetModuleHandleA, 0
mov [hInstance],eax
invoke DialogBoxParamA,eax,1000,0,ADDR DlgProc,0
invoke ExitProcess,0

DlgProc FRAME hwnd,uMsg,wParam,lParam

WMINITDIALOG:
cmp D[uMsg],WM_INITDIALOG
jne >WMCOMMAND
jmp >.EXIT

WMCOMMAND:
cmp D[uMsg],WM_COMMAND
jne >WMCLOSE
jmp >.EXIT

WMCLOSE:
cmp D[uMsg],WM_CLOSE
jne >DEFPROC
INVOKE EndDialog,[hwnd],0

DEFPROC:
mov eax,0
ret

.EXIT

mov eax, 1
ret
ENDF
Posted on 2004-02-15 20:11:41 by donkey
You can also merge sections at link-time.
Posted on 2004-02-16 01:48:47 by Henk-Jan
Henk,

Don't get so excited, there are very few hard and fast rules in programming and especially in assembler coding and when you make them, someone breaks them.

Argue about other code all you want, that's not what I was talking about (I keep wondering why you throw in that useless segmented crap and C-compiler crap anyway, it is completely unrelated to the cache-issue).

This is where the idea of seperated code and data came from originally, dos model segmented architecture where you could not put data in the code segment.

DOS com files were never restricted to this dos EXE model and with the advent of 32 bit PE files, they are not either.

Besides, since when do asm programmers accept anything less than optimal cache-usage and top performance?

1. When it does not matter. Why build the fastest MessageBox on the planet when the user will not see the difference.

2. When it does not perform any better. Casual string reads are by no means a performance issue so you can read them from data, code, resource section, file or more or less where-ever you like and it just does not go any faster.

Stop trying to cover up with silly evasions. The above example is BAD, do NOT do it, EVER. Why not? I mentioned that earlier.

I trust the clock far more than I trust opinion and that is what I base what I say on. Hunger is bad, war is worse and code that breaks the rules is truly wicked but none of it is worth losing sleep over.

Regards,
http://www.asmcommunity.net/board/cryptmail.php?tauntspiders=in.your.face@nomail.for.you&id=2f46ed9f24413347f14439b64bdc03fd
Posted on 2004-02-16 03:37:20 by hutch--