Results 1 to 9 of 9

Thread: ASM includes broken in fpc 3.0.4 / x86_64

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #1

    ASM includes broken in fpc 3.0.4 / x86_64

    Wait. I'm now not sure it wasn't MY fault.
    x86_64 asm is a veritable minefield for someone who learned x86 asm during DOS times. So many instructions that compile, seem to work, but fail with addresses above 4Gb causing AVs or trashed memory.

    Will investigate in detail later.















    I will investigate it and fill a bug report later, got no time now.

    But the fact is, ASM includes are broken in this combination.
    Everything works fine for i686; the same ASM blocks work fine with fpc 2.6.4 so it's not my fault (probably).

    Example of code that silently trashes memory:

    Code:
    function GetExceptionState(): PMotherSehState;
    {
       Note: while it *can* allocate the block for a thread
       it knows nothing about, that is *not* a desired behavior.
    
       Thus, any thread better call this function beforehand,
       in the beginning of it's Execute method.
    
       There is Mother^.Core.AllocateThreadExceptionState for the module
    }
    var
      T: TThreadId;
    begin
      EnterCriticalsection(Mother^.SehCriticalSection);
      T:= GetCurrentThreadId();
      Result:= @Mother^.ExceptionState;
      while true do begin
        if Result^.ThreadId = T then begin
          LeaveCriticalsection(Mother^.SehCriticalSection);
          Exit;
        end;
        if not Assigned(Result^.Next) then begin
          VerboseLog('  Allocating exception state for thread ID=' + IntToHex(T, 8) + 'h...');
          Result^.Next:= new(PMotherSehState);
          Result:= Result^.Next;
          FillChar(Result^, SizeOf(Result^), 0);
          Result^.ThreadId:= T;
          Result^.events[High(Result^.events)].eType:= deke_Terminator;
        {$ifdef CPUX86_64}
           {$if (FPC_FULLVERSION>20604) and (FPC_FULLVERSION<39999)}
             {$fatal This #@$# trashes memory. Use FPC 2.6.4 instead.}
           {$endif}
          asm
            mov rsi, qword[Result]
            mov ax, ss
            mov word[rsi + TMotherSEHState.StackSegment], ax
          end['rax', 'rsi'];
        {$endif}
        {$ifdef CPU386}
          asm
            mov esi, dword[Result]
            mov ax, ss
            mov word[esi + TMotherSEHState.StackSegment], ax
          end['eax', 'esi'];
        {$endif}
    
          LeaveCriticalsection(Mother^.SehCriticalSection);
          Exit;
        end;
        Result:= Result^.Next;
      end;
    end;
    -- it seems to work, then following exception processing crashes with "exception state not found for thread <ID>". Commenting the ASM block out fixes that.

    where
    Code:
      PMother = ^TMother;
      TMother = maybepacked record
        Initialized,
        Safe: boolean;
        Validate: function(sizes: array of const): boolean; cdecl;
        Criticalsection,
        SehCriticalSection: TRTLCriticalSection;
        State: TMotherState_;
        Core: TMotherCore;
        ExceptionState
          : TMotherSehState; //contains a pointer-chain of states for other threads
        CPU: TMotherCPU;
        Timer: TMotherTimer;
        Config: TMotherConfig;
        AssetKeeper: TMotherAssetKeeper;
        Memory: TMotherMemory;
        Stream: TMotherStream_;
        Module: TMotherModule_;
        GAPI: TMotherGAPI;
        Sound: TMotherSound;
        Text: TMotherText;
        Display: TMotherDisplay;
        Image: TMotherImaging;
    	  Input: TMotherInput_;
        Gamepad: TMotherGamepad;
        PenTablet: TMotherPenTablet;
        {$ifdef cgekernel}
         LockupGuard: TLockupGuard;
        {$else}
         stub1: ptruint;
        {$endif}
        Debug: TMotherDebug;
        ReservedStub: array[0..10000] of ptruint;
      end;
    where
    Code:
      PMotherSehState = ^TMotherSEHState;
      TMotherSEHState = maybepacked record
        // see cge.ResetMotherErrorState() and cl_die.GetExceptionState()
    
        ThreadId: TThreadId;
    
        ExceptionCode, //true exception codes in Windows, not used in Linux (see cl_seh_hack.inc)
        ExceptionAddress: ptruint;
        StackFrameAddress: ptruint; //NOT used //used to restore rbp
    
        NowDying,
        DyingAfterTrueException, {if the exception handling chain was set off
           by a real exception like an AV and not by a controlled call to Die() }
        CallStackLogged,
        ModuleIsAlreadyProcessingUnhandledException,
        IsModuleThread, {The current thread is created by the module and should be
          processed differently}
        ThreadFinished
          : boolean;
    
        AbbrTitleForIndicator: ShortString3;
        StackSegment: Word;
        ThreadTitle: {$ifdef cgekernel} UnicodeString {$else} PUnicodeChar {$endif};
    
        AVMemoryAddress,
        AVMemoryOperation: ptruint; //0 - read, 1 - write, 8-Data Execution Prevention. See MSDN.
    
        //thread load details are stored here: I did not find a better place
        tlic: TThreadLoadKind;
        tlitsc: {$ifdef cpuarm} timeval {$else} qword {$endif};
        tli: array [TThreadLoadKind] of int64; //accumulates RDTSC cycles
    
        ReservedStub: array[0..3] of ptruint;
    
        Next: PMotherSehState;
    
        events: array[0..DyingEventsLimit] of TDyingEventRec; //approximately 60 kilobytes
      end;
    where

    Code:
    {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
      // arm on Raspberry Pi
      {$define maybepacked:=}
      {$packrecords 4}
    {$else}
      {$define maybepacked:=packed}
    {$endif}
    Last edited by Chebmaster; 07-09-2018 at 07:52 AM.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •