From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mout.gmx.net (mout.gmx.net [212.227.17.21]) by sourceware.org (Postfix) with ESMTPS id 32A733851C2F for ; Thu, 18 Feb 2021 02:39:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 32A733851C2F X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from skylla.schaltzentrale ([46.91.91.208]) by mail.gmx.net (mrgmx105 [212.227.17.168]) with ESMTPSA (Nemesis) id 1MgvrB-1lmRnz156T-00hMtW for ; Thu, 18 Feb 2021 03:39:06 +0100 Date: Thu, 18 Feb 2021 03:38:56 +0100 From: Alexander Miller To: elfutils-devel@sourceware.org Subject: [PATCH v2] Improve building with LTO Message-ID: <20210218033856.18053044.alex.miller@gmx.de> In-Reply-To: <20210214235718.7654b5f1.alex.miller@gmx.de> References: <20210214235718.7654b5f1.alex.miller@gmx.de> X-Mailer: Claws Mail 3.17.7 (GTK+ 2.24.32; x86_64-pc-linux-gnu) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Provags-ID: V03:K1:hH6veo7toSnFIdtbDAMW7P+DmmS0IAB+sQWyYV148l8+cm3oT5F mYgWr8PrqvEc7fPxcYOZvIDWV5a4X8/fO8xbsbz1rgGCGrulIMcUx7v3GCemqJnIaxPHd1i a5jsH28D8BEo2X8JE2Q+eP7SKSYsqDGYqZaR6Ylqf4yk5SLd4jETEgQ/Fsw9HKrpW77c34v T5tsvZLh7g2oTzXI5VZpA== X-UI-Out-Filterresults: notjunk:1;V03:K0:nxNg/X3WgVk=:KV7fZLpjGezEOEcIPkoIlc FZR/+BXLhv5Fo4Zz1voO/ZoMwvbYDTad1zNoBXDfFPxjuENMxR6sTMbx1EbH4hPOdxo8WsA1A oVNuIB2Cz1rRsA0oTw4nqkeDtVt9ZDYuWy8j7ACZdsAlgNsyVuIiGtZEUQ5dkLMb0eZglbua6 3g7kBDLguZqg+wXhU60uOXfdSHMhS8dxImKAdJcN0JoY1nOh7FqPYJu+a1/VEGe+UvL2lYlRl uak8V70yIf+EUPXmKcQKX+ct+4ha3c8gGGDKJCGPmi6ck2sZhcsJvyQz2Z/N61Vhpsq3x8InD JI2hXoj/+WFIqpCHixsj23fWzWtXH4uGhtaG8Xm20z3TRZ42teLybTX7OzlqaeqRnlDrNV7RV zLUxyyIrwvWWRMQv/mRa5Gfikgp8R6YpaFqCZUC5KM6fhAg1QSVhnjV1HOrWJS9g/jR8xWbRi JFZSxZf0EK2x80Ayr/SL2iO2jfeFJr3goF1EzFO2d/fdDhBBtCyQCg0eorm53DagLBXMXDysG dVbUZN+SzYPcGC0wHOJlK/1OsGH7oiW711jYtPvZmdXDFm2KCEC6kNUdWuUxbhCdTn1z6sPoC tDjyHu4s1KhvFl7XRujzvSOgjhWsPW7gjAfbwWEwZAYHBO0i701bkSL6gEjkITGftp6HG02UI Y1ftJLwAUk2a6AKvB4223xhiWFmvanYiwlYd3oSGzEmDmzhsFXB49KN3F3id7U4hs6y2d8T90 TjxADTHCfDsQBS4Cey3DBCDwdDC6sxkSym9RWUAljcMfLMJ1Msq18X9z6xpo7mZuuuMYltAjJ hpSrHQyc3DYYlIEEDtB4xAhdWpWEzG262C2764LsIEwD78FmGfn0FZoRSPT+DIEkMBLDTSB6m o7R1HordeNY/lPKexsgA== X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, FREEMAIL_FROM, GIT_PATCH_0, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Feb 2021 02:39:12 -0000 From: Alexander Miller Use symver attribute for symbol versioning instead of .symver assembler directive when available. Convert to use double @ syntax for default version in all cases (required when using the attribute). Add the attributes externally_visible, no_reorder if available when using assembler directives to improve the situation for < gcc-10. This is not 100% reliable, though; -flto-partition=3Dnone may still be needed in some cases. Note that -Wno-error=3Dstack-usage=3D is still needed to build with LTO. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=3D24498 Signed-off-by: Alexander Miller --- lib/ChangeLog | 13 +++++++ lib/eu-config.h | 65 +++++++++++++++++++++++++++------- libdw/ChangeLog | 11 ++++++ libdw/dwarf_aggregate_size.c | 4 +-- libdw/dwarf_arrayorder.c | 2 +- libdw/dwarf_bitoffset.c | 2 +- libdw/dwarf_bitsize.c | 2 +- libdw/dwarf_bytesize.c | 2 +- libdw/dwarf_decl_column.c | 2 +- libdw/dwarf_decl_file.c | 2 +- libdw/dwarf_decl_line.c | 2 +- libdw/dwarf_srclang.c | 4 +-- libdwelf/ChangeLog | 5 +++ libdwelf/dwelf_elf_begin.c | 2 +- libdwfl/ChangeLog | 7 ++++ libdwfl/core-file.c | 4 +-- libdwfl/dwfl_module_build_id.c | 4 +-- libdwfl/dwfl_report_elf.c | 4 +-- 18 files changed, 107 insertions(+), 30 deletions(-) diff --git a/lib/ChangeLog b/lib/ChangeLog index 371e213..1f4cd62 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,16 @@ +2021-02-14 Alexander Miller + + * eu-config.h (used_in_asm): New macro. + (NEW_INTDEF): New macro. + (NEW_VERSION): Mark symbol as used_in_asm. Use @@ symver and change + asm name instead. New variant using symver attribute if available. + (OLD_VERSION): Update new symbol name. Indent asm directives. New + variant using symver attribute. + (COMPAT_VERSION_NEWPROTO): Mark symbol as used_in_asm. Reorder + lines. Replace asm with __asm__ in declaration. New variant using + symver attribute. + (COMPAT_VERSION): Likewise. + 2021-02-05 Mark Wielaard =20 * printversion.c (print_version): Update copyright year. diff --git a/lib/eu-config.h b/lib/eu-config.h index f0e3d07..c7d7cbb 100644 --- a/lib/eu-config.h +++ b/lib/eu-config.h @@ -176,27 +176,68 @@ asm (".section predict_data, \"aw\"; .previous\n" /* This macro is used by the tests conditionalize for standalone building.= */ #define ELFUTILS_HEADER(name) =20 +/* Don't reorder with global asm blocks or optimize away. (Doesn't reliably + keep it in the same LTO partition, though; -flto-partition=3Dnone may be + still needed for some gcc versions < 10.) */ +#ifdef __has_attribute +# if __has_attribute(no_reorder) +# define used_in_asm __attribute__ ((externally_visible, no_reorder)) +# endif +#endif +#ifndef used_in_asm +# define used_in_asm /* empty */ +#endif =20 #ifdef SYMBOL_VERSIONING -# define OLD_VERSION(name, version) \ - asm (".globl _compat." #version "." #name "\n" \ - "_compat." #version "." #name " =3D " #name "\n" \ - ".symver _compat." #version "." #name "," #name "@" #version); -# define NEW_VERSION(name, version) \ - asm (".symver " #name "," #name "@@@" #version); -# define COMPAT_VERSION_NEWPROTO(name, version, prefix) \ - asm (".symver _compat." #version "." #name "," #name "@" #version); \ +# define NEW_INTDEF(name) __typeof (name) INTUSE(name) \ + __attribute__ ((alias ("_new." #name))) attribute_hidden; +# ifdef __has_attribute +# if __has_attribute(symver) +# define NEW_VERSION(name, version) \ + __typeof (name) name __asm__ ("_new." #name) \ + __attribute__ ((symver (#name "@@" #version))); +# define OLD_VERSION(name, version) _OLD_VERSION1(name, __COUNTER__, ver= sion) +# define _OLD_VERSION1(name, num, version) _OLD_VERSION2(name, num, vers= ion) +# define _OLD_VERSION2(name, num, version) \ + __typeof (name) _compat_old##num##_##name \ + __asm__ ("_compat." #version "." #name) \ + __attribute__ ((alias ("_new." #name), symver (#name "@" #version))); +# define COMPAT_VERSION_NEWPROTO(name, version, prefix) \ __typeof (_compat_##prefix##_##name) _compat_##prefix##_##name \ - asm ("_compat." #version "." #name); -# define COMPAT_VERSION(name, version, prefix) \ + __asm__ ("_compat." #version "." #name) \ + __attribute__ ((symver (#name "@" #version))); +# define COMPAT_VERSION(name, version, prefix) \ asm (".symver _compat." #version "." #name "," #name "@" #version); \ - __typeof (name) _compat_##prefix##_##name asm ("_compat." #version "." #= name); + __typeof (name) _compat_##prefix##_##name \ + __asm__ ("_compat." #version "." #name) \ + __attribute__ ((symver (#name "@" #version))); +# endif +# endif +# ifndef NEW_VERSION +# define OLD_VERSION(name, version) \ + asm (".globl _compat." #version "." #name "\n\t" \ + "_compat." #version "." #name " =3D _new." #name "\n\t" \ + ".symver _compat." #version "." #name "," #name "@" #version); +# define NEW_VERSION(name, version) \ + __typeof (name) name __asm__ ("_new." #name) used_in_asm; \ + asm (".symver _new." #name ", " #name "@@" #version); +# define COMPAT_VERSION_NEWPROTO(name, version, prefix) \ + __typeof (_compat_##prefix##_##name) _compat_##prefix##_##name \ + __asm__ ("_compat." #version "." #name) used_in_asm; \ + asm (".symver _compat." #version "." #name ", " #name "@" #version); +# define COMPAT_VERSION(name, version, prefix) \ + __typeof (name) _compat_##prefix##_##name \ + __asm__ ("_compat." #version "." #name) used_in_asm; \ + asm (".symver _compat." #version "." #name ", " #name "@" #version); +# endif #else +# define NEW_INTDEF(name) INTDEF(name) # define OLD_VERSION(name, version) /* Nothing for static linking. */ # define NEW_VERSION(name, version) /* Nothing for static linking. */ # define COMPAT_VERSION_NEWPROTO(name, version, prefix) \ error "should use #ifdef SYMBOL_VERSIONING" -# define COMPAT_VERSION(name, version, prefix) error "should use #ifdef SY= MBOL_VERSIONING" +# define COMPAT_VERSION(name, version, prefix) \ + error "should use #ifdef SYMBOL_VERSIONING" #endif =20 #ifndef FALLTHROUGH diff --git a/libdw/ChangeLog b/libdw/ChangeLog index b8038f0..597f54b 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,14 @@ +2021-02-14 Alexander Miller + + * dwarf_aggregate_size.c (dwarf_aggregate_size): Move NEW_VERSION + before definition. Replace INTDEF with NEW_INTDEF. + * dwarf_srclang.c (dwarf_srclang): Likewise. + * dwarf_arrayorder.c (dwarf_arrayorder): Move NEW_VERSION. + * dwarf_bitoffset.c (dwarf_bitoffset): Likewise. + * dwarf_bitsize.c (dwarf_bitsize): Likewise. + * dwarf_bytesize.c (dwarf_bytesize): Likewise. + * dwarf_decl_column.c (dwarf_decl_column): Likewise. + 2020-12-20 Dmitry V. Levin =20 * .gitignore: New file. diff --git a/libdw/dwarf_aggregate_size.c b/libdw/dwarf_aggregate_size.c index 75105e4..552f122 100644 --- a/libdw/dwarf_aggregate_size.c +++ b/libdw/dwarf_aggregate_size.c @@ -209,6 +209,7 @@ aggregate_size (Dwarf_Die *die, Dwarf_Word *size, return -1; } =20 +NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161) int dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size) { @@ -219,6 +220,5 @@ dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size) =20 return aggregate_size (&die_mem, size, &type_mem, 0); } -INTDEF (dwarf_aggregate_size) +NEW_INTDEF (dwarf_aggregate_size) OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144) -NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161) diff --git a/libdw/dwarf_arrayorder.c b/libdw/dwarf_arrayorder.c index da64f99..782e075 100644 --- a/libdw/dwarf_arrayorder.c +++ b/libdw/dwarf_arrayorder.c @@ -35,6 +35,7 @@ #include "libdwP.h" =20 =20 +NEW_VERSION (dwarf_arrayorder, ELFUTILS_0.143) int dwarf_arrayorder (Dwarf_Die *die) { @@ -46,4 +47,3 @@ dwarf_arrayorder (Dwarf_Die *die) &value) =3D=3D 0 ? (int) value : -1; } OLD_VERSION (dwarf_arrayorder, ELFUTILS_0.122) -NEW_VERSION (dwarf_arrayorder, ELFUTILS_0.143) diff --git a/libdw/dwarf_bitoffset.c b/libdw/dwarf_bitoffset.c index c1a3a34..61a0d59 100644 --- a/libdw/dwarf_bitoffset.c +++ b/libdw/dwarf_bitoffset.c @@ -35,6 +35,7 @@ #include "libdwP.h" =20 =20 +NEW_VERSION (dwarf_bitoffset, ELFUTILS_0.143) int dwarf_bitoffset (Dwarf_Die *die) { @@ -46,4 +47,3 @@ dwarf_bitoffset (Dwarf_Die *die) &value) =3D=3D 0 ? (int) value : -1; } OLD_VERSION (dwarf_bitoffset, ELFUTILS_0.122) -NEW_VERSION (dwarf_bitoffset, ELFUTILS_0.143) diff --git a/libdw/dwarf_bitsize.c b/libdw/dwarf_bitsize.c index 0ed9b71..35e8744 100644 --- a/libdw/dwarf_bitsize.c +++ b/libdw/dwarf_bitsize.c @@ -35,6 +35,7 @@ #include "libdwP.h" =20 =20 +NEW_VERSION (dwarf_bitsize, ELFUTILS_0.143) int dwarf_bitsize (Dwarf_Die *die) { @@ -46,4 +47,3 @@ dwarf_bitsize (Dwarf_Die *die) &value) =3D=3D 0 ? (int) value : -1; } OLD_VERSION (dwarf_bitsize, ELFUTILS_0.122) -NEW_VERSION (dwarf_bitsize, ELFUTILS_0.143) diff --git a/libdw/dwarf_bytesize.c b/libdw/dwarf_bytesize.c index 116cd32..6d1ff9a 100644 --- a/libdw/dwarf_bytesize.c +++ b/libdw/dwarf_bytesize.c @@ -35,6 +35,7 @@ #include "libdwP.h" =20 =20 +NEW_VERSION (dwarf_bytesize, ELFUTILS_0.143) int dwarf_bytesize (Dwarf_Die *die) { @@ -46,4 +47,3 @@ dwarf_bytesize (Dwarf_Die *die) &value) =3D=3D 0 ? (int) value : -1; } OLD_VERSION (dwarf_bytesize, ELFUTILS_0.122) -NEW_VERSION (dwarf_bytesize, ELFUTILS_0.143) diff --git a/libdw/dwarf_decl_column.c b/libdw/dwarf_decl_column.c index 08d36b8..3225fd1 100644 --- a/libdw/dwarf_decl_column.c +++ b/libdw/dwarf_decl_column.c @@ -35,10 +35,10 @@ #include "libdwP.h" =20 =20 +NEW_VERSION (dwarf_decl_column, ELFUTILS_0.143) int dwarf_decl_column (Dwarf_Die *decl, int *colp) { return __libdw_attr_intval (decl, colp, DW_AT_decl_column); } OLD_VERSION (dwarf_decl_column, ELFUTILS_0.122) -NEW_VERSION (dwarf_decl_column, ELFUTILS_0.143) diff --git a/libdw/dwarf_decl_file.c b/libdw/dwarf_decl_file.c index d4aa0a1..75662a3 100644 --- a/libdw/dwarf_decl_file.c +++ b/libdw/dwarf_decl_file.c @@ -36,6 +36,7 @@ #include "libdwP.h" =20 =20 +NEW_VERSION (dwarf_decl_file, ELFUTILS_0.143) const char * dwarf_decl_file (Dwarf_Die *die) { @@ -86,4 +87,3 @@ dwarf_decl_file (Dwarf_Die *die) return cu->files->info[idx].name; } OLD_VERSION (dwarf_decl_file, ELFUTILS_0.122) -NEW_VERSION (dwarf_decl_file, ELFUTILS_0.143) diff --git a/libdw/dwarf_decl_line.c b/libdw/dwarf_decl_line.c index 80fae6c..6b31eeb 100644 --- a/libdw/dwarf_decl_line.c +++ b/libdw/dwarf_decl_line.c @@ -37,13 +37,13 @@ #include "libdwP.h" =20 =20 +NEW_VERSION (dwarf_decl_line, ELFUTILS_0.143) int dwarf_decl_line (Dwarf_Die *func, int *linep) { return __libdw_attr_intval (func, linep, DW_AT_decl_line); } OLD_VERSION (dwarf_decl_line, ELFUTILS_0.122) -NEW_VERSION (dwarf_decl_line, ELFUTILS_0.143) =20 =20 int internal_function diff --git a/libdw/dwarf_srclang.c b/libdw/dwarf_srclang.c index f10e764..77bd58c 100644 --- a/libdw/dwarf_srclang.c +++ b/libdw/dwarf_srclang.c @@ -35,6 +35,7 @@ #include "libdwP.h" =20 =20 +NEW_VERSION (dwarf_srclang, ELFUTILS_0.143) int dwarf_srclang (Dwarf_Die *die) { @@ -45,6 +46,5 @@ dwarf_srclang (Dwarf_Die *die) (die, DW_AT_language, &attr_mem), &value) =3D=3D 0 ? (int) value : -1; } -INTDEF (dwarf_srclang) +NEW_INTDEF (dwarf_srclang) OLD_VERSION (dwarf_srclang, ELFUTILS_0.122) -NEW_VERSION (dwarf_srclang, ELFUTILS_0.143) diff --git a/libdwelf/ChangeLog b/libdwelf/ChangeLog index a0ff9f4..cbfe1ec 100644 --- a/libdwelf/ChangeLog +++ b/libdwelf/ChangeLog @@ -1,3 +1,8 @@ +2021-02-14 Alexander Miller + + * dwelf_elf_begin.c (dwelf_elf_begin): Move NEW_VERSION before + definition. + 2020-12-12 Dmitry V. Levin =20 * libdwelf.h: Fix spelling typos in comments. diff --git a/libdwelf/dwelf_elf_begin.c b/libdwelf/dwelf_elf_begin.c index c7d63a1..c3cfe63 100644 --- a/libdwelf/dwelf_elf_begin.c +++ b/libdwelf/dwelf_elf_begin.c @@ -36,6 +36,7 @@ =20 #include =20 +NEW_VERSION (dwelf_elf_begin, ELFUTILS_0.177) Elf * dwelf_elf_begin (int fd) { @@ -61,4 +62,3 @@ dwelf_elf_begin (int fd) return NULL; } OLD_VERSION (dwelf_elf_begin, ELFUTILS_0.175) -NEW_VERSION (dwelf_elf_begin, ELFUTILS_0.177) diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index d107e78..c96c716 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,10 @@ +2021-02-14 Alexander Miller + + * core-file.c (dwfl_core_file_report): Move NEW_VERSION before + definition. Replace INTDEF with NEW_INTDEF. + * dwfl_module_build_id.c (dwfl_module_build_id): Likewise. + * dwfl_report_elf.c (dwfl_report_elf): Likewise. + 2021-02-01 =C3=89rico Nogueira =20 * dwfl_error.c (strerror_r): Only use the GNU version when available. diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c index a0ccc9b..4e4c9b3 100644 --- a/libdwfl/core-file.c +++ b/libdwfl/core-file.c @@ -440,6 +440,7 @@ __libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddr= p) return false; } =20 +NEW_VERSION (dwfl_core_file_report, ELFUTILS_0.158) int dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable) { @@ -625,8 +626,7 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char= *executable) error rather than just nothing found. */ return listed > 0 ? listed : retval; } -INTDEF (dwfl_core_file_report) -NEW_VERSION (dwfl_core_file_report, ELFUTILS_0.158) +NEW_INTDEF (dwfl_core_file_report) =20 #ifdef SYMBOL_VERSIONING int _compat_without_executable_dwfl_core_file_report (Dwfl *dwfl, Elf *elf= ); diff --git a/libdwfl/dwfl_module_build_id.c b/libdwfl/dwfl_module_build_id.c index 6ca9376..0c198f2 100644 --- a/libdwfl/dwfl_module_build_id.c +++ b/libdwfl/dwfl_module_build_id.c @@ -77,6 +77,7 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf = *elf) return found_build_id (mod, set, build_id_bits, build_id_len, build_id_v= addr); } =20 +NEW_VERSION (dwfl_module_build_id, ELFUTILS_0.138) int dwfl_module_build_id (Dwfl_Module *mod, const unsigned char **bits, GElf_Addr *vaddr) @@ -102,8 +103,7 @@ dwfl_module_build_id (Dwfl_Module *mod, *vaddr =3D mod->build_id_vaddr; return mod->build_id_len; } -INTDEF (dwfl_module_build_id) -NEW_VERSION (dwfl_module_build_id, ELFUTILS_0.138) +NEW_INTDEF (dwfl_module_build_id) =20 #ifdef SYMBOL_VERSIONING COMPAT_VERSION (dwfl_module_build_id, ELFUTILS_0.130, vaddr_at_end) diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c index 9da8669..a5f0e5e 100644 --- a/libdwfl/dwfl_report_elf.c +++ b/libdwfl/dwfl_report_elf.c @@ -287,6 +287,7 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, con= st char *file_name, return m; } =20 +NEW_VERSION (dwfl_report_elf, ELFUTILS_0.156) Dwfl_Module * dwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name, int = fd, GElf_Addr base, bool add_p_vaddr) @@ -322,8 +323,7 @@ dwfl_report_elf (Dwfl *dwfl, const char *name, const ch= ar *file_name, int fd, =20 return mod; } -INTDEF (dwfl_report_elf) -NEW_VERSION (dwfl_report_elf, ELFUTILS_0.156) +NEW_INTDEF (dwfl_report_elf) =20 #ifdef SYMBOL_VERSIONING Dwfl_Module * --=20 2.26.2