Hi all,
I've started with MASM after many years of not doing any programming. I used to program for DOS, where I got used to having such a thing as a PSP, and a memory map corresponding to the physical memory present. So I'm somewhat at sea with 32-bit PM, where it's all a bit abstract.
Couple of questions:
1. I was glad to see a "tutorial" folder amongst the extracted files, and I've assembled and run a couple of the demo programs. I copied one of them (called "address.asm" in the "demo 6" sub-folder) over into a folder I created where I intend to store my own programs. The first thing is, it didn't work when I assembled and ran it from there, though it ran fine in the "demo 6" folder. Second, after assembly the console reports a different sized .obj file. The original is 1407 bytes. The one in my own folder is 1389 bytes, though the asm file is identical. What's gone wrong?
2. My purpose in doing the above was to amend the program to make it display some facts about the starting conditions. I wanted to see what the starting values were for cs, ds, ss and esp, and where the data had been assembled in memory. Can anyone direct me to some online tutorial that explains what happens at start up? What does kernel.inc do? How much memory has been claimed by the program, and where is it? Stuff like that.
3. I will obviously need a disassembler. Can anyone suggest one that's easy to learn and use?
Thanks for your time. Nice forum.
Quote from: Terpsichore on August 13, 2013, 12:16:32 AM
3. I will obviously need a disassembler. Can anyone suggest one that's easy to learn and use?
Go straight for Olly (http://www.ollydbg.de/version2.html). It will also show you where cs, ds, ss and esp are. Easy to learn, just use F8 to step forward, or F9 to run until the next
int 3 (or the next crash :icon_mrgreen:)
Welcome to the Forum :icon14:
I agree on use olly
Welcome to forum
Magnus
Thanks for those fast replies. I will certainly check out olly this evening.
In the meantime I moved my little program back into the "demo6" folder where it works fine. Just won't work where it was.
Amending some of the instructions in that little routine I got it to write the relevant values to the screen
cs - 27
ds - 35
es - 35
ss - 35
esp - 1245204
eip - 4198452
And the address where the first bit of data was assembled was 4206592. And I see data and stack are sharing the same segment selector.
You'll have to forgive my ignorance, but things that are obvious to you are not obvious to me. I understand that, unlike real mode, protected mode won't allow mixing code and data together, so there can be nothing in the cs segment except code. And if my program starts at 4198452, there must be colossal amounts of code below it - 4Mb, if my arithmetic is correct. But what is it, and what does it do?
A similar question about esp. Why so high? Do you need 1 Mb of stack?
And the offset where the data was assembled. Same thing - why so high?
Hi Terpsichore,
welcome to the forum.
Gunther
win32 programming is very different from the old 16-bit code
you rarely care what the segment registers are :P
they no longer point to a page of memory
instead, they hold an index into a table that desribes the actual memory address and range
when you start a win32 program, you get 4 gb of addressable space
2 gb of that is "reserved" for system use
the stack has the capability to grow, as required, to balance memory requirements
ignore which segment is which and more-or-less write as though all your stuff is in one big segment
if you don't specify otherwise, code for a typical program begins at 400000h
here's the main point.....
you can pretty much forget about specific addresses where things are located :t
if you want to do things that you used to do via the PSP, there are usually some sort of API calls to perform the operations
for example, GetCommandLine will return an address to a zero-terminated string
no more mucking about with specific addresses
something that 16-to-32 newcomers usually bump into....
for 16-bit code, you set up registers, then "call'ed" an interrupt routine
very different for 32-bit
parameters are generally passed on the stack
the INVOKE macro (masm internal macro) will take care of pushing them onto the stack for you
INVOKE MessageBox,NULL,offset szText,offset szTitle,MB_OK
actually generates the following code
push MB_OK ;a constant defined in windows.inc
push offset szTitle
push offset szText
push NULL
call MessageBoxA ;the ANSI version of MessageBox (MessageBoxW is the UNICODE version)
the MessageBox function takes care of balancing the stack on exit
another thing worth noting....
EAX, ECX, and EDX are likely to be trashed when calling an API function
EAX is usually used to return a status or result dword (not the carry flag)
the other registers are preserved across the call
the direction flag should be cleared before calling, so clear it if you set it
and, we generally write our own "re-usable" functions following the same set of rules
Quote from: Terpsichore on August 13, 2013, 02:54:46 AM
And if my program starts at 4198452, there must be colossal amounts of code below it - 4Mb, if my arithmetic is correct. But what is it, and what does it do?
What's below it (and above it) is part of the process
Virtual Address Space (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366912(v=vs.85).aspx/css), and there may or may not be physical memory mapped into the address space. This code scans the first GB of the process virtual address space for readable memory blocks and displays the address of the block and the size, build as a console app.
;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================
.data
.code
;==============================================================================
start:
;==============================================================================
print " address length",13,10
print "-------------------------",13,10
xor ebx, ebx
.WHILE ebx < 40000000h
.IF rv(IsBadReadPtr, ebx, 1) == 0
mov esi, ebx
.WHILE esi
.IF rv(IsBadReadPtr, esi, 1)
inc esi
print uhex$(esi),"h",9
mov edi, 1
.WHILE edi < 40000000h
.IF rv(IsBadReadPtr, esi, edi)
.WHILE edi
.IF rv(IsBadReadPtr, esi, edi) == 0
print uhex$(edi),"h",13,10
jmp @F
.ENDIF
dec edi
.ENDW
.ENDIF
add edi, 1024
.ENDW
@@:
xor ebx, ebx
add ebx, esi
add ebx, edi
.BREAK
.ENDIF
dec esi
.ENDW
.ENDIF
add ebx, 4096
.ENDW
inkey "Press any key to exit..."
exit
;==============================================================================
end start
Running on my Windows XP system:
address length
-------------------------
00010000h 00001000h
00020000h 00001000h
00033000h 00100000h
00140000h 00004000h
00240000h 00006000h
00250000h 00003000h
00260000h 00016000h
00280000h 00041000h
002D0000h 00041000h
00320000h 00006000h
00330000h 00004000h
00340000h 00003000h
00400000h 00004000h
And before someone bothers to point this out, IsBadReadPtr should normally be avoided, see:
http://blogs.msdn.com/b/oldnewthing/archive/2006/09/27/773741.aspx
QuoteA similar question about esp. Why so high? Do you need 1 Mb of stack?
Depending on what your app does you could need that and more. And in recent times a MB is a small amount of memory.
there are numerous other little things to pick up on, as well
one big step is simply, how programs are assembled
a lot more goes into a windows program - include files, import libraries - all that
you will pick up on it as you go along
another more obvious point is all the changes in the 32-bit instruction set :biggrin:
addressing modes have been greatly expanded
you can do things like
mov edx,[eax+4*ecx]
also, the BSWAP, BSF, and BSR instructions are just a few of the new ones i had to learn
Thanks for all these replies. There's a lot to absorb and think about, so no doubt I'll be back to pursue it further.
In the meantime, does anyone know why my program works in one folder, but not in another?
Quote from: Terpsichore on August 13, 2013, 05:30:29 AMIn the meantime, does anyone know why my program works in one folder, but not in another?
Difficult to say without knowing your setup. Masm32 has old-fashioned hard-coded paths, i.e.
include \masm32\include\masm32rt.inc
.code
AppName db "Masm32:", 0
start: MsgBox 0, "Hello World", addr AppName, MB_OK
exit
end startThis won't work if your *.asm source folder is somewhere on C: and your Masm32 is D:\Masm32
But it will work perfectly (to my experience at least) on each and every D: folder.
Check for spaces in folder names, though, they can be nasty.
You may also check Masm32 Tips, Tricks and Traps (http://www.webalice.it/jj2006/Masm32_Tips_Tricks_and_Traps.htm)
if it's one of the older examples, it may be that it assembled properly with the old include files
they were updated fairly recently - a lot of big changes
generally, we try to make mention in the following subforum when we find issues.....
http://masm32.com/board/index.php?board=22.0 (http://masm32.com/board/index.php?board=22.0)
A quick google brought this up... http://www.acm.uiuc.edu/sigwin/old/workshops/winasmtut.pdf (http://www.acm.uiuc.edu/sigwin/old/workshops/winasmtut.pdf)
a fairly precise explanation..
Old but still one of the best Tutorial's on Win32 .. http://win32assembly.programminghorizon.com/tutorials.html (http://win32assembly.programminghorizon.com/tutorials.html)
Welcome to the machine !