Building Multi-Module Projects using GoASM.

Started by Chip, September 27, 2006, 12:06:48 PM

Previous topic - Next topic

Chip

Jeremy,

Thanks, I like the solution of using the push/pop to save all but the ESP.
I was never happy using memory stores for registers, but having to use
so many registers, it was a throwback to my initial experience with assembly.

By the way, I did find the conceptual basis for stacks and frames.  It turns
out that they were not used in mainframe processing initially - hence my
puzzlement.  Someday when I can find time, I will write up a short background
and history of the use of stacks in computers and post here.  (There are quite
good white papers on the subject - but they are very long and detailed.)

Chip
I am on Skype under my email address!

Chip


I am continuing to experience problems with linking about
10 modules into one.  In fact, I seem to be going backwards,
spending more time on figuring out why data that was
calculated correctly suddenly "disappears" or is listed in the
wrong module.

It seems that the inclusion of "INT3" to set breakpoints is
somehow destroying pointers to data.  On many occasions,
I have a DEBUG screen set to monitor critical items of data,
only to see them all reset to zero upon the execution of an INT3.

Also, I have had to insert a "JMP" to call the first module. 
Using INVOKE or CALL results in an invalid address.  (This is
way before I attempt to save and restore ESP and EBP.)

I am extremely careful in saving both ESP and EBP, and restoring
them after use before executing any calls or returns.  I use no
push or pops, instead reverting back to saving them to memory.
(I only need ESP and EBP in TWO computationally intensive modules,
All of the rest of the program should run normally.)   

Also, Data that is declared in one module, and used in a second module,
is showing up in debug as being in a third module.

In conclusion, I use many "INT3" for debugging purposes,
               
               None of my data sections are declared as shared,
                   even though I share data between all modules.
               
               None of my labels are shown or declared as "LOCAL",
                   (All jumps are to LABEL:, never to .LABEL   
               
               The entry points of modules seem to be adjusted by
                   "something" other than my own code.
               
               The location of data is erroneously being shown in
                   the incorrect module at startup, and randomly
                   dissappears based upon the use of int3.         
                   
                   
Perhaps I have specified something incorrectly, or made some mistake.
However, rereading all of the documentation numerous times has yet to
show me the error of my ways.

Since it is critical that I debug my own code, I am thinking about
putting everything back into one LARGE source module.  While I would
rather not do this, I just can not continue with the random resets of
program and data pointers.

Can anyone offer a solution?

Chip
                   





Where Data is declared:

            DATA Section "DAll"
           
            SavedEsp                        DD  ?
            SavedEbp                        DD  ?
           
           ;Calculation_Control_Block
                Calculation_Sum_Higher      DD  ?   
                Calculation_Sum_High        DD  ?   
                Calculation_Sum_Low         DD  ?   
                Calculation_Power           DD  ?
   
   
          ***** The "Dall" data section is in the control program *****
          ***** that is called first, it then calls other modules *****


How the Source is LINKED:


            "C:\Program Files\Assembly\Go Assembler\GoLink64\GoLink.exe" ALL.obj @LinkOBJ.Input @LinkDLL.Input >LinkALL.prt

            @LinkOBJ.Input                                   
                        /b                     ;Beep on Error
                        /files                 ; List all input files
                        ;/Unused               ;List Unused label References
                        /Console
                        /debug dbg             ;link this file to make MyProg.exe
                       
                        Analyse.obj
                        Calculate.obj
                        Compute.obj
                        Read.obj
                        Write.obj
                        Setup.obj
                        Log.obj
                        Shortcut.obj

            @LinkDLL.Input
                        ;MyProg.res            ;use this file for resource input
                                               
                        Kernel32.dll
                        User32.dll
                        Gdi32.dll
                       
                        COMCTL32.dll
                        comdlg32.dll
                       
                        OLEAUT32.dll
                        Hhctrl.ocx
                        winspool.drv
                        shell32.dll
                        ole32.dll   

            GoLink.Exe Version 0.26.4 - Copyright Jeremy Gordon 2002/6-JG@JGnet.co.uk
           
            C:\Program Files\Assembly\Program\Objects\ALL.obj
                Made on Wednesday, October 11, 2006 at 19:36 size: 3,111 bytes
            C:\Program Files\Assembly\Program\Objects\Analyse.obj
                Made on Wednesday, October 11, 2006 at 19:36 size: 1,989 bytes
            C:\Program Files\Assembly\Program\Objects\Calculate.obj
                Made on Wednesday, October 11, 2006 at 19:36 size: 1,294 bytes
            C:\Program Files\Assembly\Program\Objects\Compute.obj
                Made on Wednesday, October 11, 2006 at 19:36 size: 1,359 bytes
            C:\Program Files\Assembly\Program\Objects\Read.obj
                Made on Wednesday, October 11, 2006 at 19:36 size: 1,075 bytes
            C:\Program Files\Assembly\Program\Objects\Write.obj
                Made on Wednesday, October 11, 2006 at 19:36 size: 1,386 bytes
            C:\Program Files\Assembly\Program\Objects\Setup.obj
                Made on Wednesday, October 11, 2006 at 19:36 size: 7,872 bytes
            C:\Program Files\Assembly\Program\Objects\Log.obj
                Made on Wednesday, October 11, 2006 at 19:36 size: 1,665 bytes
            C:\Program Files\Assembly\Program\Objects\Shortcut.obj
                Made on Wednesday, October 11, 2006 at 19:36 size: 957 bytes
            C:\SYSTEM\system32\Kernel32.dll
                Made on Wednesday, August 04, 2004 at 05:00 size: 983,552 bytes
                Number of required imports found in this file: 13
           
            Output file:
            C:\Program Files\Assembly\Program\Objects\ALL.EXE
            Format: win32 size: 9,216 bytes
                Number of exports: none
                MSLU loader code: not added
           
            Output file:
            C:\Program Files\Assembly\Program\Objects\exe\ALL.DBG
            Format: win32 size: 10,716 bytes
                Number of exports: none
                MSLU loader code: not added








Where DEBUG incorrectly shows the data:

                           GoBug - copyright Jeremy Gordon 1996-2005
                        Date: Wednesday, October 11, 2006 Time: 19:40:04
                                  Dump of exe/dll data symbols
                                    whilst debugging ALL.exe
       
       
              All_Save                                  48C098h        "DShort"
              Analyse_Error                             40A004h        "DAll"
              Analyse_Save                              49121Ch        "DShort"
              Buffer_Array                              48C1E4h        "DShort"
              Buffer_Length_Bits                        40A024h        "DAll"
              Buffer_Length_Bytes                       40A020h        "DAll"
              Buffer_Number                             40A01Ch        "DAll"
              Buffer_Segment_Count                      40A028h        "DAll"
              Calculate_Error                           40A008h        "DAll"
              Calculate_Save                            5312B4h        "DShort"
              Calculation_Power                         491218h        "DShort"
              Calculation_Sum_High                      491210h        "DShort"
              Calculation_Sum_Higher                    49120Ch        "DShort"
              Calculation_Sum_Low                       491214h        "DShort"
              Cluster_Array_Pointer                     491200h        "DShort"
              Cluster_High_Array                        490200h        "DShort"
              Cluster_Length_Bits                       40A044h        "DAll"
              Cluster_Length_Bytes                      40A040h        "DAll"
              Cluster_Low_Array                         48F200h        "DShort"
              Cluster_Sum_High                          491204h        "DShort"
             
             
             ***** "DShort" is the data section for the last module linked     *****
             ***** IT contains NONE of the data shown as being resident there. *****
             
             
             
             
             
             
I am on Skype under my email address!

jorgon

Hi Chip

You are using "?" to initialise a data declaration, and this causes GoAsm to regard the label as unitialised data. 
GoAsm by design (and as documented) therefore puts such labels in the .bss section in the object file.
When the linker encounters unitialised data in a .bss section it simply adds that data to a convenient data section, which in this case happens to be the last one declared.  The .bss section does not end up in the exe.  As far as I am aware most linkers act in a similar way.
Unitialised data can save a lot of empty space in the exe, but you can't specify how the linker deals with it, or which data section the labels are allocated to.

The solution in your case is therefore to use a zero ("0") instead of the "?" where you want a data label to end up in a specified data section.
But why have separate data sections anyway?

By the way next time you get stuck with something like this you can look inside the object files themselves (and all sorts of other files) using Wayne Radburn's PEView which is available from here.



Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)

Chip

Jeremy,

At first I was concerned at your suggestion, since declaring all data
as initialized would change the disk image from 5k to 1,300k.  Also,
having one data section would defeat the purpose of having separate
object modules (Code and Data).

However, after playing with it, I assume that you meant not naming
the code or data sections.  I tried this, and now the program has a
disk image of only 5k.  That makes me quite happy.  (Some of my
large arrays can probably be removed after debugging,  but during
the initial stage I would rather overdesign than constantly deal with
arrays being exceeded by "real world" test input.)

I am still encountering problems with calls and int3.  It is rather curious
to see the debugger encounter an "INT3" just before a return.  It
jumbs back two instructions and then blows with an invalid address.
Perhaps this is only when an INT3 is placed just before a return.
Since I am more concerned with debugging my math logic, I have
placed JMP's to avoid the problem for the moment.

I encountered one other problem, but will post under a seperate topic.

Chip
I am on Skype under my email address!

donkey

I have not encountered the problem of debug jumping back instructions if INT3 is placed before a RET, I tried to test it but found that it debugged properly both using GoBug and Olly...

00401025   CC               INT3
00401026   89EC             MOV ESP,EBP
00401028   5D               POP EBP
00401029   C3               RETN




Which is exactly what I expect to see
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Chip

Donkey,

Here is the codepane for the last few
steps of my control program.  (I have "INT3"
scattered throughout my modules for
debugging purposes.)  I am unsure how to
display a screen dump on this forum, so here
is the codepane from the interactive session.

Chip



    The following sequence of steps are visible
    in the code pane during debugging:
   
   
        Just prior to this codepane,      there was an INT3 in the write module.
         
           
        Step 1 is the result of an F9,    returns to the control module, and
                                                                       stops on 40101B
                                                     
        Step 2 is the result of an F5,    it jumps back     to  40101A
       
       
        Step 3 is the result of an F5,    it jumps forward to 40101B 
       
       
        Step 4 is the result of an F5,    screen goes blank with a purple
                                          "Unable to Disasmble" error message
       
        Step 5 - sometimes restarting the debugger at this point will result
                 in a normal "end" without error message above.                                       
         





                           GoBug - copyright Jeremy Gordon 1996-2005
                        Date: Saturday, October 14, 2006 Time: 02:14:03
                                        Dump of codepane
                                  whilst debugging Control.exe
       
       
                                                       ~~~Start:~~~>
                                                       401000: CALL Setup
                                   
                                                       ~~~SetupEnd:~~~>
                                                       401005: JMP >>401250
                                   
                                                       ~~~AnalyseEnd:~~~>
                                                       40100A: JMP >>4011E0
                                   
                                                       ~~~ReadEnd:~~~>
                                                       40100F: JMP >>401300
                                   
                                                        ~~~CalculateEnd:~~~>
                                                        401014: INT3
                                                        401015: CALL Write
                                   
                                                        ~~~WriteEnd:~~~>
Step 2.  Then, F5 jmps here             40101A: INT3
                                   
                                                        ~~~End_of_Control_Module:~~~>
Step 1.  F9 ends up here                   40101B: RET
Step 3.  Next F5 jmps back to Ret    40101C: NOP
Step 4.  "Unable to dissamble"          40101D: NOP
                   Error Message                40101E: NOP
                                                         40101F: NOP
                                   
                                                        ~~~Setup:~~~>
                                                       401020: PUSH [Input.FlagsAndAttributes]
                                                       401026: PUSH [Input.CreationDisposition]
 
I am on Skype under my email address!

jorgon

Quote
It is rather curious
to see the debugger encounter an "INT3" just before a return.  It
jumbs back two instructions and then blows with an invalid address.

Chip, I've tested placing INT3 just before a RET in my own code and pressing "run" (F9), and it works properly with the break occurring just after the INT3 as it should do.  Then the next single-step (F5) executes the RET instruction, which returns from the call.  Could it be that in your code, this is all that is happening?  In other words when you say that "Step 2 is the result of an F5, it jumps back to 40101A" this is simply returning to the instruction after "Call Write".  Could be happening because the jumps you have inserted actually cause one function to jump to another function in this case Write without actually returning?  The way to resolve this would be to call functions normally rather than using JMP to get to them.  If you are finding that CALLs result in execution continuing from the wrong place, this is most probably because you haven't matched every PUSH with a POP, leaving the stack out of place at the RET instruction (PUSH, POP, CALL, RET and INVOKE all affect the stack).

Quote
It seems that the inclusion of "INT3" to set breakpoints is
somehow destroying pointers to data.  On many occasions,
I have a DEBUG screen set to monitor critical items of data,
only to see them all reset to zero upon the execution of an INT3.

I do not think it is the INT3 itself that is doing this.  Instead, I'm sure you will find that it is the code which executes prior to the break at INT3 which is doing this.

Author of the "Go" tools (GoAsm, GoLink, GoRC, GoBug)