- 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 foo
subroutine 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
retq
Note, 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