forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Speaking of stacks....
Goto page 1, 2  Next
 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support
View previous topic :: View next topic  
Author Message
wahorger



Joined: 13 Oct 2014
Posts: 1214
Location: Morrison, CO, USA

PostPosted: Wed Apr 25, 2018 5:58 pm    Post subject: Speaking of stacks.... Reply with quote

I was befuddled by a OpenGL error. The program would crash when a Fortran I/O statement was executed after about 150 iterations. If I removed the I/O statement, it works well. I suspected a stack issue.

So, I put in a stack checker, in-line assembly code that allows me to save the ESP register. I'd used this before with a different stack issue, to good success.

I simplified the first section of the code, generating a OpenGL window. Each Winio@ call causes the stack pointer to change. FYI: the OpenGL calls also do the same. I suspect this causes the crash when looping. If this were in a subroutine, the stack pointer is always returned to the proper value just prior to the return.

Code:

        use mswin
        integer i,ctrl
        integer stack_val
        code
        mov stack_val,ESP%
        edoc
        print *,'Before call=',stack_val
        call abcd
        code
        mov stack_val,ESP%
        edoc
        print *,'After call=',stack_val
        end
        subroutine abcd   
        integer i,ctrl
        integer stack_val
        i=winio@('%es&')
        code
        mov stack_val,ESP%
        edoc
        print *,'%es=',stack_val
        i=winio@('%ca[Simple OpengGL Sample]&')
        code
        mov stack_val,ESP%
        edoc
        print *,'%ca=',stack_val
        i=winio@('%sp&',0, 0)
        code
        mov stack_val,ESP%
        edoc
        print *,'%sp=',stack_val
        i=winio@('%ww[not_fixed_size]&')
        code
        mov stack_val,ESP%
        edoc
        print *,'%ww=',stack_val
        i=winio@('%og[static]&',800, 800)
        code
        mov stack_val,ESP%
        edoc
        print *,'%og=',stack_val
        i=winio@('%lw', ctrl)
        code
        mov stack_val,ESP%
        edoc
        print *,'%lw=',stack_val
        return
        end


On my system, the outputs show:
Code:

Before call=56687760
%es= 56687508
%ca= 56687504
%sp= 56687500
%ww= 56687496
%og= 56687492
%lw= 56687488
After call=56687608


Using compiler V8.3, Plato, compile options for RELEASE32=/SAVE /FPP /CFPP

FYI: The OpenGL calls affect the stack pointer by way more than just 4 bytes.
Back to top
View user's profile Send private message Visit poster's website
wahorger



Joined: 13 Oct 2014
Posts: 1214
Location: Morrison, CO, USA

PostPosted: Wed Apr 25, 2018 8:38 pm    Post subject: Reply with quote

N.B.: When I moved the looped sections of OpenGL from the Main to a subroutine (so the routine will get called 360 times), the program crashed after the first iteration. Moving the code back into Main means that I get the stack overflow eventually, but more than 1 iteration works.

The crash lists no routine names, just absolute offsets.
Back to top
View user's profile Send private message Visit poster's website
wahorger



Joined: 13 Oct 2014
Posts: 1214
Location: Morrison, CO, USA

PostPosted: Thu Apr 26, 2018 5:26 pm    Post subject: Reply with quote

Just as another possible reason why I can get things to crash (or not), it appears that the HEAP and STACK are allocated after the .reloc (reference the Section Map), and in that order, HEAP first, then STACK.

If the program over-runs the STACK, then it starts into the HEAP, then other data (if it doesn't crash first).

Do I have the ordering correct?

Because what I think I'm seeing with my "crashes" is the call(s) to OpenGL routines likely use the stack heavily to allocate temporaries, and if the stack is insufficient, this corrupts the heap and/or other data areas.
Back to top
View user's profile Send private message Visit poster's website
mecej4



Joined: 31 Oct 2006
Posts: 1884

PostPosted: Fri Apr 27, 2018 10:16 am    Post subject: Reply with quote

Bill, monitoring the stack pointer the way that you did can provide useful information, but one should not put too much value on that information. A wandering ESP value does not provide proof of memory leakage or incorrect stack management.

Before the 80386, one could not use the stack pointer in the R/M field of an instruction. You had to move the value of SP to BP, adjust the bias if necessary, and use BP in the R/M field. That changed with the 80386, and now EBP could be used as just another register instead of being dedicated to use as a frame pointer. Gfortran does, in fact, have the option -fomit-frame-pointer.

For a CDECL call on the 8086, we had PUSH arg1; PUSH arg2;...;CALL ..; ADD SP,nn. With the 80386 and later, the code emitted by compilers shows a more relaxed attitude, and ESP is restored many instructions after the CALL or not at all. When the code contains a number of Fortran CALLS with few other statements, ESP may be restored after all the calls have been executed.

I have not studied the code emitted by FTN95 often enough to say whether the above comments apply to it, but the modern relaxed view of ESP and EBP is something to keep in mind when inserting very short CODE ... EDOC sequences in Fortran code..
Back to top
View user's profile Send private message
wahorger



Joined: 13 Oct 2014
Posts: 1214
Location: Morrison, CO, USA

PostPosted: Fri Apr 27, 2018 2:00 pm    Post subject: Reply with quote

Thanks, mecej4,

There can be negative ramifications for the stack pointer being manipulated/"adjusted" while the current routine is running. If the stack pointer is incremented (equivalent of a POP), then the contents of the stack can/will be trashed, resulting in many bad things happening when the module is exited.

Or, in the case I brought up a couple of years ago, the constant decrement of the stack pointer can eventually result in the stack intruding into the data apace, corrupting those data.

What I'm seeing in the OpenGL crashes are instruction addresses that appear to be in the data space. This would be consistent with the stack being hammered by, perhaps, the PUSH of a data item address into the return address. There are a myriad of possibilities.

In the OpenGL module where I am having issues, the stack appears to be totally trashed. Meaning the stack pointer after the OpenGL calls is greater than the stack pointer upon entry to the test_routine. This would look like 1 or more POP instructions. Which means that a subsequent call will wipe out one or more addresses/registers on the stack, and possibly altering the return address for the current module.

The value of the stack pointer is important.

Of greater concern is the OpenGL calls, which leave the stack pointer decremented by way too much.

I'm working on a smaller version of the OpenGL issue that can be posted here showing the issues.
Back to top
View user's profile Send private message Visit poster's website
wahorger



Joined: 13 Oct 2014
Posts: 1214
Location: Morrison, CO, USA

PostPosted: Fri Apr 27, 2018 4:01 pm    Post subject: Reply with quote

So, here is an example of what can happen with a messed up stack pointer.

The code segments below were run under Plato as Release WIN32 with the options: /SAVE /WIDE_SOURCE /EXPLIST /FPP /CFPP

The two include files are:
save_stack.ins:
Code:
   code
   mov stack_at_entry,esp%
   edoc



and current_stack.ins:
Code:
   code
   mov current_stack,esp%
   edoc



The main body (forumtesting.for) is:
Code:

!       winapp
        use mswin
        use opengl$
        integer ctrl,window_handle
        integer stack_at_entry,current_stack
        stack_at_entry = 0
        current_stack = 0
        include 'save_stack.ins'
        i=winio@('%es%ca[Simple OpengGL Sample]&')
        i=winio@('%sp%ww[not_fixed_size]%og[static]%hw%lw',0, 0, 400, 400,window_handle,ctrl)
        CALL glClearColor (0.0, 0.0, 0.0, 0.0)
        include 'current_stack.ins'
        print *,'Stack values',stack_at_entry,current_stack
        print *,'Negative means likely corrupted stack:',stack_at_entry-current_stack
        CALL glClear(GL_COLOR_BUFFER_BIT)
        CALL glColor3f(1.0, 1.0, 1.0)
        CALL glMatrixMode(GL_PROJECTION)
        CALL glLoadIdentity()
        CALL glOrtho(0d0, 10d0, 10d0, 0d0, -1d0, 1d0)
        call glnewlist(1,gl_compile)
        call glBegin(GL_LINE_STRIP)
        call glVertex2f(0.,0.)
        call glVertex2f(10.,10.)
        call glEnd()
        call glEndlist()
        call glCalllist(1)
        call glFinish()
        call swap_opengl_buffers@()
        call glCalllist(1)
        call glFinish()
        call swap_opengl_buffers@()
        include 'current_stack.ins'
        print *,'Stack values',stack_at_entry,current_stack
        print *,'Negative means likely corrupted stack:',stack_at_entry-current_stack
        pause
        end


Running this yielded the following output:
Quote:
Stack values 56687648 56687656
Negative means likely corrupted stack: -8
Stack values 56687648 56687736
Negative means likely corrupted stack: 269709653

Note that the last calculation shown is NOT the proper value (shown as 269709653, S/B -8Cool. This is the example of how the stack pointer can affect the results. If I restore the stack pointer just prior to this last set of statements, the results show:
Quote:

Stack values 56687648 56687656
Negative means likely corrupted stack: -8
Stack values 56687648 56687648
Negative means likely corrupted stack: 0
Back to top
View user's profile Send private message Visit poster's website
mecej4



Joined: 31 Oct 2006
Posts: 1884

PostPosted: Fri Apr 27, 2018 6:08 pm    Post subject: Reply with quote

The code clarifies things, thanks. You are concerned specifically about ESP changing after returning from a call to an OpenGL or Winio@ routine, rather than during the course of a sequence of assignment statements.

I do not use graphics routines/libraries with FTN95, so I can only remark that the correct interfaces must be used. The interface module and the DLL that provides the OpenGL routines must be consistent. Since I see a number of senior users discussing Clearwin usage, I assumed that matters were in great shape.

Just to see the effect, I replaced your USE OPENGL$ by USE XGL, where xgl.mod was produced by compiling a three-line file containing

module xgl
include 'opengl.ins'
end

I found that the stack convention was quite different from that which I saw when I had USE OPENGL$. The EXE produced with XGL uses STDCALL for OpenGL calls whereas the OPENGL$ and WINIO@ calls appear to be CDECL.

Silverfrost should be able to clarify this issue, unless the answers are already in the help file. I agree, Bill, that a Fortran CALL should result in ESP being restored to its value after the execution of the previous statement. Perhaps, Eddie or Dan can provide their opinions.

P.S. (after reading Eddie's response below): There is a table showing how to provide the proper OpenGL interfaces for 64bit Fortran compilers other than FTN95 at https://www.silverfrost.com/ftn95-help/clearwinp/util/64bit.aspx (I found that page through Google Search, and I hope to find a similar page for 32-bit calls). Much of the information on that page is date-sensitive, and we may only infer the date from the download information for a particular distribution of GFortran -- around 2011. A README.TXT, updated for each release of FTN95, with a catalog of the files included and their intended purpose, would be helpful in avoiding what Wahorger did, namely, using with FTN95 a MOD file meant for use with Gfortran -- OPENGL$.mod . The recently released 8.30 compiler does include a README.TXT; please read it!


Last edited by mecej4 on Sat Apr 28, 2018 12:14 pm; edited 3 times in total
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7912
Location: Salford, UK

PostPosted: Fri Apr 27, 2018 10:14 pm    Post subject: Reply with quote

The following FTN95 files appear to be correct...

opengl.ins
opengl.mod
opengl.mod64

The (gFortran) file opengl$.mod looks a first sight to be wrong. It may be built from third party code that uses the wrong binding. I will make a note that this needs investigating. However, there is no need to use this particular file when compiling with FTN95.

The whole of the Silverfrost ClearWin+ library uses C_EXTERNAL (i.e. CDECL) binding and this includes winio@.
Back to top
View user's profile Send private message AIM Address
mecej4



Joined: 31 Oct 2006
Posts: 1884

PostPosted: Sat Apr 28, 2018 2:51 am    Post subject: Reply with quote

If I am not mistaken, I think that there is a longstanding problem here.

This is what I see happening when the Fortran source contains calls to WINIO@ and is compiled for 32-bit. The arguments are pushed on the stack in the usual CDECL way. Then, two additional hidden arguments are pushed before the CALL is made. This first of these is a count of the arguments, and the second hidden argument is a null-terminated string, apparently containing information regarding the argument types. After returning from the WINIO@ routine, one of these hidden arguments is not accounted for when the usual ADD ESP, nn adjustment is made.

For example, for the Fortran statement i=winio@('%sp&',0, 0), six items are pushed on the stack:
    1) The integer 4, which is the hidden string length argument;
    2), 3) The integer 0, twice;
    4) The address of the string '%sp&';
    5) The integer 3, which is the number of arguments;
    6) The string "*C*I*I\x00", which seems to indicate that the arguments are a pointer to a character variable and two pointers to integers.
After the call to WINDOW_PRINTF@@ with these arguments, the stack adjustment is done with add esp,=20, and we have lost 4 bytes, as Wahorger pointed out. We should have seen add esp,=24, instead.

The fifth and sixth items above appear to be intended for calling library routines with generic names and/or optional arguments.


Last edited by mecej4 on Sat Apr 28, 2018 9:28 am; edited 1 time in total
Back to top
View user's profile Send private message
wahorger



Joined: 13 Oct 2014
Posts: 1214
Location: Morrison, CO, USA

PostPosted: Sat Apr 28, 2018 4:06 am    Post subject: Reply with quote

Paul, thanks for the update.

I tried including the opengl.ins, but my source is .for, with wide_source enabled and the include file doesn't support this. I've run into this before, and could use some insight into how to turn the .ins file into a .mod file! I've looked, but not found, a method.

Perhaps that is the reason why all this is going on with the OpenGL!

Still doesn't quite explain the winio@ stack stuff. Then again, it's not likely to have hundreds or thousands of winio@ calls that muck up the stack!

Bill
Back to top
View user's profile Send private message Visit poster's website
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7912
Location: Salford, UK

PostPosted: Sat Apr 28, 2018 7:56 am    Post subject: Reply with quote

mecej4

Many thanks for the feedback. I will make a note that this needs checking out.

Bill

opengl.mod should have been built (by us) from the program

Code:
module opengl
include <opengl.ins>
end module opengl


I will need to check this out but in the meantime you could add this code to your program (if necessary, put it in a separate file and compile using free format).

opengl.ins should also work for fixed format and wide source. Again, I will take a look to see why this does not work.
Back to top
View user's profile Send private message AIM Address
LitusSaxonicum



Joined: 23 Aug 2005
Posts: 2388
Location: Yateley, Hants, UK

PostPosted: Sat Apr 28, 2018 8:05 am    Post subject: Reply with quote

Mecej4,

I'm sorry to say that I've never been able to fathom OpenGL, and lost interest in trying when I discovered that different graphics cards support (or don't) different features, so in a race to the bottom, the common factor wasn't that much different to the GDI, which is guaranteed to be present on every Windows PC. I had hoped to learn from a regular contributor to the forum, but he died some years ago. Almost certainly if he'd lived he would be on to 64 bit and OpenGL.

My basic position on anything to do with Fortran, graphics, Windows, life, the Universe and everything is that if it is there it should work, whether I personally need it or not. In the case where something did work, but now doesn't, or never worked at all, it is far easier to live with if one can find out about it before spending weeks struggling, and if there is a criticism in this it is about the failure to use the knowledgebase in the Forum or elsewhere to point out such issues. Take for example the Clearwin+ handle issue - it was public knowledge, and that was lost in the depths of the forum. Now it resurrected it is going to be dealt with. I must add that SF and Paul are good at addressing issues that are raised and the documentation does get updated, but less obviously.

Eddie
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7912
Location: Salford, UK

PostPosted: Sat Apr 28, 2018 8:15 am    Post subject: Reply with quote

Bill

/wide_source does not work with opengl.ins and fixed format because the trailing ampersand is not consumed correctly.

The following code works correctly. /wide_source is replaced by an OPTIONS compiler directive...

Code:
      module opengl
      include <opengl.ins>
      end module opengl
      options(wide_source)
      program main
      use opengl
      print*,"123456789012345678901234567890123456789012345678901234567890",GL_ACCUM
      end
Back to top
View user's profile Send private message AIM Address
mecej4



Joined: 31 Oct 2006
Posts: 1884

PostPosted: Sat Apr 28, 2018 8:51 am    Post subject: Re: Reply with quote

I urge that the suggested code
Code:
      module opengl
      include <opengl.ins>
      end module opengl
      options(wide_source)
      program main
      use opengl
      print*,"123456789012345678901234567890123456789012345678901234567890",GL_ACCUM
      end
be split into two pieces, with the first piece being just
Code:
      module opengl
      include <opengl.ins>
      end module opengl

Doing so will give two benefits: no imposing of the source format needs of one part on the other; no need to run large fixed content files such as OPENGL.INS through the compiler whenever a user program is recompiled.
Back to top
View user's profile Send private message
mecej4



Joined: 31 Oct 2006
Posts: 1884

PostPosted: Sat Apr 28, 2018 9:39 am    Post subject: Re: Reply with quote

wahorger wrote:
I tried including the opengl.ins, but my source is .for, with wide_source enabled and the include file doesn't support this. I've run into this before, and could use some insight into how to turn the .ins file into a .mod file! I've looked, but not found, a method.

This is a repetition of what has been stated in other responses, but I don't want you to miss it:

1. Create a separate source file in the same form as that of the INS file, with just three lines.

Code:
      module opengl
      include <opengl.ins>
      end module opengl

Compile this file, and USE the module, instead of including OPENGL.INS in your regular Fortran source files.

2. Do not use MOD files with '$' in the name if your code is to be compiled with FTN95.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support All times are GMT + 1 Hour
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group