From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mout02.posteo.de (mout02.posteo.de [185.67.36.66]) by sourceware.org (Postfix) with ESMTPS id 2030B385802B for ; Thu, 6 Jan 2022 21:31:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2030B385802B Received: from submission (posteo.de [89.146.220.130]) by mout02.posteo.de (Postfix) with ESMTPS id DE857240105 for ; Thu, 6 Jan 2022 22:31:48 +0100 (CET) Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4JVKLD2FLGz9rxP for ; Thu, 6 Jan 2022 22:31:47 +0100 (CET) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII; format=flowed Content-Transfer-Encoding: 7bit Date: Thu, 06 Jan 2022 21:31:47 +0000 From: mihaidavid@posteo.net To: gcc-help@gcc.gnu.org Subject: Seemingly wrong generated code for a function with inline assembly Message-ID: <8a370886b88b0c37df3c7af7e1aab277@posteo.net> X-Spam-Status: No, score=-3.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-help@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-help mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 06 Jan 2022 21:31:51 -0000 Hello, For context, I'm writing a function as part of a Linux kernel module (x86_64), its aim is to wrap a cpu instruction related to virtualization technology, namely, VMREAD (part of Intel VMX / Intel VT-x). The generated assembly code for the function seems to lack the initialization of a local variable to 0 (`int _retval`). Here's the C code (you can ignore the lines with the `/* IGNORE */` comment at the end, the same behavior is observed with or without them). My intention is for _retval to remain 0 after the asm block iff vmread is successful (i.e. `ja 3f` is taken, jumping out of the asm block with _retval remaining to its initial value of 0). ``` c static noinline unsigned long __cpu_vmread(unsigned long field, int *retval) { unsigned long val; int _retval = 0; // IMPORTANT TODO: TEST FAULTING!!! MAYBE LABELS ARE WRONG! asm volatile( "1: vmread %[field], %[val]\n\t" " ja 3f\n\t" /* success! jump out of asm */ /* VMfail, set ret to -2 and jump out of asm */ " mov $-2, %[_retval]\n\t" " jmp 3f\n\t" /* fault, set ret to -1 and fall out of asm */ /* IGNORE */ "2: mov $-1, %[_retval]\n\t" /* IGNORE */ "3:\n\t" _ASM_EXTABLE(1b, 2b) /* IGNORE */ : [val] "=rm" (val), [_retval] "=rm" (_retval) : [field] "r" (field) : "cc" ); *retval = _retval; return val; } ``` Here's the generated assembly for the function (objdump): ``` assembly 7 0000000000000000 <__cpu_vmread>: 8 0: 0f 78 f8 vmread %rdi,%rax 9 3: 77 0c ja 11 <__cpu_vmread+0x11> 10 5: bf fe ff ff ff mov $0xfffffffe,%edi 11 a: eb 05 jmp 11 <__cpu_vmread+0x11> 12 c: bf ff ff ff ff mov $0xffffffff,%edi 13 11: 89 3e mov %edi,(%rsi) // *retval = _retval 14 13: c3 retq ``` As you can see, the compiler decided that _retval should be allocated in register %edi (see the `mov $-1/$-2, $[_retval]` instructions) but nowhere is it initialized to 0 as the declaration says, so if `ja` is taken, _retval is _undefined_ with a garbage value (I checked with the debugger), but it should actually be 0. To solve this I added an inline instruction before vmread to initialize _retval to 0 and it works, but it still baffles me why the compiler doesn't make sure _retval is initialized to 0 since it says so in its declaration. Maybe (likely) I'm just missing something and this is actually expected behavior but it could also be a bug in gcc, I'd appreciate it if someone could shed some light. Could it have something to do with the optimization of the function's epilogue? The -O is -O2, the buildsystem is the standard one for linux modules (kernel 5.10.7) and the only added cc options are `-g -DDEBUG`. gcc version is: `gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0` Here are some things I tried, with no result: * initializing _retval to another value instead of 0 * making the function inline, same happens at the inline sites * removing `static noinline` altogether * changing the optimization level to -O1 Thanks, - Horia Mihai David (hMihaiDavid)