Recent

Author Topic: Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64  (Read 1254 times)

440bx

  • Sr. Member
  • ****
  • Posts: 387
Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64
« on: October 06, 2018, 03:03:16 am »
Hello,

When using the "windows" unit definition of IMAGE_TLS_DIRECTORY64, the value obtained for the Characteristics field is incorrect.

The reason why isn't quite clear as the definition in struct.inc seems correct but, the offset used to access the Characteristic field is definitely incorrect (the offset used in the assembly code is off by 4.)

Below is a short example that reproduces the problem.
Code: Pascal  [Select]
  1. {$MODE OBJFPC                        }
  2.  
  3. {$MODESWITCH     ADVANCEDRECORDS     }
  4. {$MODESWITCH     TYPEHELPERS         }
  5. {$MODESWITCH     ALLOWINLINE         }
  6. {$MODESWITCH     RESULT              }
  7. {$MODESWITCH     PROPERTIES          }
  8.  
  9. {$MODESWITCH     ANSISTRINGS-        }
  10. {$MODESWITCH     AUTODEREF-          }
  11. {$MODESWITCH     UNICODESTRINGS-     }
  12. {$MODESWITCH     POINTERTOPROCVAR-   }
  13.  
  14. {$LONGSTRINGS    OFF                 }
  15. {$WRITEABLECONST ON                  }
  16. {$TYPEDADDRESS   ON                  }
  17.  
  18.  
  19. //{$define useinternaldefinition}
  20.  
  21. // -----------------------------------------------------------------------------
  22. // NOTE: compile the program as a 64bit windows executable.
  23. // -----------------------------------------------------------------------------
  24.  
  25. program TlsDirectoryRecordLayout;
  26.  
  27.  
  28. uses
  29.   windows,
  30.   sysutils
  31.   ;
  32.  
  33. {$ifdef useinternaldefinition}
  34.  
  35. // other than formatting, this definition seems equivalent to the one found in
  36. // struct.inc.  However, when using this definition the result is correct.
  37. // when using the defintion from the windows unit, the result is incorrect.
  38.  
  39. type
  40.   _IMAGE_TLS_DIRECTORY64 = record
  41.      StartAddressOfRawData   : ULONGLONG;
  42.      EndAddressOfRawData     : ULONGLONG;
  43.      AddressOfIndex          : ULONGLONG;           { PDWORD }
  44.      AddressOfCallBacks      : ULONGLONG;           { PIMAGE_TLS_CALLBACK *; }
  45.      SizeOfZeroFill          : DWORD;
  46.  
  47.      case longint of
  48.        0 : (
  49.              Characteristics : DWORD
  50.            );
  51.        1 : (
  52.              CharacteristicsFields : bitpacked record
  53.                 Reserved0 : 0..$FFFFF;  // 5 nibbles=20 bits
  54.                 Alignment : 0..$F;      // 4 bits
  55.                 Reserved1 : 0..$FF;     // 8 bits
  56.              end
  57.            );
  58.   end;
  59.  
  60.   TIMAGE_TLS_DIRECTORY64 =  _IMAGE_TLS_DIRECTORY64;
  61.   PIMAGE_TLS_DIRECTORY64 = ^TIMAGE_TLS_DIRECTORY64;
  62.  
  63.  
  64.  
  65.   _IMAGE_TLS_DIRECTORY32 = record
  66.      StartAddressOfRawData   : DWORD;
  67.      EndAddressOfRawData     : DWORD;
  68.      AddressOfIndex          : DWORD;               { PDWORD }
  69.      AddressOfCallBacks      : DWORD;               { PIMAGE_TLS_CALLBACK * }
  70.      SizeOfZeroFill          : DWORD;
  71.  
  72.      case longint of
  73.        0 : (
  74.              Characteristics : DWORD
  75.            );
  76.        1 : (
  77.              CharacteristicsFields : bitpacked  record
  78.                 Reserved0 : 0..$FFFFF;  // 5 nibbles=20 bits
  79.                 Alignment : 0..$F;      // 4 bits
  80.                 Reserved1 : 0..$FF;     // 8 bits
  81.              end
  82.            );
  83.  
  84.     end;
  85.   TIMAGE_TLS_DIRECTORY32 =  _IMAGE_TLS_DIRECTORY32;
  86.   PIMAGE_TLS_DIRECTORY32 = ^TIMAGE_TLS_DIRECTORY32;
  87. {$endif}
  88.  
  89. type
  90.   // layout of a TLS directory entry in a PE file
  91.  
  92.   TLS_DATA = packed record
  93.     f1 : qword;
  94.     f2 : qword;
  95.     f3 : qword;
  96.     f4 : qword;
  97.  
  98.     f5 : DWORD;
  99.     f6 : DWORD;
  100.   end;
  101.  
  102. const
  103.   // TLS directory values as they would appear in a 64bit PE file
  104.  
  105.   // clang.exe and MS link.exe, among others, are examples of executables that
  106.   // specify TLS alignment.
  107.  
  108.   TlsData : TLS_DATA =
  109.   (
  110.     f1 : $100041000;  // qwords
  111.     f2 : $100041212;
  112.     f3 : $10003b70C;
  113.     f4 : $10002e778;
  114.  
  115.     f5 : $0;          // DWORD - sizeof zero fill
  116.     f6 : $00300000;   // DWORD - 4 byte align
  117.   );
  118.  
  119.  
  120. function LoadTls(Tls : PIMAGE_TLS_DIRECTORY64) : boolean;
  121. var
  122.   TlsArray : array[0..5] of qword;
  123.  
  124. begin
  125.   TlsArray[0] := Tls^.StartAddressOfRawData;
  126.   TlsArray[1] := Tls^.EndAddressOfRawData;
  127.   TlsArray[2] := Tls^.AddressOfIndex;
  128.   TlsArray[3] := Tls^.AddressOfCallbacks;
  129.   TlsArray[4] := Tls^.SizeOfZeroFill;
  130.  
  131.   // when using the structure definition present in stuct.inc, the offset to
  132.   // the characteristics field is incorrect, it points 4 bytes past the field.
  133.  
  134.   TlsArray[5] := Tls^.Characteristics;
  135.  
  136.   writeln(IntToHex(TlsArray[0], 10));
  137.   writeln(IntToHex(TlsArray[1], 10));
  138.   writeln(IntToHex(TlsArray[2], 10));
  139.   writeln(IntToHex(TlsArray[3], 10));
  140.   writeln(IntToHex(TlsArray[4], 10));
  141.  
  142.   writeln;
  143.   writeln('The value below should NOT be zero (0) - s/b : 0000300000');
  144.   writeln;
  145.  
  146.   writeln(IntToHex(TlsArray[5], 10));
  147.  
  148.   result := true;
  149. end;
  150.  
  151. begin
  152.   LoadTls(PIMAGE_TLS_DIRECTORY64(@TlsData));
  153.  
  154.   writeln;
  155.   writeln('press any key to end this program');
  156.  
  157.   readln;
  158. end.
  159.  

Uncomment the define "useinternaldefinition" to observe the difference in the Characteristics.

The first impression is that the definition of IMAGE_TLS_DIRECTORY64 in the Windows unit is incorrect but, it does look right.

Thaddy

  • Hero Member
  • *****
  • Posts: 7182
Re: Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64
« Reply #1 on: October 06, 2018, 07:39:56 am »
My first impression is that somewhere the packsettings play an issue:
natural alignment will probably be a qword alignment causing an off by four for the variant case. (as opposed to 32 bit)
Try {$packrecords c} or a reverse definition of the variant part (bitpacked part first)
Also turn optimizations off to test if the compiler maybe did record field re-ordering (unlikely, but a possible optimization)
« Last Edit: October 06, 2018, 07:43:00 am by Thaddy »
inline variables like in D10.3 are a bit like Brexit: if you are given the wrong information it sounds like a good idea. Every kid loves candy, but it makes you fat and your teeth will disappear.

ASerge

  • Hero Member
  • *****
  • Posts: 998
Re: Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64
« Reply #2 on: October 06, 2018, 08:57:28 am »
Code: Pascal  [Select]
  1. {$APPTYPE CONSOLE}
  2.  
  3. uses Windows;
  4.  
  5. type // Copied from struct.inc
  6.   _IMAGE_TLS_DIRECTORY64 =  record
  7.       StartAddressOfRawData : ULONGLONG;
  8.       EndAddressOfRawData : ULONGLONG;
  9.       AddressOfIndex : ULONGLONG;               { PDWORD }
  10.       AddressOfCallBacks : ULONGLONG;           { PIMAGE_TLS_CALLBACK *; }
  11.       SizeOfZeroFill : DWORD;
  12.           case longint of
  13.             0 : ( Characteristics : DWORD );
  14.             1 : ( CharacteristicsFields:  bitpacked record
  15.                                   Reserved0 : 0..$FFFFF; // 5 nibbles=20 bits
  16.                                   Alignment : 0..$F;      // 4 bits
  17.                                   Reserved1 : 0..$FF;     // 8 bits
  18.               end );
  19.     end;
  20.  
  21. begin
  22.   Writeln(SizeOf(_IMAGE_TLS_DIRECTORY64));
  23.   Writeln(SizeOf(Windows._IMAGE_TLS_DIRECTORY64));
  24.   Readln;
  25. end.

In fpc 3.0.4 40 and 48, in fpc 3.3.1 40 and 40.

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 6617
Re: Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64
« Reply #3 on: October 06, 2018, 12:56:34 pm »
It should be 40, I did a printf with visual studio.

IIRC some image structs had 8 byte packing and some not, and there was a bugreport about it, and it got reviewed.

440bx

  • Sr. Member
  • ****
  • Posts: 387
Re: Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64
« Reply #4 on: October 06, 2018, 03:18:16 pm »
It should be 40, I did a printf with visual studio.

IIRC some image structs had 8 byte packing and some not, and there was a bugreport about it, and it got reviewed.
I got so focused on the problem this was causing that I forgot to mention it is with FPC 3.0.4 (release) under Win 7, 64 bit.

ETA:

reported it as a bug: 0034395
« Last Edit: October 06, 2018, 04:02:15 pm by 440bx »

engkin

  • Hero Member
  • *****
  • Posts: 2128
Re: Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64
« Reply #5 on: October 06, 2018, 06:33:59 pm »
...
In fpc 3.0.4 40 and 48,
in fpc 3.3.1 40 and 40.

440bx

  • Sr. Member
  • ****
  • Posts: 387
Re: Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64
« Reply #6 on: October 06, 2018, 07:37:33 pm »
Are problems of this kind "back fixed" or updating to the latest version the only alternative ?

Cyrax

  • Hero Member
  • *****
  • Posts: 624
Re: Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64
« Reply #7 on: October 06, 2018, 07:43:59 pm »
Are problems of this kind "back fixed" or updating to the latest version the only alternative ?

Yes, updating to latest is the only way. There will be stable release of 3.2.0 in the future, where this should be fixed.
« Last Edit: October 06, 2018, 07:48:36 pm by Cyrax »

440bx

  • Sr. Member
  • ****
  • Posts: 387
Re: Possibly incorrect definiton of IMAGE_TLS_DIRECTORY64
« Reply #8 on: October 06, 2018, 08:40:52 pm »
Are problems of this kind "back fixed" or updating to the latest version the only alternative ?

Yes, updating to latest is the only way. There will be stable release of 3.2.0 in the future, where this should be fixed.
Thank you.  I'll wait for the stable release, in the meantime, I'll just work around it.