Is it a va_arg bug in clang?

Hello,

I’m trying to use the clang3.7 to compile 64bits x86 code with Microsoft ABI in Ubuntu 64bit, but I find the va_arg get the wrong variable argument from the va_list. Below is my test code.

#include <stdio.h>

#include <stdarg.h>

void

attribute((ms_abi))

Foo_va_list (

int VaNum,

const char *Format,

)

{

va_list Marker;

long long Value;

va_start (Marker, Format);

for (int i = 0; i < VaNum; i++ ) {

Value = va_arg (Marker, int);

printf(“Value = 0x%llx\n”, Value);

}

va_end (Marker);

}

int main()

{

Foo_va_list (16, “0123456789abcdef= %x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x \n”, 0,1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf);

return 0;

}

The expected output are:

Value = 0x0

Value = 0x1

Value = 0x2

Value = 0x3

Value = 0x4

Value = 0x5

Value = 0x6

Value = 0x7

Value = 0x8

Value = 0x9

Value = 0xa

Value = 0xb

Value = 0xc

Value = 0xd

Value = 0xe

Value = 0xf

But the real output are:

Value = 0x0

Value = 0x1

Value = 0x2

Value = 0x3

Value = 0x4

Value = 0x5

Value = 0x0

Value = 0x1

Value = 0x2

Value = 0x3

Value = 0x4

Value = 0x5

Value = 0x6

Value = 0x7

Value = 0x8

Value = 0x9

After I remove the Microsoft ABI definition attribute((ms_abi)) above Foo_va_list () in the code, the output will become correct. I find GCC also have similar wrong behavior with attribute((ms_abi)). I don’t know how to make the attribute((ms_abi)) work correctly with va_arg. I appreciate if any suggestion.

Steven Shi

Intel\SSG\STO\UEFI Firmware

Tel: +86 021-61166522

iNet: 821-6522

For the variadic function error with AMD64 abi and windows calling convention on 64bits x86, I find it has been tracked in Bug 20847 (https://llvm.org/bugs/show_bug.cgi?id=20847) (http://reviews.llvm.org/D1622#inline-9345). Do we still plan to fix it?

You know, I meet exactly same va_arg mistake with llvm3.7 when I enable the Uefi firmware (http://www.uefi.org/) build with clang. The ms_abi is the Uefi firmware binary module standard interface. I really hope this bug fix can been checked in as soon as possible. If we cannot fix it in short time, could we offer a temporary fix patch based on llvm3.7?

For the variadic function error with AMD64 abi and windows calling
convention on 64bits x86, I find it has been tracked in Bug 20847 (
https://llvm.org/bugs/show_bug.cgi?id=20847) (
http://reviews.llvm.org/D1622#inline-9345). Do we still plan to fix it?

You know, I meet exactly same va_arg mistake with llvm3.7 when I enable
the Uefi firmware (http://www.uefi.org/) build with clang. The ms_abi is
the Uefi firmware binary module standard interface. I really hope this bug
fix can been checked in as soon as possible. If we cannot fix it in short
time, could we offer a temporary fix patch based on llvm3.7?

This is already fixed in clang trunk. Your code is rejected as follows:

<stdin>:15:17: error: 'va_start' used in Win64 ABI function
                va_start (Marker, Format);
                ^

You need to use __builtin_ms_va_list, __builtin_ms_va_start,
__builtin_ms_va_end to use ms_abi varargs semantics. (In particular, note
that __builtin_ms_va_list is a different type from va_list, so this can't
"just work" in the way you expect it to.)

Hi Richard,

Thank you for the info. I build my code in Ubuntu-64bits with simply commands: “clang X64.c”, then run “./a.out” to see the output. If I replace my va_list, va_start, va_arg va_end with __builtin_ms_va_list, __builtin_ms_va_start, __builtin_ms_va_arg, __builtin_ms_va_end, my code will build fail in Ubuntu with below message. Do you suggest I should build it in windows and not in Linux? Or did I miss any build option here? Appreciate if you could let me know the correct build steps.

jshi19@jshi19-Intel:/mnt/disk3$ clang X64.c

X64.c:12:2: error: unknown type name ‘__builtin_ms_va_list’; did you mean

‘__builtin_va_list’?

__builtin_ms_va_list Marker;

^~~~~~~~~~~~~~~~~~~~

__builtin_va_list

note: ‘__builtin_va_list’ declared here

X64.c:15:2: error: use of unknown builtin ‘__builtin_ms_va_start’

[-Wimplicit-function-declaration]

__builtin_ms_va_start (Marker, Format);

^

X64.c:17:11: error: use of unknown builtin ‘__builtin_ms_va_arg’

[-Wimplicit-function-declaration]

Value = __builtin_ms_va_arg (Marker, int);

^

X64.c:17:11: note: did you mean ‘__builtin_ms_va_start’?

X64.c:15:2: note: ‘__builtin_ms_va_start’ declared here

__builtin_ms_va_start (Marker, Format);

^

X64.c:17:40: error: expected expression

Value = __builtin_ms_va_arg (Marker, int);

^

X64.c:20:2: error: use of unknown builtin ‘__builtin_ms_va_end’

[-Wimplicit-function-declaration]

__builtin_ms_va_end (Marker);

^

X64.c:20:2: note: did you mean ‘__builtin_ms_va_arg’?

X64.c:17:11: note: ‘__builtin_ms_va_arg’ declared here

Value = __builtin_ms_va_arg (Marker, int);

^

5 errors generated.

Steven Shi

Intel\SSG\STO\UEFI Firmware

Tel: +86 021-61166522

iNet: 821-6522

You need a newer version of clang for these builtins.

Hi Richard,

I tried latest 3.7.1 release, the clang has same build failure and don’t know __builtin_ms_va_list at all. I compared the llvm trunk with 3.7.1 and find the trunk has a VA commit from Davis which is not included in the 3.7.1 release. So, I guess I need to directly build the latest trunk instead of the 3.7.1 release. (why 3.7.1 release doesn’t include this patch?)

commit 7e96f0f6fffbdebfdac238ae76cc3a791acfa23e

Author: Charles Davis cdavis5x@gmail.com

Make variable argument intrinsics behave correctly in a Win64 CC function.

Summary:

This change makes the variable argument intrinsics, llvm.va_start and

llvm.va_copy, and the va_arg instruction behave as they do on Windows

inside a CallingConv::X86_64_Win64 function. It’s needed for a Clang patch

I have to add support for GCC’s __builtin_ms_va_list constructs.

But when I try to configure the trunk build with cmake, the cmake report failures as below. I can pass configure the 3.7.1 release with the same command. Could you let me know the right configure or build steps for llvm trunk? Appreciate your continues help!

My cmake command:

cmake …/llvm -G “Unix Makefiles” -DCMAKE_BUILD_TYPE=“Release” -DLLVM_TARGETS_TO_BUILD=“X86” -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_CXX_COMPILER=“/usr/bin/g++” -DCMAKE_C_COMPILER=“/usr/bin/gcc”

cmake failure output:

… …

– Performing Test HAS_MAYBE_UNINITIALIZED

– Performing Test HAS_MAYBE_UNINITIALIZED - Success

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 6: /mnt/disk3/llvmtruck/llvm/au: not foundig.guess:

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 8: /mnt/disk3/llvmtruck/llvm/au: not foundig.guess:

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 28: /mnt/disk3/llvmtruck/llvm/a: not foundfig.guess:

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 29: /mnt/disk3/llvmtruck/llvm/a: not foundfig.guess:

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 40: /mnt/disk3/llvmtruck/llvm/a: not foundfig.guess:

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 42: /mnt/disk3/llvmtruck/llvm/a: not foundfig.guess:

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 54: /mnt/disk3/llvmtruck/llvm/a: not foundfig.guess:

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 65: /mnt/disk3/llvmtruck/llvm/a: not foundfig.guess:

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 68: /mnt/disk3/llvmtruck/llvm/a: not foundfig.guess:

/mnt/disk3/llvmtruck/llvm/autoconf/config.guess: 71: /mnt/disk3/llvmtruck/llvm/autoconf/config.guess: Syntax error: word unexpected (expecting “in”)

CMake Error at cmake/modules/GetHostTriple.cmake:24 (message):

Failed to execute /mnt/disk3/llvmtruck/llvm/autoconf/config.guess

Call Stack (most recent call first):

cmake/config-ix.cmake:331 (get_host_triple)

CMakeLists.txt:407 (include)

Steven Shi

Intel\SSG\STO\UEFI Firmware

Tel: +86 021-61166522

iNet: 821-6522

(why 3.7.1 release doesn’t include this patch?)

Dot releases contain only critical bug fixes. We don't backport every
change, you'll have to wait for 3.8.

Could you let me know the right configure or build steps for llvm trunk?
Appreciate your continues help!

There should be no difference between building 3.7 and trunk. Procedure
explained at http://clang.llvm.org/get_started.html should work. Make sure
your build directory is not inside the source tree. I'd start with "cmake
-G "Unix Makefiles" ../llvm -DCMAKE_BUILD_TYPE=Release" to make sure things
build correctly.

Hi Nikola,

Thank you. I can build successfully with svn repository, but the trunk in git repository cannot build. With the latest svn trunk 3.8, my code va_arg can works with ms_abi now, thank you anyway!

Steven Shi

Intel\SSG\STO\UEFI Firmware

Tel: +86 021-61166522

iNet: 821-6522