Hi Guys! I am new to the forum and MASM32 development environment but I am loving it and the community on this forum already.
My question pertains mainly to a problem I am having with assembling and linking basic programs. For some reason when I try to
"Console Assemble and Link" the following code, I get this error:
"error LNK2001: unresolved external symbol _main"
code:
Quote
.486
.MODEL flat
.code
main:
mov eax,0FFFFFFFFh
END main
I have been able to get other examples to run, but for some reason these basic ones won't link.
I am trying to focus on 32-bit code currently. I am coming from writing my basic assembly programs in Visual Studio 2012.
Any help is appreciated, Thanks in advance everyone!
Welcome LoveToLrn,
.486
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.data
; your data here
.code
; your subroutines here
start: ; starting point of your program
invoke ExitProcess,0
end start
Have you downloaded the masm32 SDK? http://masm32.com/masmdl.htm
It has a lot of examples.
Yes I downloaded the whole package I believe. I wasen't sure if I was missing any "mission critical" code like those includes,
looking at them I can see what I missed, thanks very much Siekmanski! :biggrin:
that specific error is probably related to the missing line
.MODEL Flat,StdCall
terminating with ExitProcess is also a nice idea
but, i can understand what you were doing - you eliminated all the externals
the processor, model, casemap option, and includes can all be done with one line
INCLUDE \Masm32\Include\Masm32Rt.inc
that is a plain ASCII text file that you can open and examine with NotePad
it covers the most-often used includes and libraries
OH! Thanks for the tip dedndave! Can I modify the text file with my own libs/includes?
you can, but i don't recommend it :eusa_naughty:
just add any additional includes and/or includelibs after that line
INCLUDE \Masm32\Include\Masm32Rt.inc
.586
INCLUDE \Masm32\Include\AdvApi32.inc
INCLUDELIB \Masm32\Lib\AdvApi32.lib
and - anything that's in there that your program does not use won't affect the size of the EXE
the reason i don't recommend it.....
you won't be compatible with all the code posted in the forum
when someone else tries to build your project - bang - errors
same when you try to build someone else's
EDIT: i also added a bump in the processor from 486 to 586
Ok, good point, thanks :biggrin:
Also is your .586 directive just a more recent version of the processor model than .386, or .486 for that matter?
Is there any benefit to specifying a more recent processor model number beyond .386?
yes there is
it allows you to use the newer pentium instructions and instruction forms
one example that comes to mind is the RDTSC instruction, but there are others
also, if you want to use SIMD instructions....
.686
.MMX
.XMM
i think the masm version that is in the masm32 package goes as far as SSE2 extensions
you can find newer versions of the assembler that can handle SSE3, 4, etc
also, JwAsm is a free assembler that handles them and is nearly 100% compatible with masm
Awesome, Thanks for the info!
I am not as far along as SIMD but hope to be writing more complex programs soon.
I think you guys and this forum as a whole will be a HUGE boost! Very glad I found it. :biggrin:
try this program
assemble as console mode
.XCREF
.NoList
INCLUDE \Masm32\Include\Masm32rt.inc
.List
;###############################################################################################
;initialized data section
.DATA
szMessage db 'Hello World !',0
;***********************************************************************************************
;uninitialized data section
.DATA?
dwSomeVal dd ?
;###############################################################################################
;code section
.CODE
;***********************************************************************************************
_main PROC
print offset szMessage
print chr$(13,10)
inkey
INVOKE ExitProcess,0
_main ENDP
;###############################################################################################
END _main
I tried it out, I was wondering how to pass a wait message to the console! Thanks :biggrin:
Also didn't know there was a .data segment for uninitialized variables.
Quote from: LoveToLrn on December 04, 2013, 03:36:07 PM
Also didn't know there was a .data segment for uninitialized variables.
There isn't. The data segments are...
.const
Here you define any global constant data such as integer constants, string constants and floating point constants etc.
.data?
Here you define uninitialised global variables such as general variables, arrays and structures etc. Memory is reserved but not initialised.
.data
Here you define initialised global variables such as general variables, arrays and structures etc. Memory is reserved and initialised.
Quote from: hamper on December 04, 2013, 10:39:50 PM
.data?
Here you define uninitialised global variables such as general variables, arrays and structures etc. Memory is reserved but not initialised.
That is the "official" version. Truth is the OS initialises them to zero - in contrast to local variables, which are really not initialised, i.e. a space is reserved for them on the stack, but it will contain garbage.
I knew that was the situation under C, where uninitialised global variables are automatically initialised to zero (for numeric) or nul (each byte of a character or string), and uninitialised local variables of any type are not automatically initialised at all (so their memory locations will still contain whatever was there already), but I didn't know whether this was the case under assembly language as well. Guess I'll have to check this out and update my notes accordingly. Thanks for the info.
The development of these languages involved a design philosophy in which conflicts between performance and safety were generally resolved in favor of performance. The programmer was given the burden of being aware of dangerous issues such as uninitialized variables.
What is so dangerous about uninitialized variables ?
I am assuming that the programmer is consciences and sets it properly before using it.
Do some operating systems set it to zero in case the programmer boofed up ?
Andy
Quote from: hamper on December 05, 2013, 05:08:03 AM
I knew that was the situation under C, where uninitialised global variables are automatically initialised to zero (for numeric) or nul (each byte of a character or string), and uninitialised local variables of any type are not automatically initialised at all (so their memory locations will still contain whatever was there already), but I didn't know whether this was the case under assembly language as well. Guess I'll have to check this out and update my notes accordingly. Thanks for the info.
It's somehow difficult to find proper documentation for the fact that the .data? contains zeroes on program start. Wiki says (http://en.wikipedia.org/wiki/Data_segment#BSS):
QuoteThe BSS segment, also known as uninitialized data, starts at the end of the data segment and contains all global variables and static variables that are initialized to zero or do not have explicit initialization in source code. For instance a variable declared static int i; would be contained in the BSS segment.
Heap
The heap area begins at the end of the BSS segment and grows to larger addresses from there.
Just in case a newbie reads this, let's be a bit more explicit:
_bss segment
myvar dd ?and
.data?
myvar dd ?do exactly the same: they mark the beginning of the uninitialised data segment.
In fact, it is not C but Windows who cares about zeroing the .data? segment, so assembly code automatically enjoys the same treatment, i.e. zeroed variables that don't increase the size of the executable ("bss = better save space").
In contrast, local variables are created on the stack by one simple instruction:
sub esp, size_of_locals (the PROLOGUE macro knows the total size required for local variables and takes care to reserve it on the stack with this instruction).
As you can see in Olly (http://www.ollydbg.de/version2.html), on top of a proc there is not the faintest effort to zero the space created with sub esp, xxx; so if the stack has been used elsewhere in your code, it may contain values of pushed variables, return addresses etc, and occasionally also zeros.
In case you want to use these variables to assign values to them, no problem. If, however, your code assumes that they are zero, you might run into trouble. Take this simple example:
include \masm32\include\masm32rt.inc
.code
start:
call foo
inkey chr$(13, 10, "Nice, isn't it?")
exit
foo proc uses esi edi ebx Arg1, Arg2
LOCAL ct
; a ClearLocals (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1151) macro would be nice ;-)
.Repeat
inc ct
print "*"
.Until ct==50
ret
foo endp
end startJust test it - you will see a long line of stars. Great, isn't it? Now test the same inside a bigger application, and you'll see how your screen fills up with stars. If you have a console, that is - a GUI app will just hang, or maybe it won't, it really depends on what kind of garbage fills the variable "ct" at that particular moment. In any case, you have a ticking bomb in your code...
There was a dedicated "FindBugs for Assembler" thread (http://findbugs%20for%20assembler) some time ago, which treated the uninitialised locals issue, too.
P.S.: In case this is not yet confusing enough: In C, you can use the
static keyword for local variables:
#include <stdio.h>
void PrintCt (void) {
static int ct=0; // WOW, a "static" local variable...
ct++;
printf("%i ", ct);
}
int main(void) {
PrintCt();
PrintCt();
PrintCt();
return 0;
}
Guess what it will output 8)
Hi,
It is the operating system that zeroes out uninitialized memory
on program load for security reasons. Or fills it with some other
value. When I was programming in FORTRAN on a CDC mainframe,
uninitialized variables were set to an illegal value if used by a real
(floating point) calculation. (Boom, end of program.) When used
in an integer calculation, (I think) it just produced a garbage result.
Regards,
Steve N.