Login
Username:

Password:

Remember me



Lost Password?

Register now!

Sections

Who's Online
36 user(s) are online (22 user(s) are browsing Forums)

Members: 0
Guests: 36

more...

Support us!

Headlines

 
  Register To Post  

« 1 ... 3 4 5 (6)
Re: Tracing of callhookpkt()/callhook()
Just can't stay away
Just can't stay away


See User information
@kas1e
Quote:
PS. Also, did i understand it correctly, that they (os4 devs) tried to get rid of Varargs functions mostly from API ? Why i ask about, is that they say there https://wiki.amigaos.net/wiki/Linker_Libraries , that:

Intuition
CallHook
() and CallHookA()
These functions invoke hooksCallHook() expects a parameter packet ("message"on the stack, while CallHookA() takes a pointer to the message.
Replaced by IUtility->CallHookPkt() in V50.



Like, both were deprecated in favor of single CallHookPkt() , so to not have varargs function. Even if they have CallHook() still in utility.library (probably side effect of easy porting from os3 back in times), it all looks like that they want to get rid of Varargs one. Maybe because Varargs ones is potetialy not safe-ones, as can corrupt the stack in some conditions , etc, and that is the reassons they want non-varargs one to be used always ?
It's most likely not related to varargs at all, but that only utility.library CallHookPkt() includes the required check and different way to execute the Hook function depending on if it's emulated m68k code or PPC native code.

The same could have been added in the amiga.lib/libamiga.a hook functions, instead of removing them, but why? It would have been duplicated code, and statically linked code is always bad if you have the same functions in a shared library where bugs can be fixed or new features added without having to recompile all software using it as it's the case for static link libraries such as libamiga.a or the clib2 libc.a.

I don't know if there were usable OS3 utility.library sources which could have been used for the OS4 implementation, but I guess it was the same as with exec (and several other OS3 sources): Useless m68k assembler code reimplemented from scratch for OS4.

Go to top
Re: Tracing of callhookpkt()/callhook()
Home away from home
Home away from home


See User information
@joerg
Quote:

It's most likely not related to varargs at all, but that only utility.library CallHookPkt() includes the required check and different way to execute the Hook function depending on if it's emulated m68k code or PPC native code.


But as they have both CallHookPkt() (non varargs) and CallHook() (varargs) different implementation even today in utitlity.library, it's interesting why they choose to expand with emulator check an CallHookPkt() and not CallHook(). Probably because with the Varargs one there can be scenarios of corrupted stack, and varargs functions it not very secured ?

I mean, varargs stuff with all this “unknown amount of the arguments passed on stack” as final argument of the function can cause all sort of buffer overflows and string format issues in some conditions, and it is probably better to avoid varargs stuff as much as possible ?

I just go through google, and found right from start:

Quote:

Varargs throws out a lot of type-safety - you could pass pointers, floats, etc., instead of ints and it will compile without issue. Misuse of varargs, such as omitting arguments, can introduce odd crashes due to stack corruption, or reading invalid pointers.


or

Quote:

The vararg mandates that the parameter be passed on the stack, thus slowing the function call. On some architecture the difference can be significative. On x86 it's not very important because of its lack of register, on SPARC, for example, it can be important. Up to 5 parameters are passed on registers and if your function uses few locals, no stack adjustment is made. If your function is a leaf function (i.e. doesn't call another function), there is no window adjustment also. The cost of the call is therefor very small. With a vararg, the normal sequence of passing parameters on the stack, stack adjustement and window management is made or your function wouldn't be able to get at the parameters. This increases the cost of the call significantly.



And:

Quote:

A function using varargs cannot correctly verify its arguments

To try to avoid this, creators of varargs routines rely on conventions to manage this. For example, args sometimes get passed in as pairs - a type constant followed by the actual value ending with a sentinel:
SomeFunc(kInt, 3, kDouble, 2.0, kString, "blah", kLastArg);
Other times a descriptor is passed in first which describes the arguments:
printf("%d %f %s\n", 3, 2.0, "blah");
Other times, the first argument is a command:
DispatchMessage(kPaintWindow, &bounds, blackColor);
No matter what, it is possible to break the callee by passing in something that doesn't follow the convention. The problem is that there is nothing that can be done to enforce the convention. Without enforcement, you get a crash if you're lucky. If you're not lucky, you get a time bomb set in your heap that will go off only if the conditions are right.
In the last example, you're about as safe as you can get as long as you don't actually called DispatchMessage(), but instead use author-supplied macros like:
#define PaintWindow(bounds, color) DispatchMessage(kPaintWindow, bounds, color)
because then at least DispatchMessage is called correctly as long as the macro matches convention, and it is a single point of failure (which means a single point for a fix, which we like). I would turn around and argue that a single API, DispatchMessage, would be better off being multiple APIs.
Here's the skinny - if you're using varargs, you're probably doing something wrong out of the gate. Varargs promises a lot, but delivers very little.


So maybe that was another reasson why they choose to expand CallHookPkt() with an emulator, and not varargs based CallHook().

ps. Btw, can you remind why "A" append at the end of functions ? I mean, CallHook() -> varargs, CallHookA() - not. DoSuperMethod() - varargs, DoSuperMethodA() not. A mean A* register ?

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top
Re: Tracing of callhookpkt()/callhook()
Not too shy to talk
Not too shy to talk


See User information
@kas1e

Just quickly I always knew the "A" postfixed to function names as being for Attribute. But it's confused again by "Tags" or "TagList" functions where that's postfixed on names as well. Like OpenWindowTagList and OpenWindowTags. Suppose the "A" team of functions is mainly for BOOPSI.

Go to top
Re: Tracing of callhookpkt()/callhook()
Just can't stay away
Just can't stay away


See User information
@kas1e
Quote:
But as they have both CallHookPkt() (non varargs) and CallHook() (varargs) different implementation even today in utitlity.library, it's interesting why they choose to expand with emulator check an CallHookPkt() and not CallHook().
The removed amiga.lib/libamiga.a CallHook() didn't support emulated m68k code, but of course the utility.library one does.

Like with all other VARARGS68K functions, for example the TagItem ones or IDOS->FPrintf() calling IDOS->VFPrintf(), there is not much additional code, it's simply something like
uint32 VARARGS68K _impl_CallHook(struct UtilityIFace *Selfstruct Hook *hookAPTR object, ...)
{
   
uint32 result;
   
va_list args;
   
va_startlinear(argsobject);
   
result Self->CallHookPkt(hookobjectva_getlinearva(objectAPTR));
   
va_end(args);
   return 
result;
}


On AmigaOS <= 3.9/m68k such varargs functions IIRC weren't even in the AmigaOS shared libraries, but instead in the AztecC/SASC/DICE/GCC/VBCC/etc. pragma/inline includes, i.e. for GCC something like:
static inline CallHook(struct Hook *hookAPTR object, ...))
{
   return 
CallHookPkt(hookobject, &(object 1));
}
in inline/utility.h.
But such simple stack hacks don't work on PPC where the first 8 arguments of each type, int, float/double and vector, are passsed in registers, only on CPUs like m68k using the stack for all arguments.

Go to top
Re: Tracing of callhookpkt()/callhook()
Home away from home
Home away from home


See User information
@joerg
Quote:

The removed amiga.lib/libamiga.a CallHook() didn't support emulated m68k code, but of course the utility.library one does.

That is clear, but now utility.library on amigaos4 have both CallHookPkt() and CallHook() : question is why they choose to add support for emulated m68k code to CallHookPkt() and not to CallHook() (which is now part of utility.library too for now).

Is adding m68k emulation support code to non-varargs functions is anyhow better choose ? Or it's all simple because CallHook() were added to os4's utility.library for easy os3 porting after CallHookPkt() were expanded with m68k emulation support code ?

OS4 devs says that in OS4, CallHookPkt() and CallHook() are 2 independent functions.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top
Re: Tracing of callhookpkt()/callhook()
Just can't stay away
Just can't stay away


See User information
@kas1e
Are you sure IUtility->CallHook() doesn't include m68k support?
That would be very strange.

Quote:
OS4 devs says that in OS4, CallHookPkt() and CallHook() are 2 independent functions.
Maybe because it's such a small function that the code size of a uint32 VARARGS68K _impl_CallHook() calling Self->CallHookPkt(), as I wrote in my previous answer, isn't much less then implementing it directly.
It's a very small function anyway, something like
if (IExec->IsNative(hook->h_Entry))
   return 
hook->h_Entry(hookobjectmessage);
else
   return 
IExec->EmulateTags(hook->h_EntryET_RegisterA0hookET_RegisterA2objectET_RegisterA1messageTAG_DONE);
for CallHookPkt() and
uint32 result;
   
APTR message;
   
va_list args;
   
va_startlinear(argsobject);
   
message va_getlinearva(objectAPTR));
   if (
IExec->IsNative(hook->h_Entry))
      
result hook->h_Entry(hookobjectmessage);
   else
      
result IExec->EmulateTags(hook->h_EntryET_RegisterA0hookET_RegisterA2objectET_RegisterA1messageTAG_DONE);
   
va_end(args);
   return 
result;
for CallHook().

Go to top
Re: Tracing of callhookpkt()/callhook()
Not too shy to talk
Not too shy to talk


See User information
@joerg

An issue with that is it's using h_Entry as the HLL entry point. According to convention, h_Entry is for asm stub and h_Subentry is the HLL function. Mind you, it's pointing to some code, but that's not the point. It's designed so that h_Entry is an asm stub that calls h_Subentry. Perhaps naming it as h_Start and h_Main or h_Function would be less confusing but I suppose in any case h_Entry can be treated as a generic entry point.

Go to top
Re: Tracing of callhookpkt()/callhook()
Just can't stay away
Just can't stay away


See User information
@Hypex
On PPC nobody is using an asm stub in h_Entry and a C function in h_SubEntry.
It's not required because on PPC all 3 arguments are passed in registers (r3, r4 and r5) in C code anyway.

On m68k an asm stub in h_Entry can be used which pushes the 3 registers A0, A2 and A1 on the stack and calls a C function in h_SubEntry.
On m68k C functions don't use registers but only the stack for the arguments.

But even on m68k most people didn't use that anymore but something like
ASM SAVEDS int32 hookFunc(REG(a0struct Hook *hook), REG(a2APTR object), REG(a1APTR message))
{
   ...
   return 
result;
}
in h_Entry.

The EmulateTags() call works in any case, no matter if there is a m68k asm stub in h_Entry which calls a h_SubEntry function with stack arguments, or if h_Entry is the C function using register arguments with the REG() macro.

It's the same for PPC native code, just in case someone uses useless code like
int32 hookFunc(struct Hook *hookAPTR objectAPTR message)
{
   ...
   return 
result;
}

int32 hookStub(struct Hook *hookAPTR objectAPTR message)
{
   return 
hook->h_SubEntry(hookobjectmessage);
}

struct Hook hook;
hook.h_Entry hookStub;
hook.h_SubEntry hookFunc;


Edited by joerg on 2024/5/23 6:08:42
Go to top
Re: Tracing of callhookpkt()/callhook()
Not too shy to talk
Not too shy to talk


See User information
@joerg

Quote:
On PPC nobody is using an asm stub in h_Entry and a C function in h_SubEntry. It's not required because on PPC all 3 arguments are passed in registers (r3, r4 and r5) in C code anyway.


Yes, obviously the ABI convention helps here in SYSV, which C compilers follow.

The 68K ABI convention is also the same way as the native ABI also uses registers in API calls, however, C compilers don't follow it for internal functions calls and use the common stacking standard.

Quote:
On m68k an asm stub in h_Entry can be used which pushes the 3 registers A0, A2 and A1 on the stack and calls a C function in h_SubEntry. On m68k C functions don't use registers but only the stack for the arguments.


And that's where the mess begins. It would have needed a specific keyword like APICALL in GCC does, but I imagine that C compilers could have used registers automatically, if they could be told to call it like an API function. Of course there would be no library base so perhaps it wouldn't have been easy to tell the C compiler to put parameters in registers like a normal library call.

Quote:
But even on m68k most people didn't use that anymore but something like


Except in that case but it can be compiler specific. Where as a library call using the same register method is just an include file away for the causal coder.

Quote:
The EmulateTags() call works in any case, no matter if there is a m68k asm stub in h_Entry which calls a h_SubEntry function with stack arguments, or if h_Entry is the C function using register arguments with the REG() macro.


Transparency is good and expected.

Quote:
It's the same for PPC native code, just in case someone uses useless code like


Ha.

Go to top
Re: Tracing of callhookpkt()/callhook()
Just can't stay away
Just can't stay away


See User information
@Hypex
Quote:
The 68K ABI convention is also the same way as the native ABI also uses registers in API calls,
No, it doesn't.
Check for example https://m680x0.github.io/doc/abi.html
For the return value a register (d0 for ints, a0 for pointers) is used, but all arguments are on the stack, none in a register.

Quote:
Quote:
But even on m68k most people didn't use that anymore but something like

Except in that case but it can be compiler specific.
It would have been compiler specific if I'd have used something like
int32 hookFunc(__asm(a0struct Hook *hook__asm(a2APTR object__asm(a1APTR message)
which only works with GCC, but using the REG() macro instead works at least with SAS/C, DICE, VBCC, StormC and GCC.

Go to top
Re: Tracing of callhookpkt()/callhook()
Not too shy to talk
Not too shy to talk


See User information
@joerg

Quote:
No, it doesn't.


I don't know what it's based on but I meant the Amiga 68K ABI which is fully register based. For API calls. Including the A6 offset jump.

Quote:
It would have been compiler specific if I'd have used something like


That's still too complicated. Given a library call is like this without needing to think about it. So it certainly could have been programmed in.

int32 hookFunc(struct Hook *hookAPTR objectAPTR message)

Go to top
Re: Tracing of callhookpkt()/callhook()
Just can't stay away
Just can't stay away


See User information
@Hypex
Quote:
That's still too complicated. Given a library call is like this without needing to think about it.
Only works because on m68k the AmigaOS library calls are replaced with inline functions, macros or #pragma, depending on the compiler, which replace the standard stack based m68k ABI with register arguments, and a hidden A6 library base argument, for those functions .

Quote:
So it certainly could have been programmed in.

int32 hookFunc(struct Hook *hookAPTR objectAPTR message)
#include https://github.com/adtools/SDI/blob/master/SDI_hook.h
HOOKPROTO(hookFuncint32APTRAPTR);
static 
int32 hookFunc(struct Hook *hookAPTR objectAPTR message)
{
   ...
}

Go to top
Re: Tracing of callhookpkt()/callhook()
Not too shy to talk
Not too shy to talk


See User information
@joerg

Quote:
Only works because on m68k the AmigaOS library calls are replaced with inline functions, macros or #pragma, depending on the compiler, which replace the standard stack based m68k ABI with register arguments, and a hidden A6 library base argument, for those functions .


Then that's what was needed. Regarding SDI, looks like it was a bit too late for the 80's, being dated from this century. But what does SDI mean? I read through that project years ago and unless I missed the obvious it doesn't say what it is. I think an acronym is rather pointless if it isn't explained on the first line of the readme.

Go to top
Re: Tracing of callhookpkt()/callhook()
Just can't stay away
Just can't stay away


See User information
@Hypex
Quote:
Regarding SDI, looks like it was a bit too late for the 80's, being dated from this century.
For AmigaOS, 1-3.x/m68k and 4.x/PPC, it's useless, the REG(), ASM, SAVEDS, etc. macros are enough if you want to support both m68k and PPC versions of AmigaOS, or even just different compilers: SAS/C, DICE, StormC, VBCC and GCC for m68k AmigaOS, VBCC and GCC for PPC AmigaOS.
SDI is only required if you additionally want to support AmigaOS incompatible OSes like AROS and/or MorphOS.

Quote:
But what does SDI mean? I read through that project years ago and unless I missed the obvious it doesn't say what it is. I think an acronym is rather pointless if it isn't explained on the first line of the readme.
Standard Developver Interface

Go to top
Re: Tracing of callhookpkt()/callhook()
Home away from home
Home away from home


See User information
@joerg
Quote:

Are you sure IUtility->CallHook() doesn't include m68k support?
That would be very strange.


Do some debugging with GDB and find out that even for IUtility->CallHook(.....) there seems to be 68k emulator check too (while, it different functions still, and not simple use of CallHookPkt() inside), see:

test case:

#include 

uint32 MyFunction (struct Hook *hVOID *oVOID *msg)
{
        
printf("test\n");
        return(
1);
}

int main()
{
        
struct Hook h;

        
h.h_Entry MyFunction;
        
h.h_SubEntry NULL;
        
h.h_Data NULL;

        
IUtility->CallHook(&h,NULL,NULL);

        exit(
0);
}


And gdb output:

(gdb) break main
Breakpoint 1 at 0x1ffb152c
file callhook_static.cline 16.
(gdbr
Starting program
: /WinDH_D/cygwin_gcc_11_3/amiga/hooks/tracer/tests/callhook_static 

Breakpoint 1
main () at callhook_static.c:16

(gdbdisas

Dump of assembler code 
for function main:
0x1ffb152c :    stwu    r1,-48(r1)
0x1ffb1530 :    mflr    r0
0x1ffb1534 
:    stw     r0,52(r1)
0x1ffb1538 :   lis     r9,8187
0x1ffb153c 
:   addi    r9,r9,5376
0x1ffb1540 
:   stw     r9,24(r1)
0x1ffb1544 :   li      r9,0
0x1ffb1548 
:   stw     r9,28(r1)
0x1ffb154c :   stw     r9,32(r1)
0x1ffb1550 :   lis     r10,15555
0x1ffb1554 
:   lwz     r3,-10520(r10)
0x1ffb1558 :   stw     r9,8(r1)
0x1ffb155c :   lwz     r9,132(r3)
0x1ffb1560 :   mtctr   r9
0x1ffb1564 
:   li      r5,0
0x1ffb1568 
:   addi    r4,r1,16
0x1ffb156c 
:   crset   4*cr1+eq
0x1ffb1570 
:   bctrl
0x1ffb1574 
:   li      r3,0
0x1ffb1578 
:   bl      0x1ffb1598 
End of assembler dump
.


Latest main+68 there is call to CallHook(), so:

(gdb) break *main+68
Breakpoint 2 at 0x1ffb1570
file callhook_static.cline 24.

(gdbc
Continuing
.

Breakpoint 20x1ffb1570 in main () at callhook_static.c:24


Inside of CallHook():

(gdbsi
0x0886b6e8 in 
?? ()

(
gdbx/24i 0x0886b6e8
0x886b6e8
:      mflr    r0
0x886b6ec
:      li      r9,8
0x886b6f0
:      stw     r26,168(r1)
0x886b6f4:      addi    r10,r1,64
0x886b6f8
:      mr      r26,r5
0x886b6fc
:      stw     r28,176(r1)
0x886b700:      mr      r28,r3
0x886b704
:      stw     r29,180(r1)
0x886b708:      addi    r29,r1,200
0x886b70c
:      stw     r30,184(r1)
0x886b710:      mr      r30,r4
0x886b714
:      stw     r0,196(r1)
0x886b718:      stw     r27,172(r1)
0x886b71c:      stw     r31,188(r1)
0x886b720:      stb     r9,56(r1)
0x886b724:      stb     r9,57(r1)
0x886b728:      lwz     r8,16(r3)
0x886b72c:      lwz     r31,8(r4)
0x886b730:      lwz     r8,36(r8)
0x886b734:      mr      r3,r31
0x886b738
:      stw     r29,60(r1)
0x886b73c:      lwz     r27,632(r8)
0x886b740:      stw     r10,64(r1)
0x886b744:      bl      0x8812058


So check what it calls inside callhook() by this latest BL:

(gdbsi 24

0x08812058 in 
?? ()

(
gdbx/8i 0x08812058
0x8812058
:      rlwinm  r4,r3,4,28,31
0x881205c
:      lis     r5,2332
0x8812060
:      ori     r5,r5,44372
0x8812064
:      lbzx    r0,r4,r5
0x8812068
:      cmpwi   r0,2
0x881206c
:      beq-    0x8812078
0x8812070
:      mr      r3,r0
0x8812074
:      blr
(gdb)


And as far as i aware, this function checks whether a pointer points to a segment containing PPC-native or 68k code. The segment is determined by the most significant 4 bits of the address, which is then used as an index into a table. The type read from this table is 0 for 68k code and 1 for PPC code. When a 2 is read, then the BAT registers decide about the type of code and go back to callhook().

Exactly the same code present in the CallHookPkt() too, so they both seems to call some internal function which do that check, something like "is_hal_native()" or something of that sort.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top
Re: Tracing of callhookpkt()/callhook()
Not too shy to talk
Not too shy to talk


See User information
@joerg

Quote:
For AmigaOS, 1-3.x/m68k and 4.x/PPC, it's useless, the REG(), ASM, SAVEDS, etc. macros are enough if you want to support both m68k and PPC versions of AmigaOS, or even just different compilers: SAS/C, DICE, StormC, VBCC and GCC for m68k AmigaOS, VBCC and GCC for PPC AmigaOS. SDI is only required if you additionally want to support AmigaOS incompatible OSes like AROS and/or MorphOS.


I thought it was useful for any cross Amiga development. Including modern development. Especially for AROS and MOS without major changes.

Quote:
Standard Developver Interface


Thanks. So it wasn't anyones initials. Now if only they stated this on Github. :[-D

Go to top
Re: Tracing of callhookpkt()/callhook()
Not too shy to talk
Not too shy to talk


See User information
@kas1e

Quote:
Do some debugging with GDB and find out that even for IUtility->CallHook(.....) there seems to be 68k emulator check too (while, it different functions still, and not simple use of CallHookPkt() inside), see:


How did you do that? The only GDB I know working is the old 6.3 one and being they can all report same build date makes it hard to know which. And it only works on A1/XE and Classic from my testing.

Quote:
And as far as i aware, this function checks whether a pointer points to a segment containing PPC-native or 68k code. The segment is determined by the most significant 4 bits of the address, which is then used as an index into a table. The type read from this table is 0 for 68k code and 1 for PPC code. When a 2 is read, then the BAT registers decide about the type of code and go back to callhook().


Except there's some slight overhead manually checking like that. It's true PPC and 68K would be in their own segment. I don't recall where but I read that 68K and and PPC spaces are marked by MMU. May have been in some document on porting libraries. So what it does is attempt to simply jump to an address. If it's not marked as executable segment it will cause an ISI trap. The trap will check the address and if it's 68K drop into the emulator to run it. That allows code to run transparently without checking addresses like a standard emulator would.

But, for calling hooks, it could just check before jumping in. From native code it should be native. But I suppose hooks are backwards compatible to 68K as well.

Quote:
Exactly the same code present in the CallHookPkt() too, so they both seems to call some internal function which do that check, something like "is_hal_native()" or something of that sort.


There is something. I forget which. It may be TypeOfMem() but that was also around in 68K so not specific to OS4 checking address is 68K.

Go to top

  Register To Post
« 1 ... 3 4 5 (6)

 




Currently Active Users Viewing This Thread: 1 ( 0 members and 1 Anonymous Users )




Powered by XOOPS 2.0 © 2001-2024 The XOOPS Project