changeset 2901:b64cee69f7e3

Add TLS support to avoid problems with gcc -fstack-protector
author bartv
date Tue, 11 Aug 2009 16:00:29 +0000
parents 7e08602b099e
children c23173de14a8
files packages/hal/synth/i386linux/current/ChangeLog packages/hal/synth/i386linux/current/cdl/hal_synth_i386.cdl packages/hal/synth/i386linux/current/include/pkgconf/mlt_synth_i386_rom.ldi packages/hal/synth/i386linux/current/include/var_arch.h packages/hal/synth/i386linux/current/src/tls.c packages/hal/synth/i386linux/current/src/vectors.S
diffstat 6 files changed, 193 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/packages/hal/synth/i386linux/current/ChangeLog
+++ b/packages/hal/synth/i386linux/current/ChangeLog
@@ -1,3 +1,12 @@
+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.
+
 2009-01-31  Bart Veer <bartv@ecoscentric.com>
 
 	* cdl/hal_synth_i386.cdl: update compiler flags for gcc 4.x
--- a/packages/hal/synth/i386linux/current/cdl/hal_synth_i386.cdl
+++ b/packages/hal/synth/i386linux/current/cdl/hal_synth_i386.cdl
@@ -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"
--- a/packages/hal/synth/i386linux/current/include/pkgconf/mlt_synth_i386_rom.ldi
+++ b/packages/hal/synth/i386linux/current/include/pkgconf/mlt_synth_i386_rom.ldi
@@ -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
--- a/packages/hal/synth/i386linux/current/include/var_arch.h
+++ b/packages/hal/synth/i386linux/current/include/var_arch.h
@@ -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
new file mode 100644
--- /dev/null
+++ b/packages/hal/synth/i386linux/current/src/tls.c
@@ -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)
+};
--- a/packages/hal/synth/i386linux/current/src/vectors.S
+++ b/packages/hal/synth/i386linux/current/src/vectors.S
@@ -72,6 +72,7 @@
 
         .file   "vectors.S"
 
+        .extern _hal_synth_user_desc
 	.extern	_linux_entry
         
         .data
@@ -97,5 +98,34 @@ cyg_hal_sys_environ:
         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