patching sys_call_table from a module
afs patches the sys_call_table to provide support for various functions. the existing doesnt seem to work right. i figured out that the ia64 calls are offset by 1024. but know i have a different problem:
during insmod i printk what i patch the table with:
sys_call_table[__NR_afs_syscall - 1024] = a000000000125bd0 afs_syscall a000000000125bd0
however, i get the following ksymoops when i try to use that syscall:
Quoted 3 lines
Quoted 3 lines
IP; a000000000125bd1 <[libafs-2.4.5].bss.end+7e32/3fffffffffee2261> <==>>b0; e000000004415ce0 <ia64_ret_from_syscall+0/20> b6; e000000004402f60 <demine_args+0/a0> b7; e0000000044157b0 <ia64_switch_to+b0/120>
Trace; e00000000441a080 <show_stack+40/c0>
Trace; e00000000441a840 <show_regs+740/780>
Trace; e00000000442b830 <die_if_kernel+70/140> Trace; e00000000442c510 <ia64_illegal_op_fault+130/220> Trace; e000000004403ed0 <dispatch_illegal_op_fault+2b0/400>
so yes, a000000000125bd0 does seem to be [libafs-2.4.5].bss.end+7e32 however, if i look at the loadmap from the insmod, i see:
a0000000000f59e0 T afs_syscall
would this have anything to do with -mconstant-gp?
i wrote a little example to illustrate my problem. its attached at the bottom. if i make a syscall(__NR_afs_syscall, ...) i get the following:
pts[2437]: Bad break 104
psr : 0000101008026018 ifs : 8000000000000008 ip : [<a0000000000344b0>]
unat: 0000000000000000 pfs : 0000000000000089 rsc : 0000000000000003
rnat: 40000000000bb190 bsps: e0000000044157b0 pr : 000000000001015b
ldrs: 0000000000000000 ccv : 0000000000000000 fpsr: 0009804c0270033f b0 : e000000004415ce0 b6 : e000000004402f60 b7 : e0000000044157b0 f6 : 1003e0000000000000020 f7 : 1003e0000000000000010
f8 : 1003e0000000000000006 f9 : 10002a000000000000000
r1 : e000000004a12b20 r2 : 0000000000000000 r3 : 00000000000000ff r8 : e00000002facff00 r9 : 0000000000000000 r10 : ffffffffffffffff r11 : 600000000000c3b8 r12 : e00000002facfe60 r13 : e00000002fac8000 r14 : e000000000000000 r15 : e000000004415ce0 r16 : e00000002facfe70 r17 : e00000002facfe78 r18 : 00001013080a6010 r19 : 20000000001e1bb0 r20 : 0000000000000000 r21 : 4000000000000e98 r22 : 600000000005ec20 r23 : 600000000005ed28 r24 : 0000000000005540 r25 : 2000000000293f90 r26 : 600000000005ed28 r27 : 0000000000000000 r28 : 0000000000000040 r29 : 0000000000000000 r30 : 0000000000000008 r31 : 0000000000000000 r32 : 0000000000000000 r33 : 0000000000000000 r34 : 0000000000000000 r35 : 0000000000000000 r36 : 0000000000000000 r37 : 0000000000000000 r38 : 0000000000000000 r39 : 0000000000000000
Call Trace: [<e00000000441a080>] sp=0xe00000002facfa50 bsp=0xe00000002fac8ec8
[<e00000000441a840>] sp=0xe00000002facfc10 bsp=0xe00000002fac8e70 [<e00000000442b830>] sp=0xe00000002facfc30 bsp=0xe00000002fac8e48 [<e00000000442bb00>] sp=0xe00000002facfc30 bsp=0xe00000002fac8e28 [<e000000004415d00>] sp=0xe00000002facfcc0 bsp=0xe00000002fac8e28 [<a0000000000344b0>] sp=0xe00000002facfe60 bsp=0xe00000002fac8de0 [<e000000004415ce0>] sp=0xe00000002facfe60 bsp=0xe00000002fac8dd8
what am i doing wrong or cant i do this?
/* mysyscall.c
% cc -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -ffixed-r13 -mfixed-rangeñ0-f15,f32-f127 -falign-functions2 -mb-step -D__KERNEL__ -DKERNEL -D_KERNEL -DMODULE -c mysyscall.c
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/init.h>
#include <sys/syscall.h>
extern long sys_call_table[];
static long saved_syscall;
asmlinkage long
afs_syscall(long arg0, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6, long arg7, long stack)
{
struct pt_regs *regs = (struct pt_regs *) &stack;
printk("afs_syscall()\n");
return 0;
}int __initmysyscall_init(void)
{
printk("hello world\n");
saved_syscall = sys_call_table[__NR_afs_syscall - 1024];
sys_call_table[__NR_afs_syscall - 1024] = (long) afs_syscall;
return 0;
}void __exitmysyscall_exit(void)
{
printk("goodbye cruel world\n");
sys_call_table[__NR_afs_syscall - 1024] = saved_syscall;
}module_init(mysyscall_init);module_exit(mysyscall_exit);
Chas-
Your problem is that, in IA64, a pointer to a function does not point directly to the function itself. Instead it points to a data structure where the first element truly points to the function and the second element contains the GP value for the function.
Changing your code to something like:
int __init
mysyscall_init(void)
{
struct foo {
long addr;
long gp;
} fp; printk("hello world\n");
saved_syscall = sys_call_table[__NR_afs_syscall - 1024];
fp = (struct foo *)afs_syscall;
sys_call_table[__NR_afs_syscall - 1024] = fp->addr;
return 0;}
should accomplish what you want. (I think there are some magic C macros that will break a function pointer into it's component pieces but I don't know what they are, I just do it the hard way :-)
Quoted 89 lines · chas williams
i wrote a little example to illustrate my problem. its attached at the bottom. if i make a
syscall(__NR_afs_syscall, ...)i get the following:pts[2437]: Bad break 104
psr : 0000101008026018 ifs : 8000000000000008 ip : [<
a0000000000344b0>]
unat: 0000000000000000 pfs : 0000000000000089 rsc : 0000000000000003
rnat:40000000000bb190bsps:e0000000044157b0pr :000000000001015b
ldrs: 0000000000000000 ccv : 0000000000000000 fpsr:0009804c0270033fb0 :e000000004415ce0b6 :e000000004402f60b7 :e0000000044157b0f6 :1003e0000000000000020f7 :1003e0000000000000010
f8 :1003e0000000000000006f9 :10002a000000000000000
r1 :e000000004a12b20r2 : 0000000000000000 r3 :00000000000000ffr8 :e00000002facff00r9 : 0000000000000000 r10 : ffffffffffffffff r11 :600000000000c3b8r12 :e00000002facfe60r13 :e00000002fac8000r14 :e000000000000000r15 :e000000004415ce0r16 :e00000002facfe70r17 :e00000002facfe78r18 :00001013080a6010r19 :20000000001e1bb0r20 : 0000000000000000 r21 :4000000000000e98r22 :600000000005ec20r23 :600000000005ed28r24 : 0000000000005540 r25 :2000000000293f90r26 :600000000005ed28r27 : 0000000000000000 r28 : 0000000000000040 r29 : 0000000000000000 r30 : 0000000000000008 r31 : 0000000000000000 r32 : 0000000000000000 r33 : 0000000000000000 r34 : 0000000000000000 r35 : 0000000000000000 r36 : 0000000000000000 r37 : 0000000000000000 r38 : 0000000000000000 r39 : 0000000000000000Call Trace: [<e00000000441a080>] sp=0xe00000002facfa50 bsp=0xe00000002fac8ec8[<
e00000000441a840>] sp=0xe00000002facfc10 bsp=0xe00000002fac8e70 [<e00000000442b830>] sp=0xe00000002facfc30 bsp=0xe00000002fac8e48 [<e00000000442bb00>] sp=0xe00000002facfc30 bsp=0xe00000002fac8e28 [<e000000004415d00>] sp=0xe00000002facfcc0 bsp=0xe00000002fac8e28 [<a0000000000344b0>] sp=0xe00000002facfe60 bsp=0xe00000002fac8de0 [<e000000004415ce0>] sp=0xe00000002facfe60 bsp=0xe00000002fac8dd8what am i doing wrong or cant i do this?
/*
mysyscall.c% cc -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -ffixed-r13 -mfixed-rangeñ0-f15,f32-f127 -falign-functions2 -mb-step -D__KERNEL__ -DKERNEL -D_KERNEL -DMODULE -c
mysyscall.c*/
#include <
linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/init.h>
#include <sys/syscall.h>extern long sys_call_table[];
static longsaved_syscall;asmlinkage long
afs_syscall(long arg0, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6, long arg7, long stack){ struct pt_regs *regs = (struct pt_regs *) &stack; printk("afs_syscall()\n"); return 0; }int
__initmysyscall_init(void){ printk("hello world\n"); saved_syscall = sys_call_table[__NR_afs_syscall - 1024]; sys_call_table[__NR_afs_syscall - 1024] = (long) afs_syscall; return 0; }void
__exitmysyscall_exit(void){ printk("goodbye cruel world\n"); sys_call_table[__NR_afs_syscall - 1024] = saved_syscall; }
module_init(mysyscall_init);module_exit(mysyscall_exit);_______________________________________________
Linux-IA64 mailing list
[email protected]
http://lists.linuxia64.org/lists/listinfo/linux-ia64
Signature · 4 lines
Don Dugger "Censeo Toto nos in Kansa esse decisse." - D. Gale [email protected] Ph: 303/938-9838
Quoted 2 lines
where the first element truly points to the function and the second element contains the GP value for the function.
ok. i see. so i can now set the syscall table to the 'real' location for the afs_syscall routine. however, i still run into trouble when invoking the syscall:
Quoted 3 lines
Quoted 3 lines
IP; a000000000034250 <[mysyscall].text.end+11/31> <==>>b0; a0000000000340e0 <[mysyscall].text.start+20/40> b6; e000000004402f60 <demine_args+0/a0> b7; e0000000044157b0 <ia64_switch_to+b0/120>
Trace; e00000000441a080 <show_stack+40/c0> Trace; e00000000441a840 <show_regs+740/780> Trace; e00000000442b830 <die_if_kernel+70/140> Trace; e000000004443fc0 <ia64_do_page_fault+760/800> Trace; e000000004415d00 <ia64_leave_kernel+0/2a0> Trace; a000000000034250 <[mysyscall].text.end+11/31> Trace; a0000000000340e0 <[mysyscall].text.start+20/40> Trace; a0000000000340e0 <[mysyscall].text.start+20/40>
i suspect that my afs_syscall() is trying to use the 'gp' which is probably not setup?
Quoted 2 lines
`-mconstant-gp' which I didn't see in your flags list. In general, you must compile your modules with the same flags that were
that's a problem. modules cant be compiled with -mconstant-gp apparently.
Chas-
Looking back at your last message I think you are compiling your module with the wrong flags. My kernel uses the flag `-mconstant-gp' which I didn't see in your flags list. In general, you must compile your modules with the same flags that were used to compile the kernel.
Quoted 26 lines · chas williams
Quoted 2 lines
where the first element truly points to the function and the second element contains the GP value for the function.
ok. i see. so i can now set the syscall table to the 'real' location for the
afs_syscallroutine. however, i still run into trouble when invoking the syscall:Quoted 3 lines
Quoted 3 lines
IP; a000000000034250 <[mysyscall].text.end+11/31> <==> >>b0; a0000000000340e0 <[mysyscall].text.start+20/40> b6; e000000004402f60 <demine_args+0/a0> b7; e0000000044157b0 <ia64_switch_to+b0/120>Trace;
e00000000441a080<show_stack+40/c0> Trace;e00000000441a840<show_regs+740/780> Trace;e00000000442b830<die_if_kernel+70/140> Trace;e000000004443fc0<ia64_do_page_fault+760/800> Trace;e000000004415d00<ia64_leave_kernel+0/2a0> Trace;a000000000034250<[mysyscall].text.end+11/31> Trace;a0000000000340e0<[mysyscall].text.start+20/40> Trace;a0000000000340e0<[mysyscall].text.start+20/40>i suspect that my
afs_syscall()is trying to use the 'gp' which is probably not setup?_______________________________________________
Linux-IA64 mailing list
[email protected]
http://lists.linuxia64.org/lists/listinfo/linux-ia64
Signature · 4 lines
Don Dugger "Censeo Toto nos in Kansa esse decisse." - D. Gale [email protected] Ph: 303/938-9838
Uh, maybe you should ignore my last message. I don't use modules so I'm really shouldn't try to debug them.
Quoted 4 lines · chas williams
Quoted 2 lines
`-mconstant-gp' which I didn't see in your flags list. In general, you must compile your modules with the same flags that were
that's a problem. modules cant be compiled with -mconstant-gp apparently.
Signature · 4 lines
Don Dugger "Censeo Toto nos in Kansa esse decisse." - D. Gale [email protected] Ph: 303/938-9838
It looks like you can't do this easily right now. As others have pointed out, on IA64 a pointer to a function is actually a pointer to a two element structure that contains the actual function address, and the gp value to use for that function.
However, sys_call_table in the kernel is not currently implemented as a real "array of pointers to functions" ... it is simply an array of function addresses ... and the code in ivt.S that makes the branch through the pointer when a user invokes a system call knows this. So the ivt.S code just leaves "gp" unchanged ... which works for all system calls that are staticly linked into the kernel, but means that system calls in modules are in trouble as they will be invoked with the kernel "gp" instead of their own, and they will fault as soon as they try to access any data objects that belong to the module.
You might be able to workaround this for now by providing a stub function in your module that sets "gp" and calls your real function.
Probably the real fix would be to change sys_call_table and ivt.S to make them follow the usual ia64 conventions for pointers to functions.
-Tony Luck
-----Original Message-----
From: chas williams [mailto:[email protected]]
Sent: Tuesday, July 03, 2001 6:46 AM
To: [email protected]
Subject: [Linux-ia64] patching sys_call_table from a module
afs patches the sys_call_table to provide support for various functions. the existing doesnt seem to work right. i figured out that the ia64 calls are offset by 1024. but know i have a different problem:
Quoted 2 lines
You might be able to workaround this for now by providing a stub function in your module that sets "gp" and calls your real function.
this seems the best idea at the moment. only one problem. i really dont know ia64 assembly. i managed to write a little function that just returns and patching the syscall entry with that doesnt crash. that's about the extent of my ability. i would guess that when module functions are called from the kernel that a small stub routine that preserves the kernel's gp and sets up the function's gp is called first? perhaps i could look at this code for some help? or if someone on this list would be kind enough...
Quoted 2 lines
You might be able to workaround this for now by providing a stub function in your module that sets "gp" and calls your real function.
i took at look at the what the modutil did when loading kernel modules. the following stub seems to work with one small problem:
GLOBAL_ENTRY(afs_syscall_stub)
mov r8=-1
movl r15=0xa000000000034610 /* afs_syscall */;;
ld8 r16=[r15],8
mov r14=gp;;
ld8 gp=[r15]
mov b6=r16
br.few b6;;END(afs_syscall_stub)
0xa000000000034610 is the descriptor for afs_syscall. if i use movl r15,afs_syscall;; instead, insmod fails to load the module:
insmod: obj_ia64.c:258: obj_ia64_ins_imm64: Assertion `slot = 1' failed.
i guess i dont know afs_syscall until the module is actually loaded?