Recent

Author Topic: Alignment of strings in records different in linux-arm and linux-i386  (Read 1720 times)

wk

  • Newbie
  • Posts: 2
Hi,

I have some binary files of records saved with Delphi. It is possible to load them with fpc and {$ALIGN 4} on Win32 and Linux i386.
Unfortunately it is not possible with Linux on arm.
I assume the alignment of strings in records is somehow different.

I can reproduce this with a mimimal example:
Code: Pascal  [Select]
  1. {$ALIGN 4}
  2. program stringalignmenttest;
  3.  
  4. uses
  5.   sysutils;
  6.  
  7. type
  8.   tRecString = record
  9.     string1 : string [4];
  10.     string2 : string [16];
  11.     string3 : string [8];
  12.   end;
  13.  
  14.   tRecInt = record
  15.     int1 : shortint;
  16.     int2 : integer;
  17.     int3 : shortint;
  18.     int4 : shortint;
  19.     int5 : integer;
  20.   end;
  21.  
  22. var
  23.   recstring : tRecString;
  24.   recint :    tRecInt;
  25.   fstr :      file of tRecString;
  26.   fint :      file of TRecInt;
  27.   fname :     string;
  28.   alstring :  string;
  29.  
  30. begin
  31.   recint.int1       := 1;
  32.   recint.int2       := 2;
  33.   recint.int3       := 3;
  34.   recint.int4       := 4;
  35.   recint.int5       := 5;
  36.   recstring.string1 := 'ABCD';
  37.   recstring.string2 := 'ABCDEFGHIJKLMNOP';
  38.   recstring.string3 := 'ABCDEFGH';
  39.  
  40.   alstring := '-a4';
  41.   fname    := 'bindump';
  42.  
  43. {$IFDEF WIN32}
  44.   fname += '-win32';
  45. {$ENDIF}
  46.  
  47. {$IFDEF LINUX}
  48. {$IFDEF CPUARM}
  49.   fname += '-linuxarm';
  50. {$ENDIF}
  51. {$IFDEF CPU386}
  52.   fname += '-linuxi386';
  53. {$ENDIF}
  54. {$ENDIF}
  55.  
  56.  
  57.   assignFile(fint, fname + '-int' + alstring);
  58.   rewrite(fint);
  59.   Write(fint, recint);
  60.   closefile(fint);
  61.   writeln('sizeof recint: ' + IntToStr(sizeof(recint)));
  62.  
  63.   assignFile(fstr, fname + '-string' + alstring);
  64.   rewrite(fstr);
  65.   Write(fstr, recstring);
  66.   closefile(fstr);
  67.   writeln('sizeof recstring: ' + IntToStr(sizeof(recstring)));
  68.   writeln('sizeof recstring.string1: ' + IntToStr(sizeof(recstring.string1)));
  69.   writeln('sizeof recstring.string2: ' + IntToStr(sizeof(recstring.string2)));
  70.   writeln('sizeof recstring.string3: ' + IntToStr(sizeof(recstring.string3)));
  71.  
  72. end.
  73.  

Here are the results for arm and i386, both with 2 and 4-byte-alignment


The results for Linux on i386 and Win32 with 4-byte-alignment are:

program output:
Code: [Select]
$ ./stringalignmenttest
sizeof recint: 16
sizeof recstring: 31
sizeof recstring.string1: 5
sizeof recstring.string2: 17
sizeof recstring.string3: 9

hexdump of the generated files win32 and linux-i386 are the same:
Code: [Select]
bindump-linuxi386-int-a4
00000000  01 00 00 00 02 00 00 00  03 04 00 00 05 00 00 00  |................|
00000010

bindump-linuxi386-string-a4
00000000  04 41 42 43 44 10 41 42  43 44 45 46 47 48 49 4a  |.ABCD.ABCDEFGHIJ|
00000010  4b 4c 4d 4e 4f 50 08 41  42 43 44 45 46 47 48     |KLMNOP.ABCDEFGH|
0000001f


The results for Linux on arm with 4-byte-alignment are:

program output:
Code: [Select]
sizeof recint: 16
sizeof recstring: 34
sizeof recstring.string1: 5
sizeof recstring.string2: 17
sizeof recstring.string3: 9

hexdump of the generated files on linux-arm:
Code: [Select]
bindump-linuxarm-int-a4
00000000  01 00 00 00 02 00 00 00  03 04 00 00 05 00 00 00  |................|
00000010
bindump-linuxarm-string-a4
00000000  04 41 42 43 44 00 10 41  42 43 44 45 46 47 48 49  |.ABCD..ABCDEFGHI|
00000010  4a 4b 4c 4d 4e 4f 50 00  08 41 42 43 44 45 46 47  |JKLMNOP..ABCDEFG|
00000020  48 00                                             |H.|
00000022


The results for Linux on i386 with 2-byte-alignment are:

program output:
Code: [Select]
./stringalignmenttest
sizeof recint: 12
sizeof recstring: 31
sizeof recstring.string1: 5
sizeof recstring.string2: 17
sizeof recstring.string3: 9


hexdump of the generated files on linux-i386:
Code: [Select]
bindump-linuxi386-int-a2
00000000  01 00 02 00 00 00 03 04  05 00 00 00              |............|
0000000c
bindump-linuxi386-string-a2
00000000  04 41 42 43 44 10 41 42  43 44 45 46 47 48 49 4a  |.ABCD.ABCDEFGHIJ|
00000010  4b 4c 4d 4e 4f 50 08 41  42 43 44 45 46 47 48     |KLMNOP.ABCDEFGH|
0000001f


The results for Linux on arm with 2-byte-alignment are:

program output:
Code: [Select]
sizeof recint: 12
sizeof recstring: 34
sizeof recstring.string1: 5
sizeof recstring.string2: 17
sizeof recstring.string3: 9


hexdump of the generated files on linux-arm:
Code: [Select]
bindump-linuxarm-int-a2
00000000  01 00 02 00 00 00 03 04  05 00 00 00              |............|
0000000c
bindump-linuxarm-string-a2
00000000  04 41 42 43 44 00 10 41  42 43 44 45 46 47 48 49  |.ABCD..ABCDEFGHI|
00000010  4a 4b 4c 4d 4e 4f 50 00  08 41 42 43 44 45 46 47  |JKLMNOP..ABCDEFG|
00000020  48 00                                             |H.|
00000022


I am using fpc 3.0.0 and Lazarus 1.6.1 updated with fpcup on 2016-04-04. Binarys for linux are crosscompiled under Windows 8.1.



It seems that alignment for integers in records does work just as expected, both on i386 and arm.
It seems that strings align to 1 byte on i386 and to 2 bytes on arm, regardless of the compiler directive {$ALIGN}

Is it possible to get the same behavior on arm as on i386?
Is this a bug in fpc?

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 674
Re: Alignment of strings in records different in linux-arm and linux-i386
« Reply #1 on: April 08, 2016, 11:35:52 am »
Only records declared as "packed" are guaranteed to have the same layout across different platforms/architectures. Everything else takes into account the alignment requirements specified by the relevant ABIs (capped by the current {$align xxx} setting).

wk

  • Newbie
  • Posts: 2
Re: Alignment of strings in records different in linux-arm and linux-i386
« Reply #2 on: April 08, 2016, 12:03:39 pm »
Is it possible to overwrite the ABI alignment settings?
Where are these settings defined? I couldn't find a list.

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 674
Re: Alignment of strings in records different in linux-arm and linux-i386
« Reply #3 on: April 08, 2016, 01:11:11 pm »
Is it possible to overwrite the ABI alignment settings?
Quote
No.

Where are these settings defined? I couldn't find a list.
The ABIs are defined by processor manufacturers, OS providers and sometimes standards bodies. The ARM ABI used by current Linux distributions can be found at http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf . I can't readily find the documentation for the Win32 ABI, I guess it's part of the Visual Studio documentation.

Note that ABIs do not define alignments for things like shortstrings, since they are a Pascal-specific concept. How these are aligned is compiler/implementation-defined (currently they are aligned to 2 bytes on platforms that may produce a bus error when accessing a non-aligned 16 bit value, and to 1 byte elsewhere). There is really no way to get the same data layouts on different platforms unless you declare your records as packed. Memory representations of data structures are not portable in any way.