2 Copyright © 1995-2001, 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
48 newFunction - New jumptable entry (pointer to the new function).
51 Old jumptable entry (pointer to the old function).
54 While it's more or less safe to patch a library vector with
55 SetFunction() it's not possible to safely remove the patch later.
56 So don't use this function if it can be avoided.
61 On native builds, this contains a hack to fix dos.library/ramlib
62 attempts to setfunction exec functions. Because of this, a funcOffset
63 of more than 32 kB be truncated. This hack will also fix other programs
64 only using the lower 16 bits of funcOffset and leaving garbage in the
65 upper 16 bits. These programs should be fixed.
68 MakeLibrary(), MakeFunctions(), SumLibrary().
72 ******************************************************************************/
76 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
80 D(bug("SetFunction(%s, %lx, %lx) = ", (ULONG
)library
->lib_Node
.ln_Name
, funcOffset
, (ULONG
)newFunction
));
82 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
84 Fix dos.library/ramlib attempts to SetFunction() CloseDevice/
85 CloseLibrary/RemDevice/RemLibrary/OpenDevice/OpenLibrary.
87 This also effectively limits the max offset to 32k, but this limit was
88 already in the original, though not really documented.
90 What happens is this: the prototype for the funcOffset says it is a
91 long, but the autodoc also says that only a0.w (lower 16 bits) is used.
92 Dos.library/ramlib only sets the lower 16 bits of a0 to the required
93 offset, without sign-extending to the upper 16 bits, in fact without
94 even clearing them. These high 16 bits will therefore contain garbage:
96 SetFunction(exec.library, 7804fe3e, fc6524) = 30303030 CloseDevice
97 SetFunction(exec.library, 3030fe62, fc6528) = 30303030 CloseLibrary
98 SetFunction(exec.library, 3030fe4a, fc651c) = 30303030 RemDevice
99 SetFunction(exec.library, 3030fe6e, fc6520) = 30303030 RemLibrary
100 SetFunction(exec.library, 3030fe44, fc6564) = 30303030 OpenDevice
101 SetFunction(exec.library, 3030fdd8, fc659a) = 30303030 OpenLibrary
103 In my [ldp] opinion, the autodoc should never have said that only A0.W
104 is used for the funcOffset, while specifying a "long" in the prototype.
105 This will stay broken and this fix will stay here until we fix
108 if (funcOffset
& 0x00008000)
110 funcOffset
|= 0xffff0000;
114 funcOffset
&= 0x0000ffff;
118 /* Vector pre-processing for non-native machines: */
119 funcOffset
= (-funcOffset
) / LIB_VECTSIZE
;
124 Arbitrate for the jumptable. This isn't enough for interrupt callable
125 functions - but it need not be.
129 /* Mark the library as changed. */
130 library
->lib_Flags
|=LIBF_CHANGED
;
132 #if (AROS_FLAVOUR & AROS_FLAVOUR_NATIVE)
133 /* The following section is coded like this (instead of using the macros),
134 because else gcc will output 64-bit muls instructions, that are not
135 present on the 68060 (and will crash it). It's faster this way, too. :) */
136 vecaddr
= (APTR
)((ULONG
)library
+ funcOffset
);
138 /* Get the old vector pointer */
139 ret
= (APTR
)*(ULONG
*)(((ULONG
)vecaddr
)+2);
141 /* Set new vector and jmp instruction */
142 *(UWORD
*)vecaddr
= 0x4ef9;
143 *(ULONG
*)(((ULONG
)vecaddr
)+2) = (ULONG
)newFunction
;
145 #else /* non-native section follows */
146 /* Get old vector. */
147 ret
= __AROS_GETVECADDR (library
, funcOffset
);
149 /* Don't forget to initialise the vector, or else there would be no actual
150 assembler jump instruction in the vector */
151 __AROS_INITVEC (library
, funcOffset
);
154 __AROS_SETVECADDR (library
, funcOffset
, newFunction
);
156 #endif /* end if system specific sections */
159 /* And clear the instruction cache. */
160 /* Simply clear the entire cache... */
163 /* ...or clear the vector address range specifically */
164 CacheClearE (__AROS_GETJUMPVEC(library
,funcOffset
),LIB_VECTSIZE
,CACRF_ClearI
|CACRF_ClearD
);
167 /* Arbitration is no longer needed */
170 /* Sum the library up again */
173 D(bug("%lx\n", ret
));