Author Topic: A 64-bit Nasm assignment procedure; set(val,var)?  (Read 27787 times)

Offline mjrice

  • Jr. Member
  • *
  • Posts: 66
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #15 on: October 11, 2018, 12:28:41 PM »
Passing subroutine parameters by reference allows one to change the parameter within the subroutine. A good example is a subroutine that swaps a and b.

Fortran:

      subroutine swap(a,b)
      temp=b
      b=a
      a=temp
      return
      end

Note: Fortran automatically types variables that begin with I-J-K-L-M-N as integer,
all others as real (float). Which means you that needn't explicitly declare them.

C:
void swap(int *a, int *b)
{
   int t;
 
   t  = *b;
   *b = *a;
   *a = t;
}
     
Fortran passes addresses implicitly. C must do it explicitly.

Michael

Offline dreamCoder

  • Full Member
  • **
  • Posts: 107
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #16 on: October 11, 2018, 01:07:54 PM »
Thanks for the explanations Michael.

From what I see, I suspect that gfortran uses the heap to store the arguments. That means that you can't use RBP/RSP addressing due to them not being on the stack. But if they do, you could try moving up and down the stack to check its content, like;

mov rax,[rsp-16] / [rsp+16]

or something like that, regardless of alignment.

And also try comparing the value of RSP and RDI. If they're radically different, than I am pretty sure that RDI is pointing to a heap memory area. Similarly you can move up and down RDI to verify the content of any arguments in the vicinity.

This is fun and new to me. I wished I knew gfortran.
 

Offline mjrice

  • Jr. Member
  • *
  • Posts: 66
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #17 on: October 12, 2018, 03:31:14 AM »
To Frank:

mov rdi, [rdi]

Thanks for that. It's been something I was wondering about.

To: dreamcoder

I'm unsure what problem you're addressing. I was only using RBP as a temporary register to execute the necessary double dereferencing. Frank's provision (see above) makes doing that much more straightforward.

Michael







 

Offline dreamCoder

  • Full Member
  • **
  • Posts: 107
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #18 on: October 12, 2018, 04:34:12 AM »
I was actually trying to zoom in into the possibility that your earlier code was actually overwriting / missing the return address and hence throwing invalid memory reference upon return. x86's call / ret mechanism work the same across languages / calling conventions - return address must reside at TOS prior to RET. You first code is showing that clear symptom of missing the return address. But it's good to know that you already solved it.

Offline dreamCoder

  • Full Member
  • **
  • Posts: 107
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #19 on: October 12, 2018, 06:13:44 AM »
After a detailed investigation, I found that the statement

call set(13,k)

will actually force the compiler to put a foreign immediate on the stack. This will make the return address to be off by one 'notch', hence the invalid reference upon return.

The remedy is not to pass an immediate to a call, since gfortran is pass-by-reference, but simply to supply a proper argument to such function where gfortran has more control over the internal stack. And btw, gfortran aligns the stack by default. So the solution is much simpler and more straightforward.

Code: [Select]
! prog.f     
! gfortran prog.f test.o -o prog
     
      external :: set
      integer k,j
      k=0
      j=13     !use this instead of direct immediate to feed an external function
      call set(j,k)
      print *,k
      end

The asm file
Code: [Select]
;test.asm
;nasm -f elf64 test.asm

global set_
section .text
set_:
mov rax, [rdi]
mov [rsi], rax
ret

That's how curious I am on new things that need reversing. hehehe ;D 

EDIT: On the second thought, using a direct immediate to feed an external function is going to clobber RDI.
« Last Edit: October 12, 2018, 07:12:32 AM by dreamCoder »

Offline mjrice

  • Jr. Member
  • *
  • Posts: 66
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #20 on: October 12, 2018, 12:40:09 PM »
Ignore. Pressed wrong button.
« Last Edit: October 12, 2018, 01:19:53 PM by mjrice »

Offline mjrice

  • Jr. Member
  • *
  • Posts: 66
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #21 on: October 12, 2018, 02:12:37 PM »
To dreamcoder:

The error could have many causes, most likely the disparity between 64-bit NASM compilation and not insisting that gfortran use 64-bit integers and reals, which was fixed by adding those flags to the gfortran compilation. Not insisting leaves those sizing decisions to gfortran's optimizer, which might leave garbage in the high-order 32-bits of a 64-bit word. Who knows...

Moving on. Earlier in the year, I believe I found value, and maybe behavioral, differences, between addresses acquired via Fortran's "loc" function and a machine address function written in assembly, "madov," which I used seven years ago. I'll be reviewing my notes about that and see what conclusion I reached, if any.

If you've downloaded gfortran you could write your own madov.asm function and test it with same gfortran main program. The "madov" function must leave the address in RAX, and must have those same ending underscores in its name. And gfortran main program must include.

integer, external :: madov

You could also keep Fortran's "loc" to see if they match.

Infer how to add it to the gfortran compilation by looking at how "set" was added. Don't forget the three Fortran flags.

Michael

Offline mjrice

  • Jr. Member
  • *
  • Posts: 66
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #22 on: October 13, 2018, 01:59:40 AM »
I looked through some notes from last June and found that I was testing addresses without the three Fortran flags. With the flags included, the addresses acquired with "madov" and "loc" match.

global madov_

section .text  ;return the (64-bit integer) machine address of a variable

madov_:
  mov  rax, rdi
  ret

      integer, external :: madov
      c=17.5
      i=loc(c)
      j=madov(c)
      print *, i,j
      end

[mrice@localhost ~]$ nasm -f elf64 madov.asm -o madov.o && gfortran -fdefault-integer-8 -fdefault-real-8 -fno-range-check madovtest.f90 madov.o && ./a.out
      140730831529000      140730831529000
[mrice@localhost ~]$ nasm -f elf64 madov.asm -o madov.o && gfortran -fdefault-integer-8 -fdefault-real-8 -fno-range-check madovtest.f90 madov.o && ./a.out
      140720354825944      140720354825944

Next up, two asm functions to access the contents of an address; "cont" to access a real (float), "inhalt" to access an integer.

Michael



 

Offline mjrice

  • Jr. Member
  • *
  • Posts: 66
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #23 on: October 14, 2018, 12:06:37 AM »
This isn't going to work. Seven years ago, back in 32-bit land, one could store an address in a 32-bit word. That no longer holds in 64-bit land, as the addresses printed in my last post reveal.

Decimal                   Hex
140720354825944   7FFC02C316D8

I need to poke around and see if there's a path forward.

Michael





Offline mjrice

  • Jr. Member
  • *
  • Posts: 66
Re: A 64-bit Nasm assignment procedure; set(val,var)?
« Reply #24 on: November 11, 2018, 05:23:41 AM »
I'm back, and back in 32-bit land after downloading and installing the latest 32-bit versions of Fedora Linux (29), Gfortran, and Nasm.

The test function executed fine after doing a new make on my archived directory.

I then ran the same code in my last two posts in 32-bit to produce the following:

          -1081206440           3213760856

The two values are the output the Gfortran "loc" function and the nasm "madov" function respectively. They're just the signed and unsigned decimal values of the same binary integer address.