This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

synthetic target -fstack-protector patch


This is an attempt to resolve the long-standing problem with gcc
-fstack-protector and the synthetic target, especially on Ubuntu
systems. It creates a new data structure matching the one provided by
glibc's thread support and places it at an appropriate location in the
address map. During startup, before any C code gets to run, an extra
system call is used to install this data structure in one of the x86
descriptor tables, and from then on the structure can be accessed
relative to the %gs register. One field in the TLS structure is
supposed to point at the base of the current thread stack, which is
how gcc's -fstack-protector performs its run-time stack overflow
checking.

Currently the stack base field is initialized to the start of RAM and
is never updated, so the stack overflow check should never fail.
However it should be possible to extend this such that the field gets
updated during a context switch. That way we can get stack overflow
checking in the synthetic target, especially if built with
-fstack-protector-all. It is going to be a little bit tricky, and the
interrupt stack will need attention as well,

There may still be problems if people are using up-to-date gcc with
old kernels that don't support the system call, but hopefully nobody
is going to be affected by that.

Bart

2009-08-11  Bart Veer  <bartv@ecoscentric.com>

	* src/tls.c: new module for TLS (thread local storage) support as
	expected by gcc.

	* cdl/hal_synth_i386.cdl, include/var_arch.h,
	include/pkgconf/mlt_synth_i386_rom.ldi, src/vectors.s: add TLS
	support.

Index: cdl/hal_synth_i386.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/i386linux/current/cdl/hal_synth_i386.cdl,v
retrieving revision 1.7
diff -u -p -r1.7 hal_synth_i386.cdl
--- cdl/hal_synth_i386.cdl	2 Feb 2009 17:56:43 -0000	1.7
+++ cdl/hal_synth_i386.cdl	11 Aug 2009 15:55:53 -0000
@@ -76,7 +76,7 @@ cdl_package CYGPKG_HAL_SYNTH_I386 {
         @echo >> $(notdir $@).deps
         @rm vectors.tmp
     }
-    compile       context.S syscall-i386-linux-1.0.S profile.c
+    compile       context.S syscall-i386-linux-1.0.S profile.c tls.c
 
     cdl_component CYG_HAL_STARTUP {
         display       "Startup type"
Index: include/var_arch.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/i386linux/current/include/var_arch.h,v
retrieving revision 1.5
diff -u -p -r1.5 var_arch.h
--- include/var_arch.h	29 Jan 2009 17:49:43 -0000	1.5
+++ include/var_arch.h	11 Aug 2009 15:56:10 -0000
@@ -11,7 +11,7 @@
 // ####ECOSGPLCOPYRIGHTBEGIN####                                            
 // -------------------------------------------                              
 // This file is part of eCos, the Embedded Configurable Operating System.   
-// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2009 Free Software Foundation, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under    
 // the terms of the GNU General Public License as published by the Free     
@@ -71,6 +71,24 @@ typedef struct 
     cyg_bool    interrupts;             // Are interrupts enabled for this thread?
 } HAL_SavedRegisters;
 
+// An additional structure used for per-thread data. This is not
+// actually part of the standard HAL. However gcc can generate code
+// which expects one of these structures to be accessible via
+// %gs:0, e.g. when -fstack-protector is enabled.
+//
+// This definition is based on one in the glibc sources.
+typedef struct _HAL_TLS_Data {
+    void*       tls_tcb;
+    void*       tls_dtv;
+    void*       tls_self;
+    int         tls_multiple_threads;
+    void*       tls_sysinfo;
+    void*       tls_stack_guard;
+    void*       tls_pointer_guard;
+    int         tls_gscope_flag;
+    int         tls_private_futex;
+    void*       tls_private_tm[5];
+} _HAL_TLS_Data;
 
 //-----------------------------------------------------------------------------
 // Bit manipulation routines. These are provided by the processor variant
Index: include/pkgconf/mlt_synth_i386_rom.ldi
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/i386linux/current/include/pkgconf/mlt_synth_i386_rom.ldi,v
retrieving revision 1.3
diff -u -p -r1.3 mlt_synth_i386_rom.ldi
--- include/pkgconf/mlt_synth_i386_rom.ldi	20 Nov 2005 16:21:18 -0000	1.3
+++ include/pkgconf/mlt_synth_i386_rom.ldi	11 Aug 2009 15:56:26 -0000
@@ -1,7 +1,3 @@
-// eCos memory layout - Fri Oct 20 08:40:39 2000
-
-// This is a generated file - do not edit
-
 #include <cyg/infra/cyg_type.inc>
 
 MEMORY
@@ -23,9 +19,12 @@ SECTIONS
     SECTION_eh_frame (rom, ALIGN (0x4), LMA_EQ_VMA)
     SECTION_rel__got (rom, ALIGN (0x1), LMA_EQ_VMA)
     SECTION_gcc_except_table (rom, ALIGN (0x1), LMA_EQ_VMA)
-    SECTION_data (ram, 0x02000000, LMA_EQ_VMA)
-    SECTION_sbss (ram, ALIGN (0x4), LMA_EQ_VMA)
-    SECTION_bss (ram, ALIGN (0x10), LMA_EQ_VMA)
+    .tls 0x02000000 : {
+        *(.tls.*)
+    } > ram 
+    SECTION_data (ram, 0x02000100,    LMA_EQ_VMA)
+    SECTION_sbss (ram, ALIGN (0x4) ,  LMA_EQ_VMA)
+    SECTION_bss (ram,  ALIGN (0x10),  LMA_EQ_VMA)
     CYG_LABEL_DEFN(__heap1) = ALIGN (0x10);
     SECTIONS_HEAP(ram, __heap1, 0x02800000)
     SECTIONS_END
Index: src/vectors.S
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/i386linux/current/src/vectors.S,v
retrieving revision 1.5
diff -u -p -r1.5 vectors.S
--- src/vectors.S	29 Jan 2009 17:49:43 -0000	1.5
+++ src/vectors.S	11 Aug 2009 15:56:43 -0000
@@ -72,6 +72,7 @@
 
         .file   "vectors.S"
 
+        .extern _hal_synth_user_desc
 	.extern	_linux_entry
         
         .data
@@ -97,5 +98,34 @@ _start:
         addl    %eax, %eax
         addl    %eax, %ebx
         movl    %ebx, cyg_hal_sys_environ
+
+        // Clear the frame pointer, to facilitate debugging
+        xorl    %ebp, %ebp
+
+        // Align the stack to a 16-byte boundary.
+        andl    $0xFFFFFFF0, %esp
+
+        // Set up the TLS section. This must be done before any
+        // C code gets to run, or -fstack-protector-all will fail.
         
+        // _hal_synth_user_desc is statically initialized in tls.c
+        movl    $_hal_synth_user_desc,%ebx
+        // Syscall 243, set_thread_area
+        movl    $0xf3, %eax
+        int     $0x80
+
+        // The syscall may have failed. That should only happen if running
+        // on an old kernel which predates set_thread_area(), in which case
+        // we are probably also using an old gcc which does not yet support
+        // -fstack-protector. There is no obvious way forward if we are trying
+        // to run an executable built with recent gcc on an old kernel.
+        test    %eax, %eax
+        jne     1f
+
+        // gs value = (_hal_synth_user_desc.ud_entry_number * 8) + 3
+        movl    _hal_synth_user_desc,%eax
+        lea     0x3(,%eax,8),%eax
+        mov     %eax,%gs
+        
+1:      
 	jmp	_linux_entry


Index: src/tls.c
===================================================================
RCS file: src/tls.c
diff -N src/tls.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/tls.c	11 Aug 2009 15:58:09 -0000
@@ -0,0 +1,128 @@
+//=============================================================================
+//
+//      tls.c
+//
+//      Support for the per-thread data expected by parts of gcc
+//
+//=============================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2009 Free Software Foundation, Inc.                  
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//=============================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    bartv
+// Contributors: bartv
+// Date:         2009-08-09
+//
+//####DESCRIPTIONEND####
+//=============================================================================
+
+#include <pkgconf/mlt_synth_i386_rom.h>
+#include <cyg/hal/hal_arch.h>
+
+// At the time of writing some parts of gcc assume thread-local storage as
+// provided by glibc. Of particular concern is -fstack-protector which is
+// enabled by default in some distros. Without matching target-side support
+// this causes synthetic target eCos applications to SEGV early on.
+
+// eCos only needs a single TLS data structure. This will need alignment
+// suitable for filling in an x86 descriptor table entry, so the linker
+// script places this structure right at the start of RAM.
+//
+// Installing a TLS area involves a system call set_thread_area().
+// This system call should be called from the assembler startup
+// before any C code starts running, or we'll run into problems with
+// -fstack-protector-all. However all relevant data can be
+// statically initialized.
+
+_HAL_TLS_Data _hal_synth_tls_data __attribute__ ((section (".tls._hal_synth_tls_data") )) = {
+    // The meaning of most of the tls fields is not clear, so just
+    // initialize them to 0 for now - until something else
+    // stops working.
+    .tls_tcb                = (void*) 0,
+    .tls_dtv                = (void*) 0,
+    .tls_self               = (void*) 0,
+    .tls_multiple_threads   = 0,
+    .tls_sysinfo            = (void*) 0,
+    // This is the important one for the purposes of -fstack-protector.
+    // The compiler assumes that %gs:0x14 points at the base of the stack.
+    // For now we just point at the start of RAM. It should be possible
+    // to update this during context switches and at the start of interrupt
+    // handling to get a partial implementation of stack overflow checking.
+    .tls_stack_guard        = (void*) CYGMEM_REGION_ram,
+
+    .tls_pointer_guard      = (void*) 0,
+    .tls_gscope_flag        = 0,
+    .tls_private_futex      = 0,
+    .tls_private_tm[0]      = (void*) 0,
+    .tls_private_tm[1]      = (void*) 0,
+    .tls_private_tm[2]      = (void*) 0,
+    .tls_private_tm[3]      = (void*) 0,
+    .tls_private_tm[4]      = (void*) 0
+};
+
+// The argument to set_thread_area() is not a _hal_synth_tls_data,
+// unfortunately. Instead it is a user_desc structure as per
+// <asm/ldt.h>.
+typedef struct _HAL_user_desc {
+    int             ud_entry_number;
+    unsigned long   ud_base_addr;
+    int             ud_limits;
+    int             ud_flags;
+} _HAL_user_desc;
+
+#define _HAL_USER_DESC_FLAGS_SEG_32BIT          (0x01 << 0)
+#define _HAL_USER_DESC_FLAGS_CONTENTS_MASK      (0x03 << 1)
+#define _HAL_USER_DESC_FLAGS_CONTENTS_SHIFT     1
+#define _HAL_USER_DESC_FLAGS_CONTENTS_DATA      (0x00 << 1)
+#define _HAL_USER_DESC_FLAGS_CONTENTS_STACK     (0x01 << 1)
+#define _HAL_USER_DESC_FLAGS_CONTENTS_CODE      (0x02 << 1)
+#define _HAL_USER_DESC_FLAGS_READ_EXEC_ONLY     (0x01 << 3)
+#define _HAL_USER_DESC_FLAGS_LIMIT_IN_PAGES     (0x01 << 4)
+#define _HAL_USER_DESC_FLAGS_SEG_NOT_PRESENT    (0x01 << 5)
+#define _HAL_USER_DESC_FLAGS_USEABLE            (0x01 << 6)
+
+
+// And it can also be statically initialized. There is no need to worry
+// about alignment this time. Note that one of the fields gets updated
+// by the system call so this cannot be a const structure.
+
+_HAL_user_desc   _hal_synth_user_desc = {
+    .ud_entry_number        = -1,   // Let the kernel pick the descriptor table entry
+    .ud_base_addr           = (unsigned long) &_hal_synth_tls_data,
+    .ud_limits              = 1,    // A single page will do
+    .ud_flags               = (_HAL_USER_DESC_FLAGS_SEG_32BIT       |
+                               _HAL_USER_DESC_FLAGS_CONTENTS_DATA   |
+                               _HAL_USER_DESC_FLAGS_READ_EXEC_ONLY  |
+                               _HAL_USER_DESC_FLAGS_LIMIT_IN_PAGES  |
+                               _HAL_USER_DESC_FLAGS_USEABLE)
+};


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]