Relocation Error when Inserting External Cross-Compiled SPARC Linux Module
Asked Answered
R

1

8

First off: I am not an expert, so please excuse any mistakes I make trying to explain myself.

I am trying to cross-compile an external Linux module for a SPARC machine using Sparc-Linux-GCC-4.4.2. The version of the Linux kernel is 2.6.36.4-00037-g059aa91-dirty. It has been patched with some files from the LEON processor. The build flow is provided to me and it uses LinuxBuild, Buildroot, and Busybox. I am trying to make a 32 bit OS.

Everything seems to work but after I compile the module and try to insmod it to the SPARC system I get this error:

module hellok:  Unknown relocation: 6

This error comes from ~/linuxbuild-1.0.3/linux/linux-2.6-git/arch/sparc/kernel/module.c I will provide the whole method for the sake of completeness:

int apply_relocate_add(Elf_Shdr *sechdrs,
           const char *strtab,
           unsigned int symindex,
           unsigned int relsec,
           struct module *me)
{
unsigned int i;
Elf_Rela *rel = (void *)sechdrs[relsec].sh_addr;
Elf_Sym *sym;
u8 *location;
u32 *loc32;

for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
    Elf_Addr v;

    /* This is where to make the change */
    location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr
        + rel[i].r_offset;
    loc32 = (u32 *) location;

#ifdef CONFIG_SPARC64
    BUG_ON(((u64)location >> (u64)32) != (u64)0);
#endif /* CONFIG_SPARC64 */

    /* This is the symbol it is referring to.  Note that all
       undefined symbols have been resolved.  */
    sym = (Elf_Sym *)sechdrs[symindex].sh_addr
        + ELF_R_SYM(rel[i].r_info);
    v = sym->st_value + rel[i].r_addend;

    switch (ELF_R_TYPE(rel[i].r_info) & 0xff) {
#ifdef CONFIG_SPARC64
    case R_SPARC_64:
        location[0] = v >> 56;
        location[1] = v >> 48;
        location[2] = v >> 40;
        location[3] = v >> 32;
        location[4] = v >> 24;
        location[5] = v >> 16;
        location[6] = v >>  8;
        location[7] = v >>  0;
        break;

    case R_SPARC_DISP32:
        v -= (Elf_Addr) location;
        *loc32 = v;
        break;

    case R_SPARC_WDISP19:
        v -= (Elf_Addr) location;
        *loc32 = (*loc32 & ~0x7ffff) |
            ((v >> 2) & 0x7ffff);
        break;

    case R_SPARC_OLO10:
        *loc32 = (*loc32 & ~0x1fff) |
            (((v & 0x3ff) +
              (ELF_R_TYPE(rel[i].r_info) >> 8))
             & 0x1fff);
        break;
#endif /* CONFIG_SPARC64 */
    
    
    case R_SPARC_32:
    case R_SPARC_UA32:
        location[0] = v >> 24;
        location[1] = v >> 16;
        location[2] = v >>  8;
        location[3] = v >>  0;
        break;

    case R_SPARC_WDISP30:
        v -= (Elf_Addr) location;
        *loc32 = (*loc32 & ~0x3fffffff) |
            ((v >> 2) & 0x3fffffff);
        break;

    case R_SPARC_WDISP22:
        v -= (Elf_Addr) location;
        *loc32 = (*loc32 & ~0x3fffff) |
            ((v >> 2) & 0x3fffff);
        break;

    case R_SPARC_LO10:
        *loc32 = (*loc32 & ~0x3ff) | (v & 0x3ff);
        break;

    case R_SPARC_HI22:
        *loc32 = (*loc32 & ~0x3fffff) |
            ((v >> 10) & 0x3fffff);
        break;

    default:
        printk(KERN_ERR "module %s: Unknown relocation: %x\n",
               me->name,
               (int) (ELF_R_TYPE(rel[i].r_info) & 0xff));
        return -ENOEXEC;
    };
}
return 0;
}

So I understand the default case is the one I am falling under. ELF_R_TYPE(rel[i].r_info (SPARC Relocations) types are defined in my ~/linuxbuild-1.0.3/dist/buildroot/build-br/staging/usr/include/elf.h file and some are as follows:

/* SPARC relocs.  */

#define R_SPARC_NONE        0   /* No reloc */
#define R_SPARC_8           1   /* Direct 8 bit */
#define R_SPARC_16          2   /* Direct 16 bit */
#define R_SPARC_32          3   /* Direct 32 bit */
#define R_SPARC_DISP8       4   /* PC relative 8 bit */
#define R_SPARC_DISP16      5   /* PC relative 16 bit */
#define R_SPARC_DISP32      6   /* PC relative 32 bit */
#define R_SPARC_WDISP30     7   /* PC relative 30 bit shifted */
#define R_SPARC_WDISP22     8   /* PC relative 22 bit shifted */
#define R_SPARC_HI22        9   /* High 22 bit */
#define R_SPARC_22          10  /* Direct 22 bit */
#define R_SPARC_13          11  /* Direct 13 bit */
#define R_SPARC_LO10        12  /* Truncated 10 bit */
#define R_SPARC_GOT10       13  /* Truncated 10 bit GOT entry */
#define R_SPARC_GOT13       14  /* 13 bit GOT entry */
#define R_SPARC_GOT22       15  /* 22 bit GOT entry shifted */
#define R_SPARC_PC10        16  /* PC relative 10 bit truncated */
#define R_SPARC_PC22        17  /* PC relative 22 bit shifted */
#define R_SPARC_WPLT30      18  /* 30 bit PC relative PLT address */
#define R_SPARC_COPY        19  /* Copy symbol at runtime */
#define R_SPARC_GLOB_DAT    20  /* Create GOT entry */
#define R_SPARC_JMP_SLOT    21  /* Create PLT entry */
#define R_SPARC_RELATIVE    22  /* Adjust by program base */
#define R_SPARC_UA32        23  /* Direct 32 bit unaligned */

/* Additional Sparc64 relocs.  */
...

So relocation 6 corresponds to R_SPARC_DISP32 aka PC relative 32 bit. This is defined in the module.c case statement, but only under the 64-bit section. I think I either need to write the relocation myself or figure out what relocation flag I need and change the flag during compilation. I don't really understand what is going on in the relocation code, so please help me figure out how I should fix this. I don't think I can build the OS as 64-bit because it seems to break the system, so please help me find alternate solutions.

Rohrer answered 20/4, 2012 at 23:47 Comment(9)
Is it possible that it has to do with the MMU?Rohrer
Just thinking out loud, but can you [target]-objdump -r some compiled modules from the target machine and figure out what type of relocations they are using? And then figure out where in the build system the type to use is chosen? How confident are you that your build system / configuration / headers matches what's on the machine?Imaginary
Which Leon processor? Which distribution is running - something from Gaisler or something else? Do you have -m32 in your build flags?Imaginary
I am using the SPARC hfleonv8 with MMU, FPU, and mul/div (V8). I am running the Gaisler distribution and am only using files downloaded from their site. I have tried all LinuxBuild versions and am currently using the latest 1.0.4. An "lsmod" shows no modules running on the target machine. I've tried adding -m32 in EXTRA_CFLAGS but the same results occur. I did not know about objdump but I have used it on the module with the problem and see that there are multiple different relocations. Only 2 lines have the problem relocation value under [.eh_frame].Rohrer
I am not positive everything is configured properly, but it has all been done according to the documentation. The most recent documentation for building external modules is for an older version of linux, so I have been trying to figure it out on my own.Rohrer
See if you have anything at all (unused) under /lib/modules on the running system and if so do this: readelf -r something.ko | grep -o 'R[^ ]*' | sort -u and compare for the one on the system and the one you build. Are you sure the kernel sources you are using are for the same kernel version as on the system (ie, uname -a) ? Is there a /proc/config.gz you can pull off and examine?Imaginary
Nothing is placed in /lib/modules. There is no /proc/config.gz. I built some non-custom modules through "make xconfig" and they have the same relocation flags as the module I am trying to build. I can remove the [.eh_frame] and the relocation error by using the flag: -fno-dwarf2-cfi-asm : Emit DWARF 2 unwind info as compiler generated ".eh_frame" section instead of using GAS ".cfi_*" directives. Would it be bad to use this?Rohrer
I suspect dwarf debugging info may be optional anyway, maybe you could disable that entirely in the kernel config you are building against or with a gcc option, ie, no -g ?Imaginary
How can I know which kernel headers I am using to compile linux and the modules? I am using the sparc-linux-4.4.2-toolchain and the glibc as my C library. uname gives: Linux buildroot 2.6.36.4-00037-g40678bc sparc GNU/Linux. Also I looked at the flags for module compilation and there is no -g, I have to keep looking if the other flags had anything to do with the eh_frame.Rohrer
U
2

I have exactly the same problem with my own module, for a Leon-Linux configuration (linuxbuild-1.0.1).

What I did is that I moved the 'case R_SPARC_DISP32' portion of code (the 4 lines) just after the line '#endif /* CONFIG_SPARC64 */'

That's some bad hack Harry ;-) but at least I can now insmod the module... Now I need to look for side-effects on the user-land side, when apps call the routines of the module.

So, to be continued...

Best regards, Karim

Undefined answered 16/5, 2012 at 15:32 Comment(1)
I also used this for a while, but I didn't feel comfortable since I couldn't be sure that this is appropriate. I think the -fno-dwarf2-dfi-asm flag is better, but can't be positive.Rohrer

© 2022 - 2024 — McMap. All rights reserved.