linux-ppc64-26-20050403
authorSven Oehme <oehmes@de.ibm.com>
Sun, 3 Apr 2005 20:02:28 +0000 (20:02 +0000)
committerDerrick Brashear <shadow@dementia.org>
Sun, 3 Apr 2005 20:02:28 +0000 (20:02 +0000)
FIXES 18114

add support for ppc64 linux26

acinclude.m4
src/afs/LINUX/osi_flush.s [new file with mode: 0644]
src/afs/LINUX/osi_probe.c
src/afs/LINUX/osi_syscall.c
src/cf/linux-test3.m4
src/cf/osconf.m4
src/libafs/Makefile.common.in
src/libafs/MakefileProto.LINUX.in
src/libafs/make_kbuild_makefile.pl

index 0a57fd9..5aac398 100644 (file)
@@ -455,7 +455,7 @@ else
                        AFS_SYSNAME="ia64_linuxXX"
                        ;;
                powerpc-*-linux*)
-                       AFS_SYSNAME="ppc_linuxXX"
+                       AFS_SYSNAME="`/bin/arch`_linuxXX"
                        ;;
                powerpc64-*-linux*)
                        AFS_SYSNAME="ppc64_linuxXX"
diff --git a/src/afs/LINUX/osi_flush.s b/src/afs/LINUX/osi_flush.s
new file mode 100644 (file)
index 0000000..925b874
--- /dev/null
@@ -0,0 +1,41 @@
+/* Taken from linux-2.6/arch/ppc64/boot/string.S 
+ *
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ * 
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ *
+ * Flush the dcache and invalidate the icache for a range of addresses.
+ *
+ * flush_cache(addr, len)
+ */
+       .section        ".text"
+       .align          2
+       .globl          flush_cache
+       .section        ".opd","aw"
+       .align          3
+flush_cache:
+       .quad           .flush_cache,.TOC.@tocbase,0
+       .previous
+       .size           flush_cache,24
+       .globl          .flush_cache
+.flush_cache:
+        addi    4,4,0x1f        /* len = (len + 0x1f) / 0x20 */
+        rlwinm. 4,4,27,5,31
+        mtctr   4
+        beqlr
+1:      dcbf    0,3
+        icbi    0,3
+        addi    3,3,0x20
+        bdnz    1b
+        sync
+        isync
+        blr
+       .long           0
+       .byte           0,12,0,0,0,0,0,0
+       .type           .flush_cache,@function
+       .size           .flush_cache,.-.flush_cache
index e948866..3f3256f 100644 (file)
 #include <linux/unistd.h>
 #include <linux/mm.h>
 
+#if defined(AFS_PPC64_LINUX26_ENV)
+#include <asm/abs_addr.h>
+#endif
+
 #ifdef AFS_AMD64_LINUX20_ENV
 #include <asm/ia32_unistd.h>
 #endif
@@ -78,6 +82,8 @@
 /* lower bound of valid kernel text pointers */
 #ifdef AFS_IA64_LINUX20_ENV
 #define ktxt_lower_bound (((unsigned long)&kernel_thread )  & 0xfff00000L)
+#elif defined(AFS_PPC64_LINUX20_ENV)
+#define ktxt_lower_bound (KERNELBASE)
 #else
 #define ktxt_lower_bound (((unsigned long)&kernel_thread )  & ~0xfffffL)
 #endif
@@ -188,6 +194,7 @@ extern SYSCALLTYPE ia32_sys_call_table[] __attribute__((weak));
 extern SYSCALLTYPE sys_call_table32[] __attribute__((weak));
 extern SYSCALLTYPE sys_call_table_emu[] __attribute__((weak));
 
+extern asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) __attribute__((weak));
 extern asmlinkage long sys_close(unsigned int) __attribute__((weak));
 extern asmlinkage long sys_chdir(const char *) __attribute__((weak));
 extern asmlinkage ssize_t sys_write(unsigned int, const char *, size_t) __attribute__((weak));
@@ -480,6 +487,10 @@ static probectl main_probe = {
     (unsigned long)(&tasklist_lock) - 0x30000,
     0,
     0x6000,
+#elif defined(AFS_PPC64_LINUX26_ENV)
+    (unsigned long)(&do_signal),
+    0xfff,
+    0x400,
 #elif defined(AFS_PPC_LINUX20_ENV) || defined(AFS_PPC_LINUX20_ENV)
     (unsigned long)&init_mm,
     0xffff,
@@ -617,6 +628,10 @@ static probectl *probe_list[] = {
 
 /********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
 #elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
+struct fptr {
+    void *ip;
+    unsigned long gp;
+};
 
 /* 
  * syscall pairs/triplets to probe
@@ -692,6 +707,10 @@ static probectl sct32_probe = {
     (unsigned long)(&sys_close),
     0xfffff,
     0x10000,
+#elif defined(AFS_PPC64_LINUX26_ENV)
+    (unsigned long)(&do_signal),
+    0xfff,
+    0x400,
 #else
     (unsigned long)&init_mm,
     0,
@@ -859,7 +878,7 @@ static int check_table(probectl *P, PROBETYPE *ptr)
     return -1;
 }
 
-static void *try(probectl *P, tryctl *T, PROBETYPE *ptr,
+static void *try(probectl *P, tryctl *T, PROBETYPE *aptr,
                 unsigned long datalen)
 {
 #ifdef OSI_PROBE_KALLSYMS
@@ -870,8 +889,9 @@ static void *try(probectl *P, tryctl *T, PROBETYPE *ptr,
 #endif
     unsigned long offset, ip1, ip2, ip3;
     int ret;
+    PROBETYPE *ptr;
 
-#ifdef AFS_IA64_LINUX20_ENV
+#if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
     ip1 = T->fn1 ? (unsigned long)((struct fptr *)T->fn1)->ip : 0;
     ip2 = T->fn2 ? (unsigned long)((struct fptr *)T->fn2)->ip : 0;
     ip3 = T->fn3 ? (unsigned long)((struct fptr *)T->fn3)->ip : 0;
@@ -890,11 +910,19 @@ static void *try(probectl *P, tryctl *T, PROBETYPE *ptr,
     if (!ip1 || !ip2 || (T->NR3 >= 0 && !ip3))
        return 0;
 
-    for (offset = 0; offset < datalen; offset++, ptr++) {
+    for (offset = 0; offset < datalen; offset++, aptr++) {
+#if defined(AFS_PPC64_LINUX20_ENV)
+       ptr = (PROBETYPE*)(*aptr);
+       if ((unsigned long)ptr <= KERNELBASE) {
+               continue;
+       }
+#else
+       ptr = aptr;
+#endif
        ret = check_table(P, ptr);
        if (ret >= 0) {
            /* return value is number of entries to skip */
-           ptr    += ret;
+           aptr    += ret;
            offset += ret;
            continue;
        }
@@ -957,7 +985,7 @@ static int check_harder(probectl *P, PROBETYPE *p)
        }
     }
 
-#ifdef AFS_IA64_LINUX20_ENV
+#if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
     ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0;
 #else
     ip1 = (unsigned long)(P->verify_fn);
index e10e9a6..6fad884 100644 (file)
@@ -36,6 +36,9 @@ RCSID
 #include <linux/sched.h>
 #endif
 
+#ifndef NR_syscalls
+#define NR_syscalls 222
+#endif
 
 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
  * even though pointers are 64 bit quantities.
@@ -96,12 +99,30 @@ asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
 
 
 /***** PPC64 *****/
-#ifdef AFS_PPC64_LINUX20_ENV
-extern SYSCALLTYPE *afs_sys_call_table32;
+#ifdef AFS_PPC64_LINUX26_ENV
+static SYSCALLTYPE *afs_sys_call_table32;
 static SYSCALLTYPE afs_ni_syscall32 = 0;
+static SYSCALLTYPE old_sys_setgroupsp = 0;
+static SYSCALLTYPE old_sys32_setgroupsp = 0;
 
 extern int afs32_xsetgroups();
 asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
+
+asmlinkage long sys_close(unsigned int fd);
+static void sys_setgroups_stub() 
+       __attribute__ ((pure,const,no_instrument_function));
+static void sys_setgroups_stub() 
+{ 
+       printf("*** error! sys_setgroups_stub called\n");
+}
+
+static void sys32_setgroups_stub() 
+       __attribute__ ((pure,const,no_instrument_function));
+static void sys32_setgroups_stub() 
+{ 
+       printf("*** error! sys32_setgroups_stub called\n");
+}
+
 #endif /* AFS_AMD64_LINUX20_ENV */
 
 
@@ -213,6 +234,127 @@ struct fptr {
 
 #endif /* AFS_IA64_LINUX20_ENV */
 
+/***** PPC64 ***** 
+ * Spring 2005
+ * sys_call_table hook for PPC64 
+ * by Soewono Effendi <Soewono.Effendi@sysgo.de>
+ * for IBM Deutschland
+ * Thanks go to SYSGO's team for their support:
+ * Horst Birthelmer <Horst.Birthelmer@sysgo.de>
+ * Marius Groeger <Marius.Groeger@sysgo.de>
+ */
+#if defined(AFS_PPC64_LINUX26_ENV)
+extern void flush_cache(void *, unsigned long);
+#define PPC_LO(v) ((v) & 0xffff)
+#define PPC_HI(v) (((v) >> 16) & 0xffff)
+#define PPC_HA(v) PPC_HI ((v) + 0x8000)
+#define PPC_HLO(v) ((short)(((v) >> 32) & 0xffff))
+#define PPC_HHI(v) ((short)(((v) >> 48) & 0xffff))
+
+struct ppc64_opd
+{
+       unsigned long funcaddr;
+       unsigned long r2;
+};
+
+struct ppc64_stub
+{
+       unsigned char jump[136];
+       unsigned long r2;
+       unsigned long lr;
+       struct ppc64_opd opd;
+} __attribute__ ((packed));
+
+/* a stub to fix up r2 (TOC ptr) and to jump to our sys_call hook
+   function.  We patch the new r2 value and function pointer into 
+   the stub. */
+#define PPC64_STUB(stub) \
+static struct ppc64_stub stub = \
+{ .jump = { \
+        0xf8, 0x41, 0x00, 0x28, /*     std     r2,40(r1) */ \
+        0xfb, 0xc1, 0xff, 0xf0, /*     std     r30,-16(r1) */ \
+        0xfb, 0xa1, 0xff, 0xe8, /*     std     r29,-24(r1) */ \
+        0x7c, 0x5d, 0x13, 0x78, /*     mr      r29,r2 */ \
+        0x3c, 0x40, 0x12, 0x34, /*16:  lis     r2,4660 */ \
+        0x60, 0x42, 0x56, 0x78, /*20:  ori     r2,r2,22136 */ \
+        0x78, 0x42, 0x07, 0xc6, /*     rldicr  r2,r2,32,31 */ \
+        0x64, 0x42, 0x90, 0xab, /*28:  oris    r2,r2,37035 */ \
+        0x60, 0x42, 0xcd, 0xef, /*32:  ori     r2,r2,52719 */ \
+        0x3f, 0xc2, 0x00, 0x00, /*36:  addis   r30,r2,0 */ \
+        0x3b, 0xde, 0x00, 0x00, /*40:  addi    r30,r30,0 */ \
+        0xfb, 0xbe, 0x00, 0x88, /*     std     r29,136(r30) */ \
+        0x7f, 0xa8, 0x02, 0xa6, /*     mflr    r29 */ \
+        0xfb, 0xbe, 0x00, 0x90, /*     std     r29,144(r30) */ \
+        0xeb, 0xde, 0x00, 0x98, /*     ld      r30,152(r30) */ \
+        0x7f, 0xc8, 0x03, 0xa6, /*     mtlr    r30 */ \
+        0xeb, 0xa1, 0xff, 0xe8, /*     ld      r29,-24(r1) */ \
+        0xeb, 0xc1, 0xff, 0xf0, /*     ld      r30,-16(r1) */ \
+        0x4e, 0x80, 0x00, 0x21, /*     blrl */ \
+        0x3c, 0x40, 0x12, 0x34, /*76:  lis     r2,4660 */ \
+        0x60, 0x42, 0x56, 0x78, /*80:  ori     r2,r2,22136 */ \
+        0x78, 0x42, 0x07, 0xc6, /*     rldicr  r2,r2,32,31 */ \
+        0x64, 0x42, 0x90, 0xab, /*88:  oris    r2,r2,37035 */ \
+        0x60, 0x42, 0xcd, 0xef, /*92:  ori     r2,r2,52719 */ \
+        0xfb, 0xc1, 0xff, 0xf0, /*     std     r30,-16(r1) */ \
+        0xfb, 0xa1, 0xff, 0xe8, /*     std     r29,-24(r1) */ \
+        0x3f, 0xc2, 0xab, 0xcd, /*104: addis   r30,r2,-21555 */ \
+        0x3b, 0xde, 0x78, 0x90, /*108: addi    r30,r30,30864 */ \
+        0xeb, 0xbe, 0x00, 0x90, /*     ld      r29,144(r30) */ \
+        0x7f, 0xa8, 0x03, 0xa6, /*     mtlr    r29 */ \
+        0xe8, 0x5e, 0x00, 0x88, /*     ld      r2,136(r30) */ \
+        0xeb, 0xa1, 0xff, 0xe8, /*     ld      r29,-24(r1) */ \
+        0xeb, 0xc1, 0xff, 0xf0, /*     ld      r30,-16(r1) */ \
+        0x4e, 0x80, 0x00, 0x20  /*     blr */ \
+}} 
+
+static void * create_stub(struct ppc64_stub *stub,
+                          struct ppc64_opd *opd)
+{
+       unsigned short *p1, *p2, *p3, *p4;
+       unsigned long addr;
+
+       stub->opd.funcaddr = opd->funcaddr;
+       stub->opd.r2 = opd->r2;
+       addr = (unsigned long) opd->r2;
+       p1 = (unsigned short*) &stub->jump[18];
+       p2 = (unsigned short*) &stub->jump[22];
+       p3 = (unsigned short*) &stub->jump[30];
+       p4 = (unsigned short*) &stub->jump[34];
+
+       *p1 = PPC_HHI(addr);
+       *p2 = PPC_HLO(addr);
+       *p3 = PPC_HI(addr);
+       *p4 = PPC_LO(addr);
+
+       addr = (unsigned long) stub - opd->r2;
+       p1 = (unsigned short*) &stub->jump[38];
+       p2 = (unsigned short*) &stub->jump[42];
+       *p1 = PPC_HA(addr);
+       *p2 = PPC_LO(addr);
+       p1 = (unsigned short*) &stub->jump[106];
+       p2 = (unsigned short*) &stub->jump[110];
+       *p1 = PPC_HA(addr);
+       *p2 = PPC_LO(addr);
+
+       addr = (unsigned long) opd->r2;
+       p1 = (unsigned short*) &stub->jump[78];
+       p2 = (unsigned short*) &stub->jump[82];
+       p3 = (unsigned short*) &stub->jump[90];
+       p4 = (unsigned short*) &stub->jump[94];
+
+       *p1 = PPC_HHI(addr);
+       *p2 = PPC_HLO(addr);
+       *p3 = PPC_HI(addr);
+       *p4 = PPC_LO(addr);
+
+        flush_cache((void *)stub, sizeof(*stub));
+        return ((void*)(stub));
+}
+
+PPC64_STUB(afs_sys_call_stub);
+PPC64_STUB(afs_xsetgroups_stub);
+PPC64_STUB(afs_xsetgroups32_stub);
+#endif /* AFS_PPC64_LINUX26_ENV */
 
 
 /**********************************************************************/
@@ -264,7 +406,51 @@ int osi_syscall_init(void)
     /* XXX no 32-bit syscalls on IA64? */
 
 
-/***** COMMON (except IA64) *****/
+#elif defined(AFS_PPC64_LINUX26_ENV)
+
+    afs_sys_call_table = osi_find_syscall_table(0);
+    if (afs_sys_call_table) {
+       SYSCALLTYPE p;
+       struct ppc64_opd* opd = (struct ppc64_opd*) sys_close;
+       unsigned long r2 = opd->r2;
+       opd = (struct ppc64_opd*) afs_syscall;
+       afs_sys_call_table32 = (unsigned long)afs_sys_call_table - 
+               NR_syscalls * sizeof(SYSCALLTYPE);
+       /* check we aren't already loaded */
+       p = SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)];
+       if ((unsigned long)p == opd->funcaddr) {
+           printf("AFS syscall entry point already in use!\n");
+           return -EBUSY;
+       }
+       /* setup AFS entry point */
+       p = create_stub(&afs_sys_call_stub, opd);
+       afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
+       afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL p;
+
+       /* setup setgroups */
+       opd = (struct ppc64_opd*) afs_xsetgroups;
+       p = create_stub(&afs_xsetgroups_stub, opd);
+       old_sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
+       afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL p;
+       opd = (struct ppc64_opd*) sys_setgroups_stub;
+       opd->funcaddr = old_sys_setgroupsp;
+       opd->r2 = r2;
+
+       /* setup setgroups32 */
+       opd = (struct ppc64_opd*) afs32_xsetgroups;
+       p = create_stub(&afs_xsetgroups32_stub, opd);
+       old_sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[_S(__NR_setgroups)];
+       afs_sys_call_table32[_S(__NR_setgroups)] = POINTER2SYSCALL p;
+       opd = (struct ppc64_opd*) sys32_setgroups_stub;
+       opd->funcaddr = old_sys32_setgroupsp;
+       opd->r2 = r2;
+
+        flush_cache((void *)afs_sys_call_table, 2*NR_syscalls*sizeof(void*));
+
+       sys_setgroupsp = sys_setgroups_stub;
+       sys32_setgroupsp = sys32_setgroups_stub;
+    }
+/***** COMMON (except IA64 or PPC64) *****/
 #else /* !AFS_IA64_LINUX20_ENV */
 
     afs_sys_call_table = osi_find_syscall_table(0);
@@ -324,12 +510,6 @@ int osi_syscall_init(void)
 #endif /* AFS_AMD64_LINUX20_ENV */
 
 
-/***** PPC64 *****/
-#ifdef AFS_PPC64_LINUX20_ENV
-    /* XXX no 32-bit syscalls on PPC64? */
-#endif
-
-
 /***** SPARC64 *****/
 #ifdef AFS_SPARC64_LINUX20_ENV
     afs_sys_call_table32 = osi_find_syscall_table(1);
@@ -371,6 +551,12 @@ void osi_syscall_clean(void)
 #if defined(AFS_IA64_LINUX20_ENV)
        afs_sys_call_table[_S(__NR_setgroups)] =
            POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
+#elif defined(AFS_PPC64_LINUX26_ENV)
+       afs_sys_call_table[_S(__NR_setgroups)] =
+           POINTER2SYSCALL old_sys_setgroupsp;
+       /* put back setgroups32 for PPC64 */
+       afs_sys_call_table32[__NR_setgroups] =
+           POINTER2SYSCALL old_sys32_setgroupsp;
 #else /* AFS_IA64_LINUX20_ENV */
        afs_sys_call_table[_S(__NR_setgroups)] =
            POINTER2SYSCALL sys_setgroupsp;
@@ -409,12 +595,6 @@ void osi_syscall_clean(void)
 #endif
 
 
-/***** PPC64 *****/
-#ifdef AFS_PPC64_LINUX20_ENV
-    /* XXX no 32-bit syscalls on PPC64? */
-#endif
-
-
 /***** SPARC64 *****/
 #ifdef AFS_SPARC64_LINUX20_ENV
     if (afs_sys_call_table32) {
index f8c2151..f64c5ef 100644 (file)
@@ -116,7 +116,7 @@ CPPFLAGS="$save_CPPFLAGS"])
 AC_DEFUN([LINUX_KERNEL_PAGE_FOLLOW_LINK],[
 AC_MSG_CHECKING(for page_follow_link_light vs page_follow_link)
 save_CPPFLAGS="$CPPFLAGS"
-CPPFLAGS="-I${LINUX_KERNEL_PATH}/include -Werror-implicit-function-declaration -D__KERNEL__ $CPPFLAGS"
+CPPFLAGS="-I${LINUX_KERNEL_PATH}/include -I${LINUX_KERNEL_PATH}/include/asm/mach-default -Werror-implicit-function-declaration -D__KERNEL__ $CPPFLAGS"
 AC_CACHE_VAL(ac_cv_linux_kernel_page_follow_link,
 [
 AC_TRY_COMPILE(
index d1c9300..b8a94bd 100644 (file)
@@ -262,8 +262,9 @@ case $AFS_SYSNAME in
                MT_LIBS="-lpthread"
                PAM_CFLAGS="-g -O2 -Dlinux -DLINUX_PAM -fPIC"
                SHLIB_LDFLAGS="-shared -Xlinker -x"
+               SHLIB_CFLAGS="-fPIC"
                TXLIBS="-lncurses"
-               XCFLAGS="-g -O2 -D_LARGEFILE64_SOURCE"
+               XCFLAGS="-g -O2 -D_LARGEFILE64_SOURCE -fPIC"
                YACC="bison -y"
                SHLIB_LINKER="${MT_CC} -shared"
                ;;
index 9ee7e74..c9e5dff 100644 (file)
@@ -393,6 +393,8 @@ osi_syscall.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_syscall.c
        $(CRULE_NOOPT)
 osi_sysctl.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_sysctl.c
        $(CRULE_NOOPT)
+osi_flush.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_flush.s
+       $(CRULE_OPT)
 osi_alloc.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_alloc.c
        $(CRULE_NOOPT)
 osi_cred.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_cred.c
index 9f54b63..d23769c 100644 (file)
@@ -24,6 +24,9 @@ AFS_OS_OBJS = \
        osi_sysctl.o \
        osi_vfsops.o \
        osi_vm.o \
+<ppc64_linux26>
+       osi_flush.o \
+<all>
        osi_vnodeops.o 
 
 AFS_OS_NFSOBJS =
@@ -82,7 +85,7 @@ CCFLAGS = $(COMMON_KERN_CFLAGS) \
       -mcpu=ultrasparc -m64 -mno-fpu -mcmodel=medlow -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
 DEFINES = $(COMMON_DEFINES) -DCPU=sparc64
 
-<ppc_linux22 ppc_linux24 ppc64_linux24>
+<ppc_linux22 ppc_linux24 ppc64_linux24 ppc64_linux26>
 CCFLAGS = $(COMMON_KERN_CFLAGS) -fsigned-char -msoft-float -fno-builtin -ffixed-r2
 DEFINES = $(COMMON_DEFINES) -D__powerpc__
 
index 03584cc..ce046e1 100755 (executable)
@@ -51,6 +51,9 @@ foreach $mf (@Makefiles) {
     elsif ($text =~ /^(\S+\.o):\s*(\S+\.c)/) {    ## Dependency
       $deps{$1} = $2;
     }
+    elsif ($text =~ /^(\S+\.o):\s*(\S+\.s)/) {    ## Dependency
+      $deps{$1} = $2;
+    }
     $text = '';
   }
   $F->close();
@@ -74,8 +77,12 @@ if (! -d $KDIR) {
 
 
 foreach (@objects) {
-  ($src = $_) =~ s/\.o$/.c/;
   die "No source known for $_\n" unless exists $deps{$_};
+  if($deps{$_} =~ /\.s$/) {
+     ($src = $_) =~ s/\.o$/.s/;
+  } else {
+     ($src = $_) =~ s/\.o$/.c/;
+  }
   if (-e "$KDIR/$src" || -l "$KDIR/$src") {
     unlink("$KDIR/$src") or die "$KDIR/$src: $!\n";
   }