Mercurial > ecos
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
