Hi all.
As I found some answers while googling around in MASM's forums, I thought it would be fair enough to start my presence here by giving instead of asking in my first post. I have been teaching myself Assembly for the last months by reading a great book and bumping my head against the computer xD xD Also, english is not my native language so I apologize for any mistake.
In recent days I took a very interesting reading about Structures in Assembly, from there, I got the tools I needed to start and create a static Array. I know, I know, most part of the time we'll be dealing with dinamic structures but there are times when you just need an array, plain and simple, where you can store and/or access several lines of text quick and easy. As with others high level languages, a static array of strings has several details:
- Every element is exactly the same size (in memory).
- If the text lines are very short you would be wasting memory.
- You must be careful with long lines of text that could overwrite other elements in the array.
* The first is also a big advantage, as you can use an index to access every element quickly.
* The second is to be spected as every text has its own length. Just declare the primary string (structure) long enough for what you need.
* If you use the array for storage (ie. a text file) make sure every line is shorter than the primary structure at runtime so it can be truncated, etc before storing inside the array.
Now some code. =) =) Here is a very simple example, declaring an small array with 3 strings preloaded and a loop printing the text. In my case, I made a console project in Easycode so you should do the same with your IDE and fit the code.
There are too many comments but I'm aiming at the poor noobs like me xD xD
; please include masm32.lib and masm32.inc for the printing part.
.Const
MaxString Equ 30 ; lenght of every line of text; this way you can give maintenance better ;-)
MaxArray Equ 2 ; three elements in array (0, 1, 2)
.Data?
.Data
LoopCounter DD 3
; main structure containing the string itself
StringStruct Struct
MyString DB MaxString Dup(0) ; VERY important as you can't add the "0,13, etc" at the end.
StringStruct EndS
; declare array and preload text on it
; you can, of course, leave it empty and fill it at runtime
MyArray StringStruct MaxArray Dup (<"First text">, <"Second text">, <"Final text">)
; name type elements text stored
LineFeed DB 13, 10, 0 ; change line after you print it
Main Proc Private
Mov Ecx, LoopCounter ; initialize print loop
Mov Edi, 0 ; EDI is the index in order to access every element
@MyLoop:
Push Ecx ; avoid disaster with StdOut
Invoke StdOut, Addr (StringStruct Ptr MyArray[Edi]).MyString ; print element at Array[Edi]
Invoke StdOut, Addr LineFeed ; same as Enter at the end
Pop Ecx ; restore loop counter
Add Edi, Type StringStruct ; move EDI to the next element in array
Loop @MyLoop
Ret
Main EndP
Greetings to Masm32's comunity. =) =)
Hi AssemblyChallenge,
you should check the examples and tutorials in the MASM32 package. And welcome to the forum.
Gunther
Hi AssemblyChallenge,
Nice first post :t
Welcome to the Forum :icon14:
ASSEMBLYCHALLENGE,
You will probably find this helpful: MASM Programmer's Guide (pdf) (http://masm32.com/board/index.php?topic=3445.msg36269#msg36269)
Hi, for a string you can allocate a dynamic memory for the string where the pointer is placed on another array.
.data
string_holder dd 0,0,0,0,0,0,0,0
string dd 0
.code
invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,1024
mov string,eax
invoke lstrcat,string,CADD("My First string")
lea edx,string_holder
add edx,0*4
mov [eax],string
invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,1024
mov string,eax
invoke lstrcat,string,CADD("My Second string")
lea edx,string_holder
add edx,1*4
mov [eax],string
invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,1024
mov string,eax
invoke lstrcat,string,CADD("My Third string")
Quote from: Zen on August 20, 2014, 09:27:02 AM
ASSEMBLYCHALLENGE,
You will probably find this helpful: MASM Programmer's Guide (pdf) (http://masm32.com/board/index.php?topic=3445.msg36269#msg36269)
Thank you! Already got a copy 8)
The book I'm reading is ''Assembly Language for x86 Processors (6th Edition)'' by Kip Irvine and so far no complains; it's very complete and not so hard to understand. The only detail: He uses Visual Studio -wich is fine- but sometimes I have to make a few "translations" for Easycode.
Greetings.
@Farabi:
That's great and the best approach -I guess- for bigger text arrays. My example tries to give a hand with simpler problem: small arrays, no need for GlobalAlloc and so on. In my own case, I made a small project a couple of weeks ago where dinamic memory was overkill :t
Regards.
Helping a little bit more:
As every element is in the same memory block, you have instant access to any of them. Let's say you have a 10 elements array (from 0..9) and you need to read/write element 4, assuming EDI as index again is very easy, all you have to do is multiply the element (4) by the size of the string structure:
.Data
MyIndex DD 0 ; put here the element to access
.Code
.
.
Mov MyIndex, 4 ; fourth element please (or whatever between 0..9)
Mov Eax, Type StringStruct ; size of structure
Mul MyIndex ; multiply and store displacement in EAX
Jc @Overflow ; just in case as EDX is used too if result too big
Mov Edi, Eax ; save final result in EDI
.
.
... whatever... Addr (StringStruct Ptr MyArray[Edi]).MyString
Making a static array in either the initialised or uninitialised data section is easy enough and occasionally useful but dynamic array are far more powerful and can be allocated in their millions of members. One thing you will need to be careful with using the Irvine book is not properly preserving registers. The Windows specification is known as the Intel ABI which involves preserving EBX ESI EDI EBP and ESP between procedure calls. A normal MASM proc preserves EBP and ESP but if you use any of EBX ESI or EDI you need to preserve them before the proc uses them and restore them before the proc exits.
The spec allows you to trash EAX ECX and EDX and you should write your code accordingly.
Here is a small example for you. Plonk this into the MASM32 editor and build it with the normal option.
IF 0 ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
.data
aarr dd 0,1,2,3,4,5,6,7,8,9
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
push ebx ; preserve these 2 as they are used
push esi
mov esi, 10 ; use ESI as the counter
mov ebx, OFFSET aarr ; put the address in EBX
@@:
print str$([ebx]),13,10 ; display dereferenced array item (each number)
add ebx, 4 ; set address to next number
sub esi, 1 ; decrement the counter
jnz @B
pop esi ; restore them again before exit
pop ebx
ret ; bye bye
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
Result will look like this.
0
1
2
3
4
5
6
7
8
9
Press any key to continue ...
Quote from: hutch-- on August 20, 2014, 03:46:39 PM
The spec allows you to trash EAX ECX and EDX
But the ABI does not
force you to trash these regs. For example, if a coder for whatever strange reasons thinks that ecx is a precious register that should be preserved between calls to a library, as demonstrated here (http://masm32.com/board/index.php?topic=94.msg36898#msg36898), then he is absolutely free to do so. No (legit) sheriffs will show up and throw you in the coder's jail 8)
Yes there is, its called the Windows API, it will say nasty things to you for making mistakes before it closes your program down.
I have had this problem for years, most of the old fellas know how to use registers in unconventional ways but they try and teach the learners the right way first rather than mislead them into writing broken unreliable code that may work on one OS version and crash on the next. Microsoft wrote the API in conformity with the Intel ABI, unless you are writing your own OS you have little choice apart from the occasional unconventional code that runs behind correct register preservations lower down the call tree.
Quote from: hutch-- on August 20, 2014, 04:54:48 PM
Yes there is, its called the Windows API, it will say nasty things to you for making mistakes before it closes your program down.
The Windows API is one thing, a "private" library is another thing. Sure,
invoke Sleep, 500 will trash ecx, but
Delay (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1212)500 won't, and it's documented, and it's legal code that will never crash, even in Windows 19.3 :biggrin:
AssemblyChallenge,
just some some notes to the code of your first post:
- Equates (EQU) exist only while assembling thus there is not need to put their declaration into the .const-section
- Because MyArray is already correctly typed, you could directly write: Addr MyArray[Edi].MyString
- The type-operator is not need in your example, because MASM does resolve type-IDs to their size in bytes if not used for declaration or definition: Add Edi, StringStruct
I still fail to see the point of misleading beginners when they need to learn the ABI to write reliable code. Without it they are being lead down the garden path writing unreliable garbage. The notion of "private library" is fine IF the end user knows its deviant and uses a different register convention to the standard ABI that Microsoft support.
"Sure, invoke Sleep, 500 will trash ecx, " This may be fine in one version of Windows but you have no way of knowing what it will be in another and this is the problem of testing on one version. Having written code for every version of NT4 sp1/2/3/4/5/6, win95 a/b/c win98/se Win2000 sp 1/2/3/4, XP sp 1/2/3 and now Win7, you can be sure that its not the same as Microsoft compilers have changed over time.
Quote from: qWord on August 20, 2014, 07:15:11 PM
AssemblyChallenge,
just some some notes to the code of your first post:
- Equates (EQU) exist only while assembling thus there is not need to put their declaration into the .const-section
- Because MyArray is already correctly typed, you could directly write: Addr MyArray[Edi].MyString
- The type-operator is not need in your example, because MASM does resolve type-IDs to their size in bytes if not used for declaration or definition: Add Edi, StringStruct
Thank you, qWord, I'll try and see how it goes xD xD My example is based on Invine's book. The whole structure addressing thing is a little bit intimidating and that was one of the reasons I choose it; kind of pulling the ghost's sheet :bgrin: :bgrin:
if you have strings of different lengths, use a vector table
apTable dd szString1,szString2,szString3
szString1 db "cdfsfsdfsdfs",0
szString2 db "52353453453453",0
szString3 db "234j4kjokijkl",0
the index into the table is always a multiple of 4 :biggrin:
Sometimes it's good to have the length of the strings, too:
include \masm32\include\masm32rt.inc
.code
apTable dd sizeof szString1, szString1, sizeof szString2, szString2, sizeof szString3, szString3
szString1 db "cdfsfsdf",0
szString2 db "52353453453453 lonoooooong",0
szString3 db "234j4kjokijkl",0
start: mov esi, offset apTable
xor ebx, ebx
.Repeat
print str$([esi+8*ebx]), " bytes: ", 9
print [esi+8*ebx+4], 13, 10
inc ebx
.Until ebx>2
exit
end start
ASSEMBLYCHALLENGE,
When I started out in assembly programming, I bought the Fifth Edition of Kip Irvine's, ''Assembly Language for x86 Processors". I found a copy in the University of California's library,...it's really the only thing out there for novice assembly programmers. But, it has problems. We get posts all the time here at the MASM Forum from beginners who are trying to use Irvine's Library procedures with procedures from the MASM package. As you will notice after you've read a number of the examples from the MASM package, Irvine's procedures will not work with the example code provided in the MASM examples directory. Irvine's code is extremely simplistic, and is designed to work only with other Irvine routines. I suggest you read through some of the example code in the MASM package,...it's much better written, demonstrates actual techniques that you would use in a real program, and, in general, works well with any procedures that you may write yourself.
Also, a large portion of the book is devoted to 16-bit DOS programming, including an explanation of using interrupts in your executable. Both of these techniques are no longer useful. Current versions of the Windows Operating System will NOT execute 16-bit DOS code (except using an emulator), and calling either hardware or software interrupts in a MASM program will crash your application.
Also,...and this is important,...he provides hardly any useful information at all about floating point techniques. The documentation provided by Intel is especially useful in this regard. You probably already know about this, but, here is the website for downloading: Intel® 64 and IA-32 Architectures Software Developer Manuals (http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html). They are definitely the most useful documentation on assembly programming available on this planet,...
Volume 1, Basic Architecture, IA 32 Software Developer's Manual, Chapter Eight, PROGRAMMING WITH THE X87 FPU.
you can search the forum for mention of Kip
the biggest issue is that kips library does not follow the rules of the windows ABI
Zen & Dave,
Kip's lib is not really the latest state-of-the-art, but it can be used flawlessly with Masm32 and even MasmBasic. There is a demo in \Masm32\MasmBasic\IrvineMb\IrvineMasm32.asc - open in \Masm32\MasmBasic\RichMasm.exe and hit F6.
As to the ABI thing: There is really no urgent need to start another holy war on this, but as a matter of fact, Kip preserves more regs than needed, and is therefore on the safe side. Coders need to pay attention that Win32 API calls trash ecx and edx, but that doesn't mean that saving them is dangerous.
quite often, arguments are passed in EBX, ESI, or EDI (usually EDI, i think) - that's not per the ABI
kip irvine floating point routines are buggish
also.....
1) In the kip irvine library, the "OPTION CaseMap:None" directive is commented out as optional.
Per Microsoft API documentation, case sensitivity should be observed.
The Masm32 library is also designed for case sensitive symbols.
2) The POINT structure is defined with members named upper-case "X" and "Y".
Per Microsoft documentation, these are named lower-case "x" and "y".
3) "GetTextColor" and "SetTextColor" are functions defined in the kip irvine library.
They are used to retrieve and set console-mode text color.
However, pre-existing Microsoft API functions (used for GUI apps) are defined in Gdi32.dll.
4) "MsgBox" is a PROC defined in kip irvine, used in a few kip irvine example programs.
"MsgBox" is a powerful MACRO defined in Masm32, used in many existing programs.
5) "exit" is a TEXTEQUate (pseudo-macro) defined in kip irvine library.
"exit" is a MACRO defined in Masm32 that allows an optional return code argument.
The Masm32 macro will perform the same function if no arguments are specified.
6) The kip irvine prototype for SetConsoleCursorPosition uses a COORD type.
While this is technically correct, the Masm32 library uses a more desirable DWORD type.
Quote from: jj2007 on August 21, 2014, 04:18:41 AM
As to the ABI thing: There is really no urgent need to start another holy war on this, but as a matter of fact, Kip preserves more regs than needed, and is therefore on the safe side. Coders need to pay attention that Win32 API calls trash ecx and edx, but that doesn't mean that saving them is dangerous.
It's not false to save ECX and EDX during a CALL, but following the calling conventions (https://en.wikipedia.org/wiki/X86_calling_conventions) that's not necessary. But all that depends on the circumstances and the selected CALL (STDCALL, FASTCALL etc). Saving all registers reduces side effects, but is not the fastest way. If someone wants to program defensive, the register save method is right.
Gunther
> Coders need to pay attention that Win32 API calls trash ecx and edx
This is simply the Intel ABI that Microsoft support. You preserve them if you need to at the caller end, not in the called proc. We all know how to write code that is not interacting with the OS to use all 8 registers (Copy ESP into a DWORD variable and copy it back later) but it must be done AFTER the correct registers are preserved lower down the call tree. If you don't it will go BANG somewhere.
Its not a holy war, its a voice crying in the wilderness, stop misleading learners so they write dangerous unreliable code and give up assembler after it keeps crashing. Once they know how it all works, they can develop bad habits like the rest of us. :biggrin:
deleted
Quote from: hutch-- on August 21, 2014, 05:31:59 AM...it must be done AFTER the correct registers are preserved lower down the call tree. If you don't it will go BANG somewhere.
OMG, Hutch, can you now kindly quote the phrase where I wrote that "the correct registers" should
NOT be preserved???
If my intention was to "mislead learners" and make them addicted to HIGH RISK CODING, then I would write "
use esi edi ebx as you like, especially in callbacks". But I didn't write that; what I wrote instead is "YES YOU ARE F**CKING ALLOWED TO SAVE AN EXTRA REGISTER LIKE ECX BECAUSE THIS IS A FREE WORLD, AND TRUST ME, IF YOU SURROUND YOUR CODE WITH PUSH ECX ... POP ECX, IT WILL NEVER EVER CRASH, AMEN".
JJ (weeping in the wilderness)
@Dave: nice list of issues, it seems you studied Kip's library throughly :t
I think you have missed the drift of my comments, for the last 15 years or so I have been fighting a losing battle to get folks learning assembler to comprehend the ABI so that their code works on all versions of Win32 yet year after year I get people who want to modify the ABI with the comments that it does not really matter or it works on Win?? in their language version and year after year I see learners write dangerous code that crashes because they have not protected the required registers.
The subtleties get lost in the noise and many learners fall by the wayside because they have to digest so much that they cannot differentiate between useful and obscure or at times ever wrong information. The old fellas all know how to write irregular code somewhere up a call tree that uses all 8 registers and any mix you like of MMX and even SSE registers but it does not help the learner to try and follow the obscurities when they have yet to learn the basics.
I posted a very simple example to show the original poster that protecting the required registers produces safe code rather than the Irvine technique that does not. As usual the effort was wasted because it was lost in the noise.
Why do you keep typing the letters "xD xD" for? Is it supposed to mean something?
Quote from: jj2007 on August 20, 2014, 04:15:49 PM
Quote from: hutch-- on August 20, 2014, 03:46:39 PM
The spec allows you to trash EAX ECX and EDX
But the ABI does not force you to trash these regs. For example, if a coder for whatever strange reasons thinks that ecx is a precious register that should be preserved between calls to a library, as demonstrated here (http://masm32.com/board/index.php?topic=94.msg36898#msg36898), then he is absolutely free to do so. No (legit) sheriffs will show up and throw you in the coder's jail 8)
"But the ABI does not Force you to trash these regs." You may be interested to know that the ABI doesn't force you to eat the tires off UPS trucks either.
Quote from: Oliver Scantleberry on April 08, 2016, 02:14:27 PMthe ABI doesn't force you to eat the tires off UPS trucks either.
Quote from: Oliver Scantleberry on April 08, 2016, 12:54:27 PM
I thought UPS delivered packages. Now they do power glitches too?
At your age, I'd be really careful with these mushrooms 8)
Ok jockey, that sounds like good advice.
Quote from: jj2007 on August 20, 2014, 05:38:50 PM
Quote from: hutch-- on August 20, 2014, 04:54:48 PM
Yes there is, its called the Windows API, it will say nasty things to you for making mistakes before it closes your program down.
The Windows API is one thing, a "private" library is another thing. Sure, invoke Sleep, 500 will trash ecx, but Delay (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1212)500 won't, and it's documented, and it's legal code that will never crash, even in Windows 19.3 :biggrin:
I don't know about Windows Ver. 19.3 jockey, but 'Delay 500' sure errors out on Windows Ver. 14. Is it some sort of garbage you've plagiarized
from a high school drop-out?
Ollie, stop eating those mushrooms. At your age, they are dangerous for your health 8)