2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
5 Desc: Patch a library or device function
8 #include <aros/config.h>
9 #include <exec/execbase.h>
10 #include <aros/libcall.h>
11 #include <proto/exec.h>
12 #include "exec_debug.h"
14 #ifndef DEBUG_SetFunction
15 # define DEBUG_SetFunction 0
21 #include <aros/debug.h>
24 /*****************************************************************************
28 AROS_LH3(APTR
, SetFunction
,
31 AROS_LHA(struct Library
*, library
, A1
),
32 AROS_LHA(LONG
, funcOffset
, A0
),
33 AROS_LHA(APTR
, newFunction
, D0
),
36 struct ExecBase
*, SysBase
, 70, Exec
)
39 Replaces a certain jumptable entry with another one. This function only
40 Forbid()s taskswitching but doesn't Disable() interrupts. You have
41 to do your own arbitration for functions which are callable from
45 library - Pointer to library structure.
46 funcOffset - Offset of the jumpvector from the library base address in
47 bytes. It's the negative LVO (library vector offset)
48 multiplied with LIB_VECTSIZE.
49 newFunction - New jumptable entry (pointer to the new function).
52 Old jumptable entry (pointer to the old function).
55 While it's more or less safe to patch a library vector with
56 SetFunction() it's not possible to safely remove the patch later.
57 So don't use this function if it can be avoided.
60 Patch of the function Open() from dos.library:
61 You can find the LVO of 5 in clib/dos_protos.h.
62 SetFunction(DOSBase, -5 * LIB_VECTSIZE, NewOpen);
63 NewOpen must be prepared with AROS_UFH macros.
66 On native builds, this contains a hack to fix dos.library/ramlib
67 attempts to setfunction exec functions. Because of this, a funcOffset
68 of more than 32 kB be truncated. This hack will also fix other programs
69 only using the lower 16 bits of funcOffset and leaving garbage in the
70 upper 16 bits. These programs should be fixed.
73 MakeLibrary(), MakeFunctions(), SumLibrary()
77 ******************************************************************************/
81 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
85 D(bug("SetFunction(%s, %lx, %lx) = ", (ULONG
)library
->lib_Node
.ln_Name
, funcOffset
, (ULONG
)newFunction
));
87 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
89 Fix dos.library/ramlib attempts to SetFunction() CloseDevice/
90 CloseLibrary/RemDevice/RemLibrary/OpenDevice/OpenLibrary.
92 This also effectively limits the max offset to 32k, but this limit was
93 already in the original, though not really documented.
95 What happens is this: the prototype for the funcOffset says it is a
96 long, but the autodoc also says that only a0.w (lower 16 bits) is used.
97 Dos.library/ramlib only sets the lower 16 bits of a0 to the required
98 offset, without sign-extending to the upper 16 bits, in fact without
99 even clearing them. These high 16 bits will therefore contain garbage:
101 SetFunction(exec.library, 7804fe3e, fc6524) = 30303030 CloseDevice
102 SetFunction(exec.library, 3030fe62, fc6528) = 30303030 CloseLibrary
103 SetFunction(exec.library, 3030fe4a, fc651c) = 30303030 RemDevice
104 SetFunction(exec.library, 3030fe6e, fc6520) = 30303030 RemLibrary
105 SetFunction(exec.library, 3030fe44, fc6564) = 30303030 OpenDevice
106 SetFunction(exec.library, 3030fdd8, fc659a) = 30303030 OpenLibrary
108 In my [ldp] opinion, the autodoc should never have said that only A0.W
109 is used for the funcOffset, while specifying a "long" in the prototype.
110 This will stay broken and this fix will stay here until we fix
113 if (funcOffset
& 0x00008000)
115 funcOffset
|= 0xffff0000;
119 funcOffset
&= 0x0000ffff;
123 /* Vector pre-processing for non-native machines: */
124 funcOffset
= (-funcOffset
) / LIB_VECTSIZE
;
129 Arbitrate for the jumptable. This isn't enough for interrupt callable
130 functions - but it need not be.
134 /* Mark the library as changed. */
135 library
->lib_Flags
|=LIBF_CHANGED
;
137 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
138 /* The following section is coded like this (instead of using the macros),
139 because else gcc will output 64-bit muls instructions, that are not
140 present on the 68060 (and will crash it). It's faster this way, too. :) */
141 vecaddr
= (APTR
)((ULONG
)library
+ funcOffset
);
143 /* Get the old vector pointer */
144 ret
= (APTR
)*(ULONG
*)(((ULONG
)vecaddr
)+2);
146 /* Set new vector and jmp instruction */
147 *(UWORD
*)vecaddr
= 0x4ef9;
148 *(ULONG
*)(((ULONG
)vecaddr
)+2) = (ULONG
)newFunction
;
150 #else /* non-native section follows */
151 /* Get old vector. */
152 ret
= __AROS_GETVECADDR (library
, funcOffset
);
154 /* Don't forget to initialise the vector, or else there would be no actual
155 assembler jump instruction in the vector */
156 __AROS_INITVEC (library
, funcOffset
);
159 __AROS_SETVECADDR (library
, funcOffset
, newFunction
);
161 #endif /* end if system specific sections */
164 /* And clear the instruction cache. */
165 /* Simply clear the entire cache... */
168 /* ...or clear the vector address range specifically */
169 CacheClearE (__AROS_GETJUMPVEC(library
,funcOffset
),LIB_VECTSIZE
,CACRF_ClearI
|CACRF_ClearD
);
172 /* Arbitration is no longer needed */
175 /* Sum the library up again */
178 D(bug("%lx\n", ret
));