HarfBuzz masinéria

Négy készüléken installáltam sikeresen a harfbuzz-8.3 nevű terméket, elégedett is voltam (fordítás után alig háromszor annyi lemezhelyet foglal, mint a php-8.3, szóval semmiképp sem bloat), de aztán botor fejjel egy újabb masinával is megpróbálkoztam. Természetesen nem megy, végtelen ciklusban gyönyörködhetem. (A jó hír az, hogy ez C++, header-fájlban implementált végtelen mélységű templétekkel, tehát gdb-vel debuggolni alig lehet.)

TL;DR a '/usr/bin/as' nem jó, a "bss_" section illesztési követelményét az első elemhez állítja, nem pedig az összes maximumát veszi. Néhány gépen az érintettség (bos.adt.base verzióval):

11,12: 6.1.9.0 nem tesztelhető, mert a gcc-5.4-ben van workaround
12: 7.2.5.0 nem tesztelhető, mert a gcc-8.3-ben van workaround (külön bss_3_ szakaszt generál)
62: 5.3.12.4 nem tesztelhető, mert a gcc-4.8.2-ben van workaround (kiegészíti a bss_ hosszát 16-tal oszthatóra)
x: 6.1.9.101 jelentkezik a hiba, mert a gcc-4.8.3-ban egy workaround sincs meg

Ez a rész tűnik érintettnek (hb-machinery.hh):

    212   Stored * get_stored () const
    213   {
    214   retry:
    215     Stored *p = this->instance.get_acquire ();
    216     if (unlikely (!p))
    217     {
    218 fprintf(stderr, "%s:%s:%d this=%p p=%p\n", __FILE__, __func__, __LINE__, (void *)this, (void *)p);
    219       if (unlikely (this->is_inert ()))
    220         return const_cast (Funcs::get_null ());
    221
    222       p = this->template call_create ();
    223       if (unlikely (!p))
    224         p = const_cast (Funcs::get_null ());
    225
    226       if (unlikely (!cmpexch (nullptr, p)))
    227       {
    228 fprintf(stderr, "%s:%s:%d this=%p p=%p\n", __FILE__, __func__, __LINE__, (void *)this, (void *)p);
    229         do_destroy (p);
    230         goto retry;
    231       }
    232     }
    233     return p;
    234   }

Kimenete:

$ hb-info /usr/local/share/fonts/MsTrueType/arial.ttf 2>&1 | head
hb-machinery.hh:get_stored:218 this=11002bf08 p=0
hb-machinery.hh:get_stored:218 this=9001000a1696874 p=0
hb-machinery.hh:get_stored:228 this=9001000a1696874 p=11002c730
hb-machinery.hh:get_stored:218 this=9001000a1696874 p=0
hb-machinery.hh:get_stored:228 this=9001000a1696874 p=11002c730
hb-machinery.hh:get_stored:218 this=9001000a1696874 p=0

Hozzászólások

Szerkesztve: 2024. 02. 09., p – 10:07

Az cmpexch a this->instance.cmpexch-t jelenti:


    240   bool cmpexch (Stored *current, Stored *value) const
    241   {
    242     /* This function can only be safely called directly if no
    243      * other thread is accessing. */
    244     return this->instance.cmpexch (current, value);
    245   }

ahol az instance:

    276   private:
    277   /* Must only have one pointer. */
    278   hb_atomic_ptr_t instance;

A do_destroy könnyen érthető (mármint, ha tudnánk, mi a 'Funcs'):


    199   static void do_destroy (Stored *p)
    200   {
    201     if (p && p != const_cast (Funcs::get_null ()))
    202       Funcs::destroy (p);
    203   }
Szerkesztve: 2024. 02. 09., p – 18:12

Esetleg releváns: (hb-atomic.hh)

    200 template <typename P>
    201 struct hb_atomic_ptr_t
    202 {
    203   typedef hb_remove_pointer<P> T;
    204
    205   hb_atomic_ptr_t () = default;
    206   constexpr hb_atomic_ptr_t (T* v) : v (v) {}
    207   hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
    208
    209   void init (T* v_ = nullptr) { set_relaxed (v_); }
    210   void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
    211   T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
    212   T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
    213   bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *
    214
    215   T * operator -> () const                    { return get_acquire (); }
    216   template <typename C> operator C * () const { return get_acquire (); }
    217
    218   T *v = nullptr;
    219 };

Valamint:

     68 static inline bool
     69 _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
     70 {
     71   const void *O = O_; // Need lvalue
     72   return __atomic_compare_exchange_n ((void **) P, (void **) &O, (void *) N,
          true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
     73 }

Szerkesztve: 2024. 02. 09., p – 16:55

További debugkiírások:

hb-machinery.hh:get_stored:217 this=11002bec8 this->instance=0
hb-machinery.hh:get_stored:219 this=11002bec8 this->instance=0 p=0
hb-machinery.hh:get_stored:221 this=11002bec8 this->instance=0 p=0
hb-machinery.hh:get_data:154 this=11002bec8 WheresData=1 retval=11002be70
hb-machinery.hh:get_data:154 this=11002bec8 WheresData=1 retval=11002be70
hb-machinery.hh:get_stored:228 after 'call_create': this=11002bec8 this->instance=0 p=11002c110
hb-machinery.hh:get_stored:235 before 'cmpexch' this=11002bec8 this->instance=0 p=11002c110
hb-machinery.hh:get_stored:217 this=9001000a181761c this->instance=0
hb-machinery.hh:get_stored:219 this=9001000a181761c this->instance=0 p=0
hb-machinery.hh:get_stored:221 this=9001000a181761c this->instance=0 p=0
hb-machinery.hh:get_stored:228 after 'call_create': this=9001000a181761c this->instance=0 p=11002c6f0
hb-machinery.hh:get_stored:235 before 'cmpexch' this=9001000a181761c this->instance=0 p=11002c6f0

A szamitastechnika olyan bugyraiba merulsz, ahol meg senki sem jart.

Vadász, vadász te sz*pni jársz ide. Legalabb megfizetik ?

Szerkesztve: 2024. 02. 10., szo – 17:36

Reggeli gondolat, apróság, de meg kellene nézni: mi a furcsa ezen a címen:

this=9001000a1696874

Kieg:

hb-machinery.hh:hb_lazy_loader_t:187 this=9001000a15817e8 reta=9000000172ba25c
hb-machinery.hh:hb_lazy_loader_t:187 this=9001000a15817f0 reta=9000000172bb024
hb-machinery.hh:hb_lazy_loader_t:187 this=9001000a15817a0 reta=9000000172afca0
hb-machinery.hh:hb_lazy_loader_t:187 this=9001000a1580f80 reta=900000016d9fa90
hb-machinery.hh:hb_lazy_loader_t:187 this=9001000a158145c reta=90000001725f4b4
hb-machinery.hh:hb_lazy_loader_t:187 this=9001000a158171c reta=9000000172abb98
hb-machinery.hh:hb_lazy_loader_t:187 this=9001000a1581594 reta=90000001728c7c4
hb-machinery.hh:hb_lazy_loader_t:187 this=9001000a158159c reta=90000001728d470

Itt a konstruktorban van a debugkiírás, és az a kérdés, hogy milyen new/malloc/stb bírt unaligned címet előállítani (gyk: 64-bites architektúrán vagyunk, 64-bites align lenne a nyerő).

hb-machinery.hh:hb_lazy_loader_t:187 this=9001000a160445c reta=900000017e4f4b4
[Switching to Thread 1]

Thread 2 hit Breakpoint 2, 0x0900000017e4f4b4 in hb_shapers_lazy_loader_t::hb_shapers_lazy_loader_t() ()
   from /usr/local/lib64/libharfbuzz.so.0

(gdb) bt
#0  0x0900000017e4f4b4 in hb_shapers_lazy_loader_t::hb_shapers_lazy_loader_t (
    this=0x9001000a160445c <_hbshaper.bss_+64>) at hb-shaper.cc:43
#1  0x0900000017e4ff40 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535)
    at hb-shaper.cc:310
#2  0x0900000017e4ffc0 in _GLOBAL__sub_I_hb_shaper.cc () at hb-shaper.cc:102
#3  0x0900000017e5001c in global constructors keyed to 65535_0_hb_shaper.cc_B739A763_0xae11c40733b643 ()
    at hb-shaper.cc:102
#4  0x0900000017ebede0 in _GLOBAL__FI_libharfbuzz_so () from /usr/local/lib64/libharfbuzz.so.0
#5  0x09fffffff00027e8 in mod_init1 () from /usr/ccs/bin/usla64
#6  0x09fffffff00039e8 in usl_init_mods () from /usr/ccs/bin/usla64
#7  0x09fffffff0003870 in usl_exec_init_mods () from /usr/ccs/bin/usla64
#8  0x0000000100000294 in __start ()
Szerkesztve: 2024. 02. 11., v – 05:18

Most úgy tűnik, hogy nem valamilyen allokátortól jön az unaligned address, hanem globális változó:

hb-common.cc:lang_find_or_insert:316 &langs=9001000a180fbac

(gdb) info symbol 0x9001000a180fbac
_hbcommon.bss_ + 64 in section .bss of /usr/local/lib64/libharfbuzz.so.0

(gdb) print (void *)&'_hbcommon.bss_'
$6 = (void *) 0x9001000a180fb6c <_hbcommon.bss_>

(gdb) info files
        0x09001000a180f7c8 - 0x09001000a18103e0 is .bss in /usr/local/lib64/libharfbuzz.so.0

(gdb) print/x (long)&'_hbcommon.bss_' - 0x09001000a180f7c8
$8 = 0x3a4
(gdb) print 0x09001000a18103e0 - (long)&'_hbcommon.bss_'
$9 = 2164

map-file:


020081AF4 00000039  2 BS CM S89041 <_hbset.bss_>            hb-set.cc(.libs/libharfbuzz_la-hb-set.o)
020081B30 0000003C  2 BS CM S89042 <_hbotcolor.bss_>        hb-ot-color.cc(.libs/libharfbuzz_la-hb-ot-color.o)
020081B6C 00000050  2 BS CM S89043 <_hbcommon.bss_>         hb-common.cc(.libs/libharfbuzz_la-hb-common.o)
020081BBC 00000040  2 BS CM S89044 <_hbottag.bss_>          hb-ot-tag.cc(.libs/libharfbuzz_la-hb-ot-tag.o)
020081BFC 0000003C  2 BS CM S89045 <_hbotmetrics.bss_>      hb-ot-metrics.cc(.libs/libharfbuzz_la-hb-ot-metrics

Na most már csak az a kérdés, ki felejtett el align-olni?

Szerk: ez a rész például még jó (gcc -S), azt jelzi hogy magát a 'lang' mezőt 2^3=8 byte-ra kellene illeszteni:

        .lcomm _ZL5langs,8,_hbcommon.bss_,3

dump szerint:

                         Section Header for .bss
PHYaddr      VTRaddr     SCTsiz      RAWptr      RELptr
0x000204c0  0x000204c0  0x00000040  0x00000000  0x00000000
Szerkesztve: 2024. 02. 11., v – 06:42

Lehet, hogy most kellene ismerni az obj-file bináris formátumát. Esetleg ez a fickó sugallhat valamit: https://sourceware.org/bugzilla/show_bug.cgi?id=18671

struct internal_scnhdr
{
  char s_name[SCNNMLEN] ATTRIBUTE_NONSTRING;    /* section name */

  /* Physical address, aliased s_nlib.
     In the pei format, this field is the virtual section size
     (the size of the section after being loaded int memory),
     NOT the physical address.  */
  bfd_vma s_paddr;

  bfd_vma s_vaddr;              /* virtual address              */
  bfd_vma s_size;               /* section size                 */
  bfd_vma s_scnptr;             /* file ptr to raw data for section */
  bfd_vma s_relptr;             /* file ptr to relocation       */
  bfd_vma s_lnnoptr;            /* file ptr to line numbers     */
  unsigned long s_nreloc;       /* number of relocation entries */
  unsigned long s_nlnno;        /* number of line number entries*/
  long s_flags;                 /* flags                        */
  unsigned char s_page;         /* TI COFF load page            */
};
/* s_flags "type".  */
#define STYP_REG         (0x0000)       /* "regular": allocated, relocated, loaded */
#define STYP_DSECT       (0x0001)       /* "dummy":  relocated only*/
#define STYP_NOLOAD      (0x0002)       /* "noload": allocated, relocated, not loaded */
#define STYP_GROUP       (0x0004)       /* "grouped": formed of input sections */
#define STYP_PAD         (0x0008)       /* "padding": not allocated, not relocated, loaded */
#define STYP_COPY        (0x0010)       /* "copy": for decision function used by field update;  not allocated,
                                                                             loaded; reloc & lineno entries pro
#define STYP_TEXT        (0x0020)       /* section contains text only */
#define S_SHRSEG         (0x0020)       /* In 3b Update files (output of ogen), sections which appear in SHARED
                                                                             will have the S_SHRSEG flag set by
                                                                             update all process invocations. */
#define STYP_DATA        (0x0040)       /* section contains data only */
#define STYP_BSS         (0x0080)       /* section contains bss only */
#define S_NEWFCN         (0x0100)       /* In a minimal file or an update file, a new function (as compared wit
#define STYP_INFO        (0x0200)       /* comment: not allocated not relocated, not loaded */
#define STYP_OVER        (0x0400)       /* overlay: relocated not allocated or loaded */
#define STYP_LIB         (0x0800)       /* for .lib: same as INFO */
#define STYP_MERGE       (0x2000)       /* merge section -- combines with text, data or bss sections only */
#define STYP_REVERSE_PAD (0x4000)       /* section will be padded with no-op instructions
                                           wherever padding is necessary and there is a
                                           word of contiguous bytes beginning on a word
                                           boundary. */

#define STYP_LIT        0x8020  /* Literal data (like STYP_TEXT) */
$ dd bs=1 skip=24 count=72 if=src/libharfbuzz_subset_la-hb-subset-cff-common.o 2>/dev/null |xd
       0: 2e 74 65 78  74 00 00 00  00 00 00 00  00 00 00 00  .text...........
      10: 00 00 00 00  00 00 00 00  00 00 00 00  00 01 ce c0  ..............▒▒
      20: 00 00 00 00  00 00 01 38  00 00 00 00  00 35 bf b0  .......8.....5▒▒
      30: 00 00 00 00  00 36 30 74  00 00 03 85  00 00 0b 49  .....60t.......I
      40: 00 00 00 20  00 00 00 00                            ... ....

$ dd bs=1 skip=96 count=72 if=src/libharfbuzz_subset_la-hb-subset-cff-common.o 2>/dev/null | xd
       0: 2e 64 61 74  61 00 00 00  00 00 00 00  00 01 ce c0  .data.........▒▒
      10: 00 00 00 00  00 01 ce c0  00 00 00 00  00 00 36 00  ......▒▒......6.
      20: 00 00 00 00  00 01 cf f8  00 00 00 00  00 35 f0 f6  ......▒▒.....5▒▒
      30: 00 00 00 00  00 00 00 00  00 00 04 89  00 00 00 00  ................
      40: 00 00 00 40  00 00 00 00                            ...@....

$ dd bs=1 skip=168 count=72 if=src/libharfbuzz_subset_la-hb-subset-cff-common.o 2>/dev/null | xd
       0: 2e 62 73 73  00 00 00 00  00 00 00 00  00 02 04 c0  .bss...........▒
      10: 00 00 00 00  00 02 04 c0  00 00 00 00  00 00 00 40  .......▒.......@
      20= 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ................
      40: 00 00 00 80  00 00 00 00                            ........
Szerkesztve: 2024. 02. 11., v – 07:12

62-es gépen mapfile (gcc-4.8.2)

000000001031CA30 00003E08  2 PR SD S13572 <.text>                  hb-common.cc(.libs/libharfbuzz_la-hb-common.
000000001094D6D0 00000194  4 RO SD S58366 <_hbcommon.rw_>          hb-common.cc(.libs/libharfbuzz_la-hb-common.
00000000200186E0 00000010  4 RW SD S58476 <.data>                  hb-common.cc(.libs/libharfbuzz_la-hb-common.
0000000020080ED8 000003B0  2 BS CM S87176 <_hbcommon.bss_>         hb-common.cc(.libs/libharfbuzz_la-hb-com

x gépen mapfile (gcc-4.8.3)

0000000010629B38 00003EA0  2 PR SD S24987 <.text>                  hb-common.cc(.libs/libharfbuzz_la-hb-common.
00000000109619D0 0000024D  4 RO SD S59045 <_hbcommon.rw_>          hb-common.cc(.libs/libharfbuzz_la-hb-common.
0000000020018180 00000010  4 RW SD S59143 <.data>                  hb-common.cc(.libs/libharfbuzz_la-hb-common.
0000000020081B6C 00000050  2 BS CM S89043 <_hbcommon.bss_>         hb-common.cc(.libs/libharfbuzz_la-hb-common.

11-es gépen mapfile (gcc-5.4.0)

00000100C1EF4 000035CC  2 PR SD S3986 <.text>                   hb-common.cc(.libs/libharfbuzz_la-hb-common.o)
0000010655170 0000018B  4 RO SD S58063 <_hbcommon.rw_>          hb-common.cc(.libs/libharfbuzz_la-hb-common.o)
0000020018610 00000010  4 RW SD S58169 <.data>                  hb-common.cc(.libs/libharfbuzz_la-hb-common.o)
000002007E638 00000010  3 BS CM S86120 <_hbcommon.bss_3_>       hb-common.cc(.libs/libharfbuzz_la-hb-common.o)
000002007E648 000000E1  2 BS CM S86121 <_hbcommon.bss_>         hb-common.cc(.libs/libharfbuzz_la-hb-common.o)

Sikerült shared library nélkül reprodukálni a gondot: ez a `ld` verzió általában 4-byte határra igazítja a 'bss'-eket.

(gdb) print &'_test0.bss_'
$2 = ( *) 0x110001138 <_test0.bss_>

(gdb) print &'_test2.bss_'
$1 = ( *) 0x11000113c <_test2.bss_>

futása:

$ ./mainstatic
main:     &main_int16=110001570
test0rut: &test0_int32=110001138
test2rut: &test2_int32=11000113c
test2rut: &test2_int64=110001144

en csak a php-8.3 osszehasonlitast nem ertem

Jó, ez egy speciális eset, a logfile-ok voltak nagyocskák, nem volt igazságos az összehasonlítás. A nettó source összehasonlítása:


termék          fájlok méret(du)
harfbuzz-8.3.0   3619  110720
php-8.3.2       22682  181200

Másik kérdés, hogy miért nagyok a logfile-ok. Ilyenek vannak benne (mármint Aixon):

ld: 0711-768 WARNING: Object .libs/libharfbuzz_la-hb-ot-layout.o, section 1,
function .OT::Layout::GPOS::is_blocklisted(hb_blob_t*, hb_face_t*) const:
        The branch at address 0x122860 is not followed by a recognized no-op
        or TOC-reload instruction. The unrecognized instruction is 0x7C691B78.

Nyilván ezt is ki lehetne nyomozni, ha végtelen sok időm lenne hobbizni, de egyelőre beérem azzal, hogy működik.

A gcc-4.8.3 által generált Assembly-t [amiben nincs workaround] különböző gépeken fordítva teszteltem, hogy az 'as' minden verzióban mutatja a hibát érdekes működést.