From owner-freebsd-i386@FreeBSD.ORG Sun Sep 14 20:00:11 2008 Return-Path: Delivered-To: freebsd-i386@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 847881065686 for ; Sun, 14 Sep 2008 20:00:11 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 3FC7C8FC13 for ; Sun, 14 Sep 2008 20:00:11 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.2/8.14.2) with ESMTP id m8EK0BkI006783 for ; Sun, 14 Sep 2008 20:00:11 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.2/8.14.1/Submit) id m8EK0BYE006782; Sun, 14 Sep 2008 20:00:11 GMT (envelope-from gnats) Resent-Date: Sun, 14 Sep 2008 20:00:11 GMT Resent-Message-Id: <200809142000.m8EK0BYE006782@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-i386@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Christoph Mallon Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B4E3E1065679 for ; Sun, 14 Sep 2008 19:56:42 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21]) by mx1.freebsd.org (Postfix) with ESMTP id A090D8FC19 for ; Sun, 14 Sep 2008 19:56:42 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.14.2/8.14.2) with ESMTP id m8EJugOg068064 for ; Sun, 14 Sep 2008 19:56:42 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.2/8.14.1/Submit) id m8EJug2W068063; Sun, 14 Sep 2008 19:56:42 GMT (envelope-from nobody) Message-Id: <200809141956.m8EJug2W068063@www.freebsd.org> Date: Sun, 14 Sep 2008 19:56:42 GMT From: Christoph Mallon To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: i386/127387: Inline assembler in x86 _start() in crt1.c only works by chance X-BeenThere: freebsd-i386@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: I386-specific issues for FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 14 Sep 2008 20:00:11 -0000 >Number: 127387 >Category: i386 >Synopsis: Inline assembler in x86 _start() in crt1.c only works by chance >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-i386 >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sun Sep 14 20:00:10 UTC 2008 >Closed-Date: >Last-Modified: >Originator: Christoph Mallon >Release: n/a >Organization: >Environment: n/a >Description: Disassembling _start() of a common binary shows this[0]: 08048450 <_start>: 8048450: 55 push %ebp 8048451: 89 e5 mov %esp,%ebp 8048453: 57 push %edi 8048454: 56 push %esi 8048455: 53 push %ebx 8048456: 83 ec 0c sub $0xc,%esp 8048459: 83 e4 f0 and $0xfffffff0,%esp 804845c: 8b 5d 04 mov 0x4(%ebp),%ebx 804845f: 89 d7 mov %edx,%edi [...] The last instruction shown is generated via inline assembler in src/lib/csu/i386-elf/crt1.c. It copies the rtld "cleanup" function pointer from %edx into a different register[1]. Just before the only declared parameter ist loaded from stack into %ebx. In the source file this instruction is below the inline assembler to load "cleanup", but of course the compiler is free to shuffle things around. Now the problematic part: The compiler chose %ebx as destination register. It could have chosen %edx, because nobody told him that there is a precious value in there. In fact there is no safe way to ensure that %edx is not destroyed before it is read in this function. I present a replacement, which does the ugly handling[2] in a small global asm block. [0] objdump -d $SOME_UNSTRIPPED_BINARY | $PAGER or just objdump -d /usr/lib/crt1.o | $PAGER [1] The used inline assembler statement is unnecessarily complicated, but that's another story. Simpler is asm("" : "=d" (cleanup));. [2] Other parts like fetching argc from the stack and aligning the stack via inline assembler are far beyond legal C, too. >How-To-Repeat: >Fix: See attachment. Patch attached with submission follows: Index: crt1.c =================================================================== --- crt1.c (Revision 183012) +++ crt1.c (Arbeitskopie) @@ -38,8 +38,6 @@ extern int _DYNAMIC; #pragma weak _DYNAMIC -typedef void (*fptr)(void); - extern void _fini(void); extern void _init(void); extern int main(int, char **, char **); @@ -55,35 +53,16 @@ char **environ; const char *__progname = ""; -static __inline fptr -get_rtld_cleanup(void) -{ - fptr retval; - -#ifdef __GNUC__ - __asm__("movl %%edx,%0" : "=rm"(retval)); -#else - retval = (fptr)0; /* XXXX Fix this for other compilers */ -#endif - return(retval); -} - /* The entry function. */ -void -_start(char *ap, ...) +static void +#ifdef __GNUC__ +__attribute__((regparm(3), noreturn, used)) +#endif +internal_start(int argc, void (*cleanup)(void), char *argv[]) { - fptr cleanup; - int argc; - char **argv; char **env; const char *s; -#ifdef __GNUC__ - __asm__("and $0xfffffff0,%esp"); -#endif - cleanup = get_rtld_cleanup(); - argv = ≈ - argc = *(long *)(void *)(argv - 1); env = argv + argc + 1; environ = env; if (argc > 0 && argv[0] != NULL) { @@ -110,4 +89,22 @@ exit( main(argc, argv, env) ); } -__asm__(".ident\t\"$FreeBSD$\""); +#ifdef __GNUC__ +__asm__( + ".text \n\t" + ".p2align 4,,15 \n" + ".globl _start \n\t" + ".type _start, @function\n" + "_start: \n\t" + "pushl %ebp \n\t" + "movl %esp, %ebp\n\t" + "andl $0xFFFFFFF0, %esp\n\t" // align stack + "movl 4(%ebp), %eax\n\t" // argc + /* edx already contains rtld cleanup */ + "leal 8(%ebp), %ecx\n\t" // argv + "call internal_start \n\t" + ".size _start, . - _start" +); +#endif + +__asm__(".ident\t\"$FreeBSD: src/lib/csu/i386-elf/crt1.c,v 1.15 2005/10/07 22:13:17 bde Exp $\""); >Release-Note: >Audit-Trail: >Unformatted: