Community
Participate
Working Groups
In printfExtend we have an assignment va_list va = *pva; where pva is a va_list pointer. This works on target where va_list is char*, so we assign (char*) *pva to char* va, which is valid. However, on some targets va_list is struct Somestruct[1], so we have struct someStruct va[1] = *pva, where pva is a pointer to an array. This doesn't work because va[1] can be initialized only by a literal array. We could check if va_copy is defined and use it, or try to remove the need for copying. More info: http://www.velocityreviews.com/forums/t437602-varargss-doubt.html http://e2e.ti.com/support/embedded/f/355/p/118367/421343.aspx#421343
It appears that 64-bit Linux targets require more than a simple pointer for va_list. So, in the interest of performance, a va_list is often typedef'd to be an array consisting of a single element rather than a simple pointer. Making it an array means that when passing a va_list to a function, only the address of the first element array is passed _not_ the array itself. This also has the consequence that any function that's passed a va_list _must never_ take the address of this parameter thinking that they have a pointer to a va_list. For example, the following code is broken void doPrint(char *fmt, va_list *pva) { /* use *pva as a va_list */ ... va_arg(*pva, ...); } void vprint(char *fmt, va_list va) { /* BUG: if va_list is an array type, &va doesn't point to a va_list!! */ doPrint(fmt, &va); } For a nice discussion of the issue see comments 10-14 of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14557. The accepted solution to the issue is to use the C99 macro va_copy() to initialize a new va_list, pass a pointer to the initialized va_list, _and_ call va_end() to finalize use of the new va_list. For example, a portable vprint() can be written as follows: void vprint(char *fmt, va_list va) { va_list nva; va_copy(nva, va); doPrint(fmt, &nva); va_end(nva); } However, if the reason for defining a doPrint() to take a va_list* is to enable it to modify the original va_list, there is no need to take it's address in the first place! The code above can be written as just void doPrint(char *fmt, va_list va) { /* updates callers va list!!!! */ ... va_arg(va, ...); } void vprint(char *fmt, va_list va) { doPrint(fmt, va); } Notice that the type signature of doPrint() has to change.
fixed in xdc-A41 (to be included in xdctools 3.30.02)
First I replicated the problem with the target Linux86_64 by adding platformprod-t42 to the package path. I also used 4.4.6 Gnu compiler configured with 64-bit support. With that setup, XDCtools 3.30.01 reports the following error when building an example: package/cfg/Mod_p86U.c: In function ‘xdc_runtime_System_printfExtend__I’: package/cfg/Mod_p86U.c:766: error: invalid initializer package/cfg/Mod_p86U.c:846: error: incompatible types when assigning to type ‘VaList’ from type ‘struct __va_list_tag *’ package/cfg/Mod_p86U.c:859: error: incompatible types when assigning to type ‘va_list’ from type ‘struct __va_list_tag *’ package/cfg/Mod_p86U.c:900: error: incompatible types when assigning to type ‘VaList’ from type ‘struct __va_list_tag *’ After switching to 3.30.02.44, with the same target and the same example, the build completes without errors.
- shipped in XDCtools 3.30.02.44