From: Willy Tarreau Date: Thu, 23 Apr 2020 15:08:02 +0000 (+0200) Subject: BUG/MINOR: tools: fix the i386 version of the div64_32 function X-Git-Tag: v2.2-dev7~194 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=09568fd54d2f091860cafa5173893445cd55c44c;p=thirdparty%2Fhaproxy.git BUG/MINOR: tools: fix the i386 version of the div64_32 function As reported in issue #596, the edx register isn't marked as clobbered in div64_32(), which could technically allow gcc to try to reuse it if it needed a copy of the 32 highest bits of the o1 register after the operation. Two attempts were tried, one using a dummy 32-bit local variable to store the intermediary edx and another one switching to "=A" and making result a long long. It turns out the former makes the resulting object code significantly dirtier while the latter makes it better and was kept. This is due to gcc's difficulties at working with register pairs mixing 32- and 64- bit values on i386. It was verified that no code change happened at all on x86_64, armv7, aarch64 nor mips32. In practice it's only used by the frequency counters so this bug cannot even be triggered but better fix it. This may be backported to stable branches though it will not fix any issue. --- diff --git a/include/common/standard.h b/include/common/standard.h index 80a1fc234d..81d6093166 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -838,10 +838,10 @@ static inline unsigned int mul32hi(unsigned int a, unsigned int b) */ static inline unsigned int div64_32(unsigned long long o1, unsigned int o2) { - unsigned int result; + unsigned long long result; #ifdef __i386__ asm("divl %2" - : "=a" (result) + : "=A" (result) : "A"(o1), "rm"(o2)); #else result = o1 / o2;