- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am trying to access the arguments passed by Intel's F90 compiler to an assembly routine. The first four, passed in registers, I have no trouble accessing. However, I cannot access the remaining four, which should be on the stack. POP does not seem to work. Here is the test code:
PROGRAM FF
   IMPLICIT NONE
   INTEGER(4),EXTERNAL :: AAA
   INTEGER(4) :: W1, W2, W3, W4, W5, W6, W7, W8, R
   W1 = 11
   W2 = 12
   W3 = 13
   W4 = 14
   W5 = 15
   W6 = 16
   W7 = 17
   W8 = 18
   R1 = 0
   R1 = AAA(W1, W2, W3, W4, W5, W6, W7, W8)
   PRINT *, R1
END PROGRAM FF
        TITLE      AAA
       .CODE
       PUBLIC AAA
AAA:
      MOV RAX,0
      POP RAX
      RET
      END
What am I missing?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Do not POP! You will crash upon return
Use rbp
Example:
RECURSIVE SUBROUTINE VECNRM_r_r (VA, VC)
00007FF6E8795D90  push        rbp  
00007FF6E8795D91  push        r14  
00007FF6E8795D93  push        r15  
00007FF6E8795D95  sub         rsp,80h  
00007FF6E8795D9C  lea         rbp,[rsp+30h]  
00007FF6E8795DA1  mov         r15,rdx  
00007FF6E8795DA4  vmovups     xmmword ptr [rbp+40h],xmm13  
00007FF6E8795DA9  mov         r14,rcx  ...
      RETURN
END SUBROUTINE VECNRM_r_r
00007FF6E8795DF6  lea         rsp,[rbp+50h]  
00007FF6E8795DFA  pop         r15  
00007FF6E8795DFC  pop         r14  
00007FF6E8795DFE  pop         rbp  
00007FF6E8795DFF  ret  Your subroutine will have different arguments than that above.
*** caution, if you modify rsp, unmodify it upon return
Suggestion,
Make a Fortran subroutine with the same arguments, call it with break point at entry.
Open a Dissassembly window when at break point, then model your assembly code after the Fortran entry and exit of procedure.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for this prompt response. However, I am not sure of what is going on in your example. All I require is the way to access the 5th through the last arguments which, according to the documentation, are on the stack. I believe RSP points to the stack. I have changed my assembly routine to:
        TITLE      AAA
       .CODE
       PUBLIC AAA
AAA:
      MOV RAX,0
      MOV RAX,{RSP]
      RET
      END
and I get the value 1481445554 instead of the expected value 15. Obviously, I am doing something wrong. My question is still:
How do I access the arguments on the stack?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You must study and understand the calling conventions of the Fortran compiler that you are using. The assembler code of the function must conform to those conventions. In addition, certain registers need to be saved on entry to the function routine, and must be restored before returning to the instruction following the function invocation point.
Note that, as soon as the function code is entered, the stack pointer has no longer the same value as before the CALL to the function. Thus, the arguments are no longer in the same memory locations relative to RSP in comparison to where they were before the CALL. Note that the RBP register is dedicated to accessing arguments on the stack. Before a CALL, some register values are also pushed to the stack. Arguments can be passed by value or by address.
You must understand all these conventions in order to write an assembler routine and get it to work with calls from Fortran code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
How is declared your AAA function on fortran side? The value may indicate a pointer to the value rather than the value itself.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, the arguments on the stack are by reference (unless modified by the interface.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
When your assembly routine AAA is entered, the stack top has the return address. Therefore, your POP RAX instruction puts that address into RAX, in contrast to your wish to move one of the other routine arguments into RAX. Furthermore, your zeroing RAX in the previous instruction makes no sense, given that the next instruction is going to overwrite the zero value in RAX. Furthermore, once you POP the return address into a register, the subsequent RET instruction will not work at all, since the return address is no longer on the stack in its expected position. Returning to a garbage address on the stack is almost certain to cause your program to crash.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
program Console23
    call foo(1, 2, 3, 4, 5, 6)
end program Console23
subroutine foo(one, two, three, four, five, six)
    integer :: one, two, three, four, five, six
    integer :: test
    test = one
    test = two
    test = three
    test = four
    test = five
    test = six
    print *,"break here"
end subroutine foosubroutine foo(one, two, three, four, five, six)
00007FF652441002  sub         esp,0A0h  ! reserve stack for foo
00007FF652441008  lea         rbp,[rsp+80h]  ! Set base pointer
00007FF652441010  mov         rax,r9  
00007FF652441013  mov         r9,qword ptr [rbp+58h]  
00007FF652441017  mov         r9,qword ptr [rbp+50h]  
00007FF65244101B  mov         qword ptr [rbp-18h],rcx  ! Store addrs of one arg
00007FF65244101F  mov         r10,qword ptr [rbp-18h]  ! r10 [rbp-18h]  = addr one
00007FF652441023  mov         qword ptr [rbp-20h],rdx ! store addre of two 
00007FF652441027  mov         r9,qword ptr [rbp-18h]  ! r9 [rbp-18h] = addre two
00007FF65244102B  mov         qword ptr [rbp-28h],r8  ! store addr three
00007FF65244102F  mov         r8,qword ptr [rbp-28h]  ! r8 [rbp-28h] = addr three
00007FF652441033  mov         qword ptr [rbp-30h],rax  ! store addr four
00007FF652441037  mov         rdx,qword ptr [rbp-30h]  ! rdx [rbp-30h] = addr four
00007FF65244103B  mov         rcx,qword ptr [rbp+50h] ! rcx [rbp+50h] = addr five
00007FF65244103F  mov         rax,qword ptr [rbp+58h] ! rax [rbp+58h] = addr six
    integer :: one, two, three, four, five, six
    integer :: test
    test = one
00007FF652441043  mov         r10d,dword ptr [r10]  
00007FF652441046  mov         dword ptr [TEST],r10d  
    test = two
00007FF65244104A  mov         r9d,dword ptr [r9]  
00007FF65244104D  mov         dword ptr [TEST],r9d  
    test = three
00007FF652441051  mov         r8d,dword ptr [r8]  
00007FF652441054  mov         dword ptr [TEST],r8d  
    test = four
00007FF652441058  mov         edx,dword ptr [rdx]  
00007FF65244105A  mov         dword ptr [TEST],edx  
    test = five
00007FF65244105D  mov         ecx,dword ptr [rcx]  
00007FF65244105F  mov         dword ptr [TEST],ecx  
    test = six
00007FF652441062  mov         eax,dword ptr [rax]  
00007FF652441064  mov         dword ptr [TEST],eax  
    print *,"break here"Your disassembly code may not set up its stack frame the way Fortran Debug build does.
The asm listing for release foo
	.def	FOO;
	.scl	2;
	.type	32;
	.endef
	.globl	FOO
	.p2align	4, 0x90
FOO:
.Lfunc_begin1:
	.cv_func_id 1
	.cv_loc	1 1 19 0
.seh_proc FOO
	subq	$56, %rsp
	.seh_stackalloc 56
	.seh_endprologue
.Ltmp3:
	.cv_loc	1 1 21 0
	cmpl	$0, (%rcx) ; one
	je	.LBB1_7
.Ltmp4:
	.cv_loc	1 1 22 0
	cmpl	$0, (%rdx) ; two
	je	.LBB1_7
.Ltmp5:
	.cv_loc	1 1 23 0
	cmpl	$0, (%r8) ; three
	je	.LBB1_7
.Ltmp6:
	.cv_loc	1 1 24 0
	cmpl	$0, (%r9) ; four
	je	.LBB1_7
.Ltmp7:
	.cv_loc	1 1 25 0
	movq	96(%rsp), %rax ; five
	cmpl	$0, (%rax)
	je	.LBB1_7
.Ltmp8:
	.cv_loc	1 1 26 0
	movq	104(%rsp), %rax ; six
	cmpl	$0, (%rax)
	je	.LBB1_7
.Ltmp9:
	.cv_loc	1 1 27 0
	addq	$56, %rsp
	retqNote, the Release build of this FOO did not use rbp.
Jim
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A hack that I've successfully used in the past is to write a shell function with same arguments in Fortran, compile it with the assembly listing, then strip out all the unnecessary assembly statements leaving an assembly shell function to which you insert your code.
Jim Dempsey
 
					
				
				
			
		
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page