On Alpine Linux 3.18 (32-bit x86), the generated 'gzip' binary fails
at every invocation:
$ ./gzip < ../gzip.doc > gzip.doc.gz-t
Segmentation fault
$ ./gzip --help
Segmentation fault
The stack trace in gdb shows 5 frames in /lib/ld-musl-i386.so.1.
Configuring with
DEFS=-DNO_ASM
provides a workaround. This proves that the problem is with lib/match.c.
Find attached the output of "objdump -d -r lib.match.o". This object code
looks harmless to me, but apparently it trips some verification failure
inside musl libc.
The attached patch fixes it. Tested on Alpine Linux 3.18 (32-bit x86).
lib/match.o: file format elf32-i386
Disassembly of section .text:
00000000 <match_init>:
0: c3 ret
00000001 <longest_match>:
1: 55 push %ebp
2: 57 push %edi
3: 56 push %esi
4: 53 push %ebx
5: 8b 74 24 14 mov 0x14(%esp),%esi
9: 8b 2d 00 00 00 00 mov 0x0,%ebp
b: R_386_32 max_chain_length
f: 8b 3d 00 00 00 00 mov 0x0,%edi
11: R_386_32 strstart
15: 89 fa mov %edi,%edx
17: 81 ea fa 7e 00 00 sub $0x7efa,%edx
1d: 73 02 jae 21 <limit_ok>
1f: 29 d2 sub %edx,%edx
00000021 <limit_ok>:
21: 81 c7 02 00 00 00 add $0x2,%edi
23: R_386_32 window
27: 8b 1d 00 00 00 00 mov 0x0,%ebx
29: R_386_32 prev_length
2d: 66 8b 44 3b fd mov -0x3(%ebx,%edi,1),%ax
32: 66 8b 4f fe mov -0x2(%edi),%cx
36: 3b 1d 00 00 00 00 cmp 0x0,%ebx
38: R_386_32 good_match
3c: 72 24 jb 62 <do_scan>
3e: c1 ed 02 shr $0x2,%ebp
41: eb 1f jmp 62 <do_scan>
43: 90 nop
00000044 <long_loop>:
44: 66 8b 44 3b fd mov -0x3(%ebx,%edi,1),%ax
49: 66 8b 4f fe mov -0x2(%edi),%cx
0000004d <short_loop>:
4d: 81 e6 ff 7f 00 00 and $0x7fff,%esi
53: 66 8b b4 36 00 00 00 mov 0x0(%esi,%esi,1),%si
5a: 00
57: R_386_32 prev
5b: 39 d6 cmp %edx,%esi
5d: 76 53 jbe b2 <the_end>
5f: 4d dec %ebp
60: 74 50 je b2 <the_end>
00000062 <do_scan>:
62: 66 3b 84 33 ff ff ff cmp -0x1(%ebx,%esi,1),%ax
69: ff
66: R_386_32 window
6a: 75 e1 jne 4d <short_loop>
6c: 66 3b 8e 00 00 00 00 cmp 0x0(%esi),%cx
6f: R_386_32 window
73: 75 d8 jne 4d <short_loop>
75: 8d b6 02 00 00 00 lea 0x2(%esi),%esi
77: R_386_32 window
7b: 89 f8 mov %edi,%eax
7d: b9 80 00 00 00 mov $0x80,%ecx
82: f3 66 a7 repz cmpsw %es:(%edi),%ds:(%esi)
85: 74 32 je b9 <maxmatch>
00000087 <mismatch>:
87: 8a 4f fe mov -0x2(%edi),%cl
8a: 2a 4e fe sub -0x2(%esi),%cl
8d: 97 xchg %eax,%edi
8e: 29 f8 sub %edi,%eax
90: 29 c6 sub %eax,%esi
92: 81 ee 02 00 00 00 sub $0x2,%esi
94: R_386_32 window
98: 80 e9 01 sub $0x1,%cl
9b: 83 d0 00 adc $0x0,%eax
9e: 39 d8 cmp %ebx,%eax
a0: 7e a2 jle 44 <long_loop>
a2: 89 35 00 00 00 00 mov %esi,0x0
a4: R_386_32 match_start
a8: 89 c3 mov %eax,%ebx
aa: 3b 05 00 00 00 00 cmp 0x0,%eax
ac: R_386_32 nice_match
b0: 7c 92 jl 44 <long_loop>
000000b2 <the_end>:
b2: 89 d8 mov %ebx,%eax
b4: 5b pop %ebx
b5: 5e pop %esi
b6: 5f pop %edi
b7: 5d pop %ebp
b8: c3 ret
000000b9 <maxmatch>:
b9: a6 cmpsb %es:(%edi),%ds:(%esi)
ba: eb cb jmp 87 <mismatch>
>From c0c8dacb5b84b0d58f5432b58feda8d0ff1391f6 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Sat, 18 Apr 2026 15:53:55 +0200
Subject: [PATCH] build: Fix broken executable on 32-bit x86 systems with musl
libc
* configure.ac (gzip_cv_assembler): Set to no on musl libc.
---
configure.ac | 50 +++++++++++++++++++++++++++++---------------------
1 file changed, 29 insertions(+), 21 deletions(-)
diff --git a/configure.ac b/configure.ac
index f319346..f54042b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -249,27 +249,35 @@ AC_CACHE_CHECK([for an assembler syntax supported by this package],
[gzip_cv_assembler],
[gzip_cv_assembler=no
case $DEFS in
- *NO_ASM*) ;;
- *)
- if cp $srcdir/lib/match.c _match.S &&
- eval "$CPP $CPPFLAGS $ASCPPFLAGS _match.S > _match.i" &&
- eval "$ASCPPPOST < _match.i > match_.s"; then
- if test ! -s match_.s || grep error < match_.s > /dev/null; then
- :
- elif eval "$CC $CPPFLAGS $CFLAGS -c match_.s >/dev/null" &&
- test -f match_.$OBJEXT; then
- rm -f match_.$OBJEXT
- gzip_cv_assembler=yes
- if echo 'void foo (void) {}' > conftest.c &&
- eval "$CC $CPPFLAGS $CFLAGS -S conftest.c >/dev/null" &&
- grep '\.note\.GNU-stack' conftest.s >/dev/null &&
- eval "$CC $CPPFLAGS $CFLAGS -c -Wa,--noexecstack match_.s >/dev/null" &&
- test -f match_.$OBJEXT; then
- gzip_cv_assembler='yes, with -Wa,--noexecstack'
- fi
- fi
- fi
- rm -f conftest* _match.i _match.S match_.s match_.$OBJEXT;;
+ *NO_ASM*) ;;
+ *)
+ # Avoid a crash in musl libc's startup code.
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ case "$host_os" in
+ *-musl* | midipix*) ;;
+ *)
+ if cp $srcdir/lib/match.c _match.S &&
+ eval "$CPP $CPPFLAGS $ASCPPFLAGS _match.S > _match.i" &&
+ eval "$ASCPPPOST < _match.i > match_.s"; then
+ if test ! -s match_.s || grep error < match_.s > /dev/null; then
+ :
+ elif eval "$CC $CPPFLAGS $CFLAGS -c match_.s >/dev/null" &&
+ test -f match_.$OBJEXT; then
+ rm -f match_.$OBJEXT
+ gzip_cv_assembler=yes
+ if echo 'void foo (void) {}' > conftest.c &&
+ eval "$CC $CPPFLAGS $CFLAGS -S conftest.c >/dev/null" &&
+ grep '\.note\.GNU-stack' conftest.s >/dev/null &&
+ eval "$CC $CPPFLAGS $CFLAGS -c -Wa,--noexecstack match_.s >/dev/null" &&
+ test -f match_.$OBJEXT; then
+ gzip_cv_assembler='yes, with -Wa,--noexecstack'
+ fi
+ fi
+ fi
+ rm -f conftest* _match.i _match.S match_.s match_.$OBJEXT
+ ;;
+ esac
+ ;;
esac])
if test "$gzip_cv_assembler" != no; then
AC_DEFINE([ASMV], ,
--
2.52.0