Package: netdiag
Version: 1.0-8
User: [EMAIL PROTECTED]
Usertags: eabi

Hi!
   Since etch at least, netwatch has not worked on arm: it reports
lots of phantom accesses in the remote IP addresses composed of the
high-order bytes of the local IP address in the low-order bytes and 16
bytes of garbage in the high-order bytes. This turns out to be
entirely due to misaligned 32-bit memory accesses, which are easy to
detect ehre as I have /proc/cpu/alignment set to cause bus errors.
   The attached patches fix the two issues.
   One is not really netwatch's fault: GCC spots a 16-byte memcpy of
what looks to it from the type casts to be properly-aligned source and
target structures, and uses 4-byte register copies to do a 16-byte
copy - at runtime it turns out that one of the params is an array of
shorts, so the nonaligned accesses do the usual ARM thing of rotating
the words by (addr & 03) bytes. (Or giving bus error if you set ethe
system that way) The easy workaround is to compile that file without
using the builtin memcpy "optimisation".
   The other is the constructions of a 4-byte network-endian integer
in a 4-char array and then accessing it as a longword, fixed in the
source with __attribute__((aligned(32)))

   I dunno if the other programs in the suite have similar issues, but
this definitely affects and fixes netwatch on both arm and armel sid.
It also works on arm-etch.

Attached:
- screen dump of garbage output (the machines' own IP address is
88.96.6.156 and the network is quiet)
- patch -p1 file to ficx the two alignment issues in netwatch.

    M

<<attachment: netwatch-arm-alignment-bugs.png>>

--- netdiag-1.0-orig/netwatch-1.0c/Makefile	2008-10-08 18:33:22.000000000 +0100
+++ netdiag-1.0/netwatch-1.0c/Makefile	2008-10-08 18:31:42.000000000 +0100
@@ -35,6 +35,10 @@
 clean:
 	rm -f *~ *.o $(EXEC) config.h config.cache config.log config.status 
 
+# work round ARM GCC bug: builtin memcpy gets alignment wrong.
+netwatch.o: netwatch.c
+	$(CC) $(XCFLAGS) -c $(OLDLINUX) -fno-builtin-memcpy $<
+
 .c.o:
 	$(CC) $(XCFLAGS) -c $(OLDLINUX) $<
 
--- netdiag-1.0-orig/netwatch-1.0c/netwatch.c	2008-10-08 18:33:22.000000000 +0100
+++ netdiag-1.0/netwatch-1.0c/netwatch.c	2008-10-08 18:19:08.000000000 +0100
@@ -2483,7 +2483,7 @@
 int
    tlocal (u_int32_t * addr)
    {
-      static unsigned char lhost[] = {  127, 0, 0, 1  };
+      static unsigned char __attribute__((aligned(32))) lhost[] = {  127, 0, 0, 1  };
       u_int32_t *k = (u_int32_t *) netmask;
       u_int32_t reslocal, restest;
       if (*addr == *(u_int32_t *) lhost)

Reply via email to