« The beginning of a bigger change ? | Main | A small x86_64 optimization brainteaser [with complete solution] »

va_list is now an array of some (opaque ?) struct... gee thanks

A little trap in the new 64 bit ABI.
void   bar( va_list args)
{
   va_list   x;  
   
   x = args;
   return( va_arg( x, int));
}
does not work anymore. It gives the error

error: array type 'va_list' (aka 'struct __va_list_tag [1]') is not assignable

I was curious if there was any "obvious" change in functionality. Here is the part of a function calling bar disassembled for three different architectures. The disassembly shows, that it's the same internally, two pointers are pushed unto the stack (put into parameter registers).

x86_64
	movq	%rbx, %rsi
	movl	%r12d, %edi
	call	_bar

i386:
	movl	-12(%ebp), %eax
	movl	%eax, 4(%esp)
	movl	8(%ebp), %eax
	movl	%eax, (%esp)
	call	_bar

ppc:
	lwz r4,76(r1)
	mr r3,r29
	bl _bar
What does work in the old and the new world is
void   bar( va_list args)
{
   va_list   *x;  
   
   x = &args;
   return( va_arg( *x, int));
}
where I incur one pointer indirection due to syntax. I am still forming an opinion on that...

Comments (3)

Isn’t this exactly why va_copy() was introduced? I’d expect it to have zero overhead compared to the assignment with this implementation.

Nat! Author Profile Page:

Very good. I was totally unaware of va_copy. I should have been using that all along.

Nat! Author Profile Page:

Except, that it doesn't work for me. No technically va_copy it's OK. But the language lawyers specify:

Each invocation of va_copy() must be matched by a corresponding invocation of va_end() in the same function.

But the actual real life code, that I am using (now) is:

static void init_parse_context( parse_context *p, unichar *buf, unsigned int len,
va_list args, NSEnumerator *rover)
{
memset( p, 0, sizeof( parse_context));
p->buf = buf;
p->end = &buf[ len];

// used to be
// p->args = args;
// wants to be
// va_copy( p->args, args)
// has to be
p->args_p = &args;
p->rover = rover;
}

With the understanding that va_list is valid as long as the stack frame is valid, this used to be no problem. But I certainly can't put va_end at the end of the function, lest it really does something and does some cleanup code.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

About

This page contains a single entry from the blog posted on November 15, 2009 12:46 AM.

The previous post in this blog was The beginning of a bigger change ?.

The next post in this blog is A small x86_64 optimization brainteaser [with complete solution].

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 4.25