Forum > General

[SOLVED] Linker issue

(1/2) > >>

MathMan:
Hi,

Environment: Lazarus 1.2.4 / FPC 2.6.4 / Win 7 64bit / Intel Core i5 430M @2.27 GHz

What do I have to do to convince the compiler to use 64 bit relocation for the inline assembler? Background is as follows.

I do keep some statistics counter in the general VAR definition


--- Code: ---unit Main;
...

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Menus;

type
  ...

var
  LongCalc: TLongCalc;

  Add_LLEU_Counter: QWORD;    // Counter for calls to add low level
  Add_LLEU_TotalTime: QWORD;  // Total time spend (in CPU clocks)
  Add_LLEU_LastTime: QWORD;   // Time spend (in CPU clocks) on last call
  Add_LLEU_MinTime: QWORD;    // Lowest time spend on all calls

--- End code ---

When I access these from within the inline assembler like


--- Code: ---function Add_LLEU   // Add Low Level Even Unsigned
(
  Op1: pLimb;  // first summand
  Op2: pLimb;  // second summand
  Res: pLimb;  // resulting sum
  Size: QWORD   // number of limb to work
):QWORD;        // Carry

begin

  {$IFNDEF ASM_VERSION} // Use Pascal only if assembly version is not avail

  {$ifdef KEEP_STATS}   // Inline statistics to be used

  asm
    rdtsc;              // Read time-stamp-counter from core
    shl     RDX, 32;    // Convert to 64 bit
    or      RAX, RDX;
    mov     qword ptr [Add_LLEU_LastTime], RAX; // Initialize this
    inc     qword ptr [Add_LLEU_Counter]        // One more activation counted
  end ['RAX', 'RDX'];

  {$endif}

--- End code ---

I do get the linker warning on 32bit absolute relocation used


--- Code: ---LongCalculator.lpr(20,1) Warning: Object file "main.o" contains 32-bit absolute relocation to symbol ".bss.n_u_main_add_lleu_counter".

--- End code ---

This means that I can only reliably run the code in the lower 4GByte of a virtual address range. As long as I keep the debugger info included Windows will start the program as required - but as soon as I remove debug info the program gets executed above that space and consequently stops with a SIGSEGV.

Any ideas what I can do about this? I read what I could find in the documentation but couldn't find something usefull.  Maybe there is doc available somewhere and I just haven't found it yet - linking me to where I should read on would then be highly appreciated.

Regards,
Jens

[02.08.2014] Edit: typos, rephrasing

MathMan:
Hi all again,

For all of you who'd like to see the solution (mainly my own stupidity) here's what happened and how I resolved it.


--- Quote from: MathMan on August 01, 2014, 11:24:55 pm ---Hi,

Environment: Lazarus 1.2.4 / FPC 2.6.4 / Win 7 64bit / Intel Core i5 430M @2.27 GHz

What do I have to do to convince the compiler to use 64 bit relocation for the inline assembler? Background is as follows.

...

--- End quote ---

Starting again with assembly language after >20 years revealed a lot of lost knowledge :-)

I completely forgot that the instruction set of x86 isn't very orthogonal so I initially tried to use combinations of instructions & addressing modes which simply aren't available. The inline assembler converted them to what is available (unfortunately a lot of things are ambiguous in assembly too) so it was finally the linker hinting me to what went wrong.

I started out with


--- Code: ---    rdtsc;              // Read time-stamp-counter from core
    shl     RDX, 32;    // Convert to 64 bit
    or      RAX, RDX;
    mov     qword ptr [SHR_LL_LastTime], RAX; // Initialize this
    inc     qword ptr [SHR_LL_Counter]        // One more activation counted

    ...

    rdtsc;              // Read time-stamp-counter from core
    shl     RDX, 32;    // Convert to 64 bit
    or      RAX, RDX;
    sub     RAX, qword ptr [SHR_LL_LastTime];   // Now RAX is the delta

    mov     qword ptr [SHR_LL_LastTime], RAX;   // Set last usage time
    add     qword ptr [SHR_LL_TotalTime], RAX;  // Add to total time spend
    cmp     RAX, qword ptr [SHR_LL_MinTime];    // Do we have a new low?
    cmovnc  RAX, qword ptr [SHR_LL_MinTime];    // No => keep old
    mov     qword ptr [SHR_LL_MinTime], RAX;    // Set accordingly

--- End code ---

What I forgot was that the addressing mode "offset64" (going to a full 64 bit address specified as an immediate value in the code) is - with respect to the above - only available for "mov" in connection with register RAX. After some fiddling I found the following replacement


--- Code: ---    rdtsc;              // Read time-stamp-counter from core
    shl     RDX, 32;    // Convert to 64 bit
    or      RAX, RDX;
    mov     SHR_LL_LastTime, RAX; // Initialize this
    mov     RAX, SHR_LL_Counter;  // One more activation counted
    inc     RAX
    mov     SHR_LL_Counter, RAX;

    ...

    rdtsc;              // Read time-stamp-counter from core
    shl     RDX, 32;    // Convert to 64 bit in RDX
    or      RDX, RAX;
    mov     RAX, SHR_LL_LastTime;
    sub     RDX, RAX;   // Now RDX is the delta

    mov     RAX, RDX;               // Set last usage time
    mov     SHR_LL_LastTime, RAX;
    mov     RAX, SHR_LL_TotalTime;  // Add to total time spend
    add     RAX, RDX;
    mov     SHR_LL_TotalTime, RAX;
    mov     RAX, SHR_LL_MinTime;    // Do we have a new low?
    cmp     RDX, RAX;
    cmovc   RAX, RDX;               // Yes => use it
    mov     SHR_LL_MinTime, RAX;    // Set accordingly

--- End code ---

This one now eliminates the linker warnings and the produces code looks as intended.

I think I have to re-read the Intel reference guide carefully :-)

Regards,
Jens

marcov:
I assume that can be considered an assembler reader bug, so I reported it: http://bugs.freepascal.org/view.php?id=26555

MathMan:

--- Quote from: marcov on August 03, 2014, 01:46:53 pm ---I assume that can be considered an assembler reader bug, so I reported it: http://bugs.freepascal.org/view.php?id=26555

--- End quote ---

I don't think so. From assembler sources one can usually infer verry little because it could always be the case that the author intentionally did something in a special way. In my bogus code above all resulting addressing modes were completely legal - so the assembler had to make do with what is available (in this case use 32bit offset variants of certain menmonics). That this can lead to catastrophy when linked & executed in a pure 64bit environment is beyond recognition of the assembler.

What the assembler could do IMO is throw a warning that the used addressing mode does not correspond to the intended environment. But even this I would only do in a very verbose setting. When using assembler the hard work of knowing what you're doing resides with the author.

That's my view on the issue - even if I have spend two days tracking this down.

MathMan:

--- Quote from: marcov on August 03, 2014, 01:46:53 pm ---I assume that can be considered an assembler reader bug, so I reported it: http://bugs.freepascal.org/view.php?id=26555

--- End quote ---

I just followed your link and read the comments from Jonas - makes perfect sense. I'll rewrite so that I only do the access to the processor time stamp counter in assembler.

BTW: Bugtracker - I wanted to raise a bug myself for missing mnemonics (ADCX, ADOX). Now I have two questions regarding this

1 - I can't seem to login. Neither under my existing account nor can I register a new one. Is there something special required - e.g. allowing Cookies?
2 - Is there a documentation on the usage of bugtracker avail? Before I register a new bug I'd like to search existing ones so that I do not duplicate and the search functionality looks pretty arcane to me.

Regards,
Jens

Navigation

[0] Message Index

[#] Next page

Go to full version