Page 1 of 1
GCC arguments passing and optimizations
Posted: Fri Aug 16, 2019 4:26 am
by LIC
Hi, I have a problem with passing arguments to a function.
Here is the function:
Code: Select all
void test(uint32_t a, uint32_t b)
{
uint32_t *arg = &a;
for (uint32_t i = 0; i < 4; ++i) {
printf("%h: %h\n", arg + i, *(arg + i));
}
}
and the call to that function:
This code is part of my kernel and the stack is setup at 0x20000 when the kernel is loaded. I ran this code with different levels of optimization and here are the outputs:
With O1 or no optimization:
0x0001ffe0: 0x00000000
0x0001ffe4: 0x00000001
Here the second argument is passed correctly.
With O2 or O3 optimization:
0x0001ffec: 0x00000000
0x0001fff0: 0x000025bc
Here the second argument is not passed and 0x25bc is just some random stuff.
It seems that with O2/O3 optimization GCC notices that I am not using the second argument in the function and just does not pass it. The reason I am using the pointer to access arguments is that I further would like to use a variable number of arguments.
Is there any kind of attribute to use on the function or another trick to force GCC to pass arguments even if there are not used? I would of course like to keep optimizations.
Regards
Re: GCC arguments passing and optimizations
Posted: Fri Aug 16, 2019 4:56 am
by Octocontrabass
Attempting to access one object from a pointer to another object is undefined behavior.
If you want to pass a variable number of arguments, you can use stdarg.h in your kernel.
Re: GCC arguments passing and optimizations
Posted: Fri Aug 16, 2019 9:23 am
by nullplan
To expand on Octo's answer: arg points to an array of only one element (namely a). Thus it is not permissible to calculate the pointer "arg + i" for i >= 2, and it is not permissible to dereference that pointer even for i >= 1. You are allowed to calculate the pointer to "one element past the end" of the array, but not to dereference it.
I also find it weird that you only get two lines of output. Should be four lines, according to the program. And "%h" is not a valid format string. I think you mean "%x".
Re: GCC arguments passing and optimizations
Posted: Sun Aug 18, 2019 4:24 am
by LIC
Hi and thanks for your replies. I get indeed get 4 lines of output but I only wrote 2 in my post as the last two ones were just random numbers and the printf function I use is a printf function I coded myself, that's why I am using "%h" and not "%x".
How can I use a variable number of arguments without using any library then?
Here is what I did for my "printf" function and it works fine...
Code: Select all
extern void printf(const char *format, ...)
{
uint32_t *curr_arg = (uint32_t *)&format + 1;
while (*format) {
// despecialization
if (*format == '\\') {
screen_putc(*(++format));
}
// special format
else if (*format == '%') {
switch (*(++format)) {
case 'i':
case 'd':
printi(*curr_arg++);
break;
case 'h':
printh(*curr_arg++);
break;
case 'c':
screen_putc(*(char *)(curr_arg++));
break;
case 's':
print(*(char **)(curr_arg++));
break;
case 'k':
screen_set_attr(*(uchar_t *)(curr_arg++));
break;
default:
screen_putc('?');
}
}
// normal character
else {
screen_putc(*format);
}
format++;
}
}
Why does it work with the printf function and not with my test function?
Regards
Re: GCC arguments passing and optimizations
Posted: Sun Aug 18, 2019 4:54 am
by iansjack
LIC wrote:How can I use a variable number of arguments without using any library then?
"stdarg.h" is a header file, not a library. Why wouldn't you want to use it?
Re: GCC arguments passing and optimizations
Posted: Sun Aug 18, 2019 4:12 pm
by LIC
Okay, I tried to understand stdarg.h, are variable arguments management built into the compiler?
Also why is my "printf" function working correctly?
Thanks for your replies
Re: GCC arguments passing and optimizations
Posted: Sun Aug 18, 2019 4:45 pm
by Solar
LIC wrote:Okay, I tried to understand stdarg.h, are variable arguments management built into the compiler?
For x86_64, it is not possible to implement <stdarg.h> functionality with pure C code. The first couple of parameters of a function are passed in registers. So you'll have to rely on the compiler to support you. G++ and clang do this via the following list of builtin functions:
- __builtin_va_arg( ap, type )
- __builtin_va_copy( dest, src )
- __builtin_va_end( ap )
- __builtin_va_start( ap, parmN )
and the typedef
Besides, implementing a function "printf()" (i.e., a function with a name
reserved by the standard) and then implementing
non-standard behavior (%h) is a
very bad idea. If you don't want to stick to the standard (why not?), then please use function names distinct from the ISO/IEC 9899 standard functions ("principle of least surprise").
And finally, have you considered adapting one of the existing standard libraries, instead of rolling your own? No offense intended, but the way you attempted to brute-force your variable argument list through undefined behavior makes me doubt you have the wherewithal to make a homegrown standard library fly. Actually, it's usually best to achieve quite some competence in user space programming before trying to tackle something like printf() (easily one of the most complex functions in the standard), or kernel-space programming...
Re: GCC arguments passing and optimizations
Posted: Sun Aug 18, 2019 10:15 pm
by nullplan
LIC wrote:Here is what I did for my "printf" function and it works fine...
Code: Select all
uint32_t *curr_arg = (uint32_t *)&format + 1;
Well, then you are very lucky indeed. That pointer is invalid. On AMD64, as well as most other archs, the arguments are passed in the registers, so the only way to have their address is for the compiler to spill them to stack. So the address will just be some random stuff somewhere on the stack. So just use va_arg(), please.
To answer your question, it worked because you were lucky, and the precise conditions applied that made it work. But it was fragile, and next compiler release might have already broken it. The likely difference between the working example here and the non-working one you posted first is the ellipsis.
Re: GCC arguments passing and optimizations
Posted: Tue Aug 20, 2019 3:29 am
by LIC
Ok, thank you for your replies and advice!