AROS World Exec
Development => Development (General) => Topic started by: deadwood on January 20, 2022, 02:45:59 AM
-
Moving from another thread
Here is another question. How do I correctly implement a function that takes variable number of arguments on AROS?
Here is a sample program:
#include <stdio.h>
#include <stdarg.h>
#include <libraries/mui.h>
#include <proto/muimaster.h>
#include <proto/intuition.h>
#include <proto/exec.h>
#define VARARGS68K __stackparm
struct Library *MUIMasterBase = NULL;
static void VARARGS68K ask(Object *app, const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
MUI_Request(app, NULL, 0, "Requester", "*Ok", fmt,
(APTR)va->overflow_arg_area);
va_end(va);
}
int main(void)
{
MUIMasterBase = OpenLibrary((STRPTR)MUIMASTER_NAME, 0);
if (MUIMasterBase == NULL) {
printf("No MUI\n");
return 10;
}
Object *app = ApplicationObject, End;
ask(app, "6 * 7 = %d", 42);
MUI_DisposeObject(app);
CloseLibrary(MUIMasterBase);
return 0;
}
When running this on x86-64-v11 I get the funny result: "6 * 7 = 22160" :(
Varargs on 64-bit ABIs are passed via combination of registers and stack. There specification is quite complex. The "overflow_area" probably works on m68k and i386 but won't work on 64-bit (also on linux). I'll dig into AROS sources if what you want to do is even possible as MUI_Request takes an array of IPTR as "params" parameter if I'm not mistaking.
-
Here is something that might help you. Essentially what your code does is trying to forward varargs (...) into a varargs function (...). This is generally not supported in standard, but works on some architectures which use stack for passing arguments. I dug into AROS sources and have two solutions which should work on any architecture. Both involve variadic argument macros, which might not be available on old compilers.
#include <proto/exec.h>
#include <libraries/mui.h>
#include <proto/muimaster.h>
#include <stdio.h>
struct Library *MUIMasterBase = NULL;
#define SOLUTION2
#ifdef ORIGINAL
#define VARARGS68K
static void VARARGS68K ask(Object *app, const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
MUI_Request(app, NULL, 0, "Requester", "*Ok", fmt,
(APTR)va->overflow_arg_area);
va_end(va);
}
#endif
#ifdef SOLUTION1
#define ask(app, fmt, ...) \
({\
MUI_Request(app, NULL, 0, "S1", "*Ok", fmt, __VA_ARGS__); \
})
#endif
#ifdef SOLUTION2
#define ask(app, fmt, ...) \
({ \
IPTR __args[] = { AROS_PP_VARIADIC_CAST2IPTR(__VA_ARGS__) }; \
MUI_RequestA((app), NULL, 0, "S2", "*Ok", fmt, __args); \
})
#endif
int main(void)
{
MUIMasterBase = OpenLibrary((STRPTR)MUIMASTER_NAME, 0);
if (MUIMasterBase == NULL) {
printf("No MUI\n");
return 10;
}
Object *app = ApplicationObject, End;
ask(app, "6 * 7 = %d", 42);
MUI_DisposeObject(app);
CloseLibrary(MUIMasterBase);
return 0;
}
-
Thanks, I like the 2nd solution as it allows to keep the macro smaller.
BTW, I also tried these AROS_SLOWSTACKFORMAT macros (they are used in various places in the AROS source tree), but it does not seem to work. Here is an example (I get "6 * 7 = 21824'):
static void ask(Object *app, const char *fmt, ...)
{
AROS_SLOWSTACKFORMAT_PRE(fmt);
MUI_Request(app, NULL, 0, "Requester", "*Ok", fmt,
AROS_SLOWSTACKFORMAT_ARG(fmt));
AROS_SLOWSTACKFORMAT_POST(fmt);
}
-
As far I as I know AROS_SLOWSTACKFORMAT "repackage" C-like varargs (...) into Amiga-like varargs (called RAWARG under AROS - simply a stream of values with different sizes allocated on stack). In your case, you are "repacking" C-like varargs into C-like varargs (that's what MUI_Request accepts as last parameter) do that's why AROS_SLOWSTACKFORMAT won't work.
-
I am not really understanding this. Maybe, let's look at a case where this is used. C/Mount uses it here: https://github.com/deadw00d/AROS/blob/e75800b801d18415f3a316dc6cb9cd694702b073/workbench/c/Mount.c#L1853 (https://github.com/deadw00d/AROS/blob/e75800b801d18415f3a316dc6cb9cd694702b073/workbench/c/Mount.c#L1853)
If this code is correct then I don't see why it also wouldn't work for MUI_Request.
-
What I mean is that if you look at VPrintf and EasyRequestargs they both take RAWARG as last parameter, while MUI_Request takes "...".
-
Ah, my bad, I meant to use MUI_RequestA.
The following also works correctly now (but the one using va->overflow_arg_area doesn't, which is okay):
static void ask(Object *app, const char *fmt, ...)
{
AROS_SLOWSTACKFORMAT_PRE(fmt);
MUI_RequestA(app, NULL, 0, "Requester", "*Ok", fmt,
AROS_SLOWSTACKFORMAT_ARG(fmt));
AROS_SLOWSTACKFORMAT_POST(fmt);
}
Of course the macro version is preferable since everything is inlined and there is no memory allocation that can fail (other then running out of stack space that is).
-
Good we had this sorted out :) Any more 64-bit issues in MUIBase?
-
Yup, you can find MUIbase 4.4.1 which includes a x86_64-v11-aros version here: https://muibase.sourceforge.io/files/amiga/ (https://muibase.sourceforge.io/files/amiga/)
-
Nice thx! If the code is already 64-bit compliant we can try building also AxRuntime version (for native Linux version of MUIBase) once I fix AxRuntime. Seems it is broken under newer linuxes (right-click menu crashes application).
-
Yup, you can find MUIbase 4.4.1 which includes a x86_64-v11-aros version here: https://muibase.sourceforge.io/files/amiga/ (https://muibase.sourceforge.io/files/amiga/)
thank you Steffen :)