X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f X-Recipient: djgpp-workers AT delorie DOT com X-Authenticated: #27081556 X-Provags-ID: V01U2FsdGVkX1/O0K8k9UfOwGcZMx6vTfoO9Fg+W7Us5iOrzZGpKQ NX8y/yxDw4XY0T Message-ID: <51C0A3B4.4010205@gmx.de> Date: Tue, 18 Jun 2013 20:15:16 +0200 From: Juan Manuel Guerrero User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:16.0) Gecko/20121025 Thunderbird/16.0.2 MIME-Version: 1.0 To: djgpp-workers AT delorie DOT com Subject: Autoresolving __[de]register_frame_info symbols in DXE modules when required. Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit X-Y-GMX-Trusted: 0 Reply-To: djgpp-workers AT delorie DOT com Starting with gcc 4.6.1, the C compiler inserts .eh_frames into the object files. This has the consequence that dxe3gen links init and fini code into DXE module that calls the __[de]register_frame_info functions. This either breaks the module generation due to unresolved symbols or creates broken modules that do not work at run-time. The patch below will allow to autoresolve these symbols iff it is recognized that there is no exception handling support by the language or compiler used. If the object file has different e_value for the ___EH_FRAME_BEGIN__ and ___EH_FRAME_END__ symbols, then the .eh_frame of the original object file (not the dxe_tmp.o) will be scanned for its CIE record. If the CIE is valid and it has a 'zR' augmentation string, it will be assumed that the programing language or compiler does not really provide exception handling support and both symbols will be autoresolved. Any other augmentation string will inhibit the autoresolve process of the symbols and dxe3gen will abort with the usual error message about unresolved symbols. To read the first few fields of the CIE, the dwarf_cie structure is used as defined in unwind-dw2-fde.h of gcc-4.6.1. If this structure changes, the code will need to be adjusted. The as valid recognized CIE ID and augmentation strings are those defined by LSB-Core-generic.pdf. All files that will be linked into a DXE module will be scanned for the 'zR' augmentation string. If a single file has an augmentation string different from 'zR' then the symbols will not be autoresolved and the user will have to link the application with the appropriate library that will provide working versions of __[de]register_frame_info. This is libgcc.a for g++ when exceptions are enabled. That the 'zR' augmentation string is the right choice is a information that I gained by trial-and-error. To autoresolve the symbols two new init and fini files are provided. This are copies of those that call the functions, but dummy functions have been added, so the symbols can be resolved by the linker. With the proposed modifications the dxe test suite of the library passes again without needing to modify neither the C and C++ code nor the Makefile. As usual, suggestions, objections and comments are welcome. Regards, Juan M. Guerrero cvs ci -m"Info about dxe3gen added." djgpp/src/docs/kb/wc204.txi cvs ci -m"Support autoresolving __[de]register_frame_info in DXE moduls if the programing language does not provide EH support." djgpp/src/dxe/dxe3gen.c cvs ci -m"Support autoresolving __[de]register_frame_info in DXE moduls if the programing language does not provide EH support." djgpp/src/dxe/makefile cvs add djgpp/src/dxe/fini4.S cvs add djgpp/src/dxe/fini5.S cvs add djgpp/src/dxe/init4.S cvs add djgpp/src/dxe/init5.S cvs ci -m"Support autoresolving __[de]register_frame_info in DXE moduls if the programing language does not provide EH support." djgpp/src/dxe/fini4.S cvs ci -m"Support autoresolving __[de]register_frame_info in DXE moduls if the programing language does not provide EH support." djgpp/src/dxe/fini5.S cvs ci -m"Support autoresolving __[de]register_frame_info in DXE moduls if the programing language does not provide EH support." djgpp/src/dxe/init4.S cvs ci -m"Support autoresolving __[de]register_frame_info in DXE moduls if the programing language does not provide EH support." djgpp/src/dxe/init5.S Logging in to :pserver:anonymous AT cvs DOT delorie DOT com:2401/cvs/djgpp ? djgpp/src/dxe/fini4.S ? djgpp/src/dxe/fini5.S ? djgpp/src/dxe/init4.S ? djgpp/src/dxe/init5.S Index: djgpp/src/docs/kb/wc204.txi =================================================================== RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v retrieving revision 1.207 diff -p -U 5 -r1.207 wc204.txi --- djgpp/src/docs/kb/wc204.txi 23 Mar 2013 11:54:58 -0000 1.207 +++ djgpp/src/docs/kb/wc204.txi 16 Jun 2013 13:01:43 -0000 @@ -1234,14 +1234,19 @@ function from the Windows 95 long filena @code{AX} register after return from the API function call. Depending on the function type, the function will ignore, fail or fall back on the corresponding SFN API function if the LFN API function is not provided by the @acronym{LFN} driver used. @pindex dxe3gen AT r{, resolving @code{__[de]register_frame_info} symbols in @acronym{DXE} moduls} -When dxe3gen detects that one of the object files that shall be linked into a -@acronym{DXE} modul contains a @code{.eh_frame} section it automatically links -the modul with @code{libc.a} to resolve both @code{__register_frame_info} and -@code{__deregister_frame_info} symbols. +The dxe3gen program inspects the @code{Augmentation String} of the @code{CIE} record +contained in the @code{.eh_frame} section to decide if both @code{__register_frame_info} +and @code{__deregister_frame_info} symbols that exist in the object file shall be +auto-resolved or not. They will be resolved by the dxe3gen program if the used +programing language does not support exception handling like @acronym{C}. They will not +be resolved if the used programing language supports exception handling like +@acronym{C++} and the exception handling has been enabled with an option like +@option{-fexceptions}. In this case the application has to be linked with +@file{libgcc.a} to resolve both symbols. @findex STYP_NRELOC_OVFL AT r{, new flag bit added to @code{s_flags} of @acronym{COFF} section header} The @code{s_flags} of the @acronym{COFF} section header now honors the new @code{STYP_NRELOC_OVFL} bit that signals that the section contains extended relocations and that the @code{s_nreloc} counter has overflown. The bit set in case of overflow by @code{STYP_NRELOC_OVFL} is @code{0x01000000}. Index: djgpp/src/dxe/dxe3gen.c =================================================================== RCS file: /cvs/djgpp/djgpp/src/dxe/dxe3gen.c,v retrieving revision 1.17 diff -p -U 5 -r1.17 dxe3gen.c --- djgpp/src/dxe/dxe3gen.c 16 Jun 2013 02:40:10 -0000 1.17 +++ djgpp/src/dxe/dxe3gen.c 18 Jun 2013 17:02:15 -0000 @@ -176,11 +176,11 @@ /* Always include local copies of sys/dxe.h and coff.h because of * NATIVE_TYPES stuff. */ #include "../../include/sys/dxe.h" #include "../../include/coff.h" -#define VERSION "1.0.2" +#define VERSION "1.0.3" #define TEMP_BASE "dxe_tmp" /* 7 chars, 1 char suffix */ #define TEMP_O_FILE TEMP_BASE".o" #define TEMP_S_FILE TEMP_BASE".s" @@ -190,10 +190,14 @@ #define IS_DIR_SEPARATOR(path) (IS_SLASH(path) || ((path) == ':')) #define NUMBER_OF_LINKER_ARGS 10 #define NUMBER_OF_ADDITIONAL_LOADED_LIBS 0 +#define IS_VALID_CIE(id) ((id) == 0) +#define IS_zR_AUGMENTATION(s) (s[0] == 'z' && s[1] == 'R' && s[2] == '\0') + + typedef enum { FALSE = 0, TRUE = !FALSE } BOOL; @@ -206,32 +210,45 @@ static #include "fini1.h" static #include "fini2.h" static #include "fini3.h" +static +#include "fini4.h" +static +#include "fini5.h" static #include "init1.h" static #include "init2.h" static #include "init3.h" +static +#include "init4.h" +static +#include "init5.h" static struct { void *data; int size; -} inits[3] = { +} inits[5] = { {init1, sizeof(init1)}, {init2, sizeof(init2)}, - {init3, sizeof(init3)} -}, finis[3] = { + {init3, sizeof(init3)}, + {init4, sizeof(init4)}, + {init5, sizeof(init5)} +}, finis[5] = { {fini1, sizeof(fini1)}, {fini2, sizeof(fini2)}, - {fini3, sizeof(fini3)} + {fini3, sizeof(fini3)}, + {fini4, sizeof(fini4)}, + {fini5, sizeof(fini5)} }; + /* Command-line options */ static struct { BOOL legacy; /* legacy DXE1 */ BOOL unresolved; /* allow unresolved symbols in output */ @@ -559,10 +576,149 @@ static int my_spawn(const char **argv) return system(cmd); } +/* Desc: check if the augmentation string is different from 'zR' + * in on of the object files that will be linked into the DXE file. + * If the augmentation string in the CIE is different to zR, it is + * assumed that the programing language offers exception handling + * and the [de]register info symbols must be resolved by linking + * the application with a language/compiler specific library like + * libgcc that will provide working version of the __[de]register_frame_info + * functions. Else the symbols will be autoresolved using the + * dummy functions compiled into this program. + * + * In : linker command line to provide list of object files to scan + * Out : TRUE if different from 'zR' augmentation else FALSE + * + * Note: - + */ +static BOOL have_EH_support(const char *argv[]) +{ + BOOL found_zR_augmentation = FALSE; + int i; + + for (i = 0; argv[i]; i++) + { + const char *dot = strrchr(argv[i], '.'); + + if (dot && !strcasecmp(dot, ".o") && strcasecmp(dot - sizeof TEMP_BASE + 1, TEMP_O_FILE)) + { + FILE *f = fopen(argv[i], "rb"); + + if (f == NULL) + { + fprintf(stderr, "%s: cannot open object file `%s' for reading\n", progname, argv[i]); + exit(-2); + } + else + { + FILHDR fh; + SYMENT *sym; + char *strings; + ULONG32 stsz; + unsigned int n; + + /* Read file header */ + fread(&fh, FILHSZ, 1, f); + + /* Read all symbols */ + sym = (SYMENT *)malloc(fh.f_nsyms * sizeof(SYMENT)); + fseek(f, fh.f_symptr, SEEK_SET); + fread(sym, SYMESZ, fh.f_nsyms, f); + + /* Read symbol name table */ + fread(&stsz, sizeof(stsz), 1, f); + strings = (char *)malloc(stsz); + fread(strings + 4, 1, stsz - 4, f); + strings[0] = 0; + + /* Find .eh_frame section */ + for (found_zR_augmentation = TRUE, n = 0; n < fh.f_nsyms; n += 1 + sym[n].e_numaux) + { + char tmp[E_SYMNMLEN + 1], *name; + + if (sym[n].e.e.e_zeroes) + { + memcpy(tmp, sym[n].e.e_name, E_SYMNMLEN); + tmp[E_SYMNMLEN] = 0; + name = tmp; + } + else + name = strings + sym[n].e.e.e_offset; + + if (!strcmp(name, ".eh_frame")) + { + SCNHDR eh_frame_scnhdr; + + /* Skip file header, optional header and all other section + headers existing before the .eh_frame section header */ + fseek(f, FILHSZ + fh.f_opthdr + (sym[n].e_scnum - 1) * (size_t)SCNHSZ, SEEK_SET); + + /* Read the .eh_frame section header and + extract the CIE (Common Information Entry) */ + if (fread(&eh_frame_scnhdr, (size_t)SCNHSZ, 1, f) == 1 + && !fseek(f, eh_frame_scnhdr.s_scnptr, SEEK_SET)) + { + /* + * To read the first few fields of the CIE record + * the struct dwarf_cie as defined in unwind-dw2-fde.h + * of gcc 4.6.1 is used. If this structure changes + * then this code will need to be adjusted accordingly. + * For a reference about the possible values of the + * augmentation string look at LSB-Core-generic.pdf. + */ + + + typedef int sword __attribute__ ((mode (SI))); + typedef unsigned int uword __attribute__ ((mode (SI))); + typedef unsigned int uaddr __attribute__ ((mode (pointer))); + typedef int saddr __attribute__ ((mode (pointer))); + typedef unsigned char ubyte; + + struct dwarf_cie + { + uword length; + sword CIE_id; + ubyte version; + unsigned char augmentation[]; + } __attribute__ ((packed, aligned (__alignof__ (void *)))); + + + /* If it is a CIE, read the augmentation string */ + struct dwarf_cie cie; + fread(&cie, sizeof(cie), 1, f); + if (IS_VALID_CIE(cie.CIE_id) && !IS_zR_AUGMENTATION(cie.augmentation)) + { + /* + * At least one of the object files linked into + * the DXE module requires exception handling. + * The application must be linked with libgcc.a + * to provide the required frame unwinding functionality. + * Stop checking other object files. + */ + found_zR_augmentation = FALSE; + break; + } + } + } + } + + free(strings); + free(sym); + } + + fclose(f); + } + } + + return !found_zR_augmentation; +} + + + /* Desc: run linker to obtain relocatable output * * In : linker command line, ptr to store output header * Out : file ptr of resulting file * @@ -604,10 +760,11 @@ static FILE *run_ld(const char *argv[], ULONG32 stsz; SYMENT *sym; char *strings; long int frame_begin = -1, frame_end = -1; long int first_ctor = -1, last_ctor = -1, first_dtor = -1, last_dtor = -1; + BOOL resolve_register_deregister_info_symbols = FALSE; int init, fini; /* Read all symbols */ sym = (SYMENT *)malloc(fh->f_nsyms * sizeof(SYMENT)); @@ -635,10 +792,12 @@ static FILE *run_ld(const char *argv[], if (!strcmp(name, "___EH_FRAME_BEGIN__")) frame_begin = sym[i].e_value; else if (!strcmp(name, "___EH_FRAME_END__")) frame_end = sym[i].e_value; + else if (!strcmp(name, ".eh_frame")) + resolve_register_deregister_info_symbols = !have_EH_support(argv); else if (!strcmp(name, "djgpp_first_ctor")) first_ctor = sym[i].e_value; else if (!strcmp(name, "djgpp_last_ctor")) last_ctor = sym[i].e_value; else if (!strcmp(name, "djgpp_first_dtor")) @@ -646,19 +805,20 @@ static FILE *run_ld(const char *argv[], else if (!strcmp(name, "djgpp_last_dtor")) last_dtor = sym[i].e_value; } - /* 3 = ctor + frame + /* + * 3 = ctor + frame * 2 = frame * 1 = ctor * 0 = */ if (frame_begin != frame_end) { - init = (first_ctor != last_ctor) ? 3 : 2; - fini = (first_dtor != last_dtor) ? 3 : 2; + init = resolve_register_deregister_info_symbols ? (first_ctor != last_ctor) ? 5 : 4 : (first_ctor != last_ctor) ? 3 : 2; + fini = resolve_register_deregister_info_symbols ? (first_ctor != last_ctor) ? 5 : 4 : (first_ctor != last_ctor) ? 3 : 2; } else { init = (first_ctor != last_ctor) ? 1 : 0; fini = (first_dtor != last_dtor) ? 1 : 0; Index: djgpp/src/dxe/makefile =================================================================== RCS file: /cvs/djgpp/djgpp/src/dxe/makefile,v retrieving revision 1.7 diff -p -U 5 -r1.7 makefile --- djgpp/src/dxe/makefile 14 May 2003 02:33:50 -0000 1.7 +++ djgpp/src/dxe/makefile 16 Jun 2013 13:01:44 -0000 @@ -1,5 +1,6 @@ +# Copyright (C) 2013 DJ Delorie, see COPYING.DJ for details # Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details # Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details # Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details # Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details @@ -29,10 +30,10 @@ $(BIN)/dxegen.exe : $(HOSTBIN)/stubify.e $(BIN)/dxe3res.exe : $(C) dxe3res.o $(L) $(LINK) $(EXE) -$(HOSTBIN)/dxegen.exe : dxe3gen.c init1.h init2.h init3.h fini1.h fini2.h fini3.h +$(HOSTBIN)/dxegen.exe : dxe3gen.c init1.h init2.h init3.h init4.h init5.h fini1.h fini2.h fini3.h fini4.h fini5.h $(GCC) -DDXE_LD=\"$(CROSS_LD)\" dxe3gen.c -o $@ clean :: @-$(MISC) rm *.o *.h $(HOSTBIN)/dxegen.exe diff -aprNU5 --no-dereference djgpp.orig/src/dxe/fini4.S djgpp/src/dxe/fini4.S --- djgpp.orig/src/dxe/fini4.S 1970-01-01 00:00:00 +0000 +++ djgpp/src/dxe/fini4.S 2013-06-16 14:06:38 +0000 @@ -0,0 +1,24 @@ +/* + * DXE3: frame info deregistration + * + * Copyright (C) 2002 - Borca Daniel + * Email : dborca AT yahoo DOT com + * Web : http://www.geocities.com/dborca + */ + + + .text + + .p2align 2,,3 + .globl _fini +_fini: + pushl $___EH_FRAME_BEGIN__ + call ___deregister_frame_info + popl %eax + ret + +___deregister_frame_info: + pushl %ebp + movl %esp, %ebp + popl %ebp + ret diff -aprNU5 --no-dereference djgpp.orig/src/dxe/fini5.S djgpp/src/dxe/fini5.S --- djgpp.orig/src/dxe/fini5.S 1970-01-01 00:00:00 +0000 +++ djgpp/src/dxe/fini5.S 2013-06-16 14:06:38 +0000 @@ -0,0 +1,34 @@ +/* + * DXE3: destruction + frame info deregistration + * + * Copyright (C) 2002 - Borca Daniel + * Email : dborca AT yahoo DOT com + * Web : http://www.geocities.com/dborca + */ + + + .text + + .p2align 2,,3 + .globl _fini +_fini: + pushl %ebx + movl $djgpp_first_dtor, %ebx + 0: + cmpl $djgpp_last_dtor, %ebx + jnb 1f + call *(%ebx) + addl $4, %ebx + jmp 0b + 1: + popl %ebx + pushl $___EH_FRAME_BEGIN__ + call ___deregister_frame_info + popl %eax + ret + +___deregister_frame_info: + pushl %ebp + movl %esp, %ebp + popl %ebp + ret diff -aprNU5 --no-dereference djgpp.orig/src/dxe/init4.S djgpp/src/dxe/init4.S --- djgpp.orig/src/dxe/init4.S 1970-01-01 00:00:00 +0000 +++ djgpp/src/dxe/init4.S 2013-06-16 14:06:38 +0000 @@ -0,0 +1,28 @@ +/* + * DXE3: frame info registration + * + * Copyright (C) 2002 - Borca Daniel + * Email : dborca AT yahoo DOT com + * Web : http://www.geocities.com/dborca + */ + + + .text + + .p2align 2,,3 + .globl _init +_init: + pushl $eh_frame + pushl $___EH_FRAME_BEGIN__ + call ___register_frame_info + popl %eax + popl %edx + ret + +___register_frame_info: + pushl %ebp + movl %esp, %ebp + popl %ebp + ret + +.lcomm eh_frame, 32 diff -aprNU5 --no-dereference djgpp.orig/src/dxe/init5.S djgpp/src/dxe/init5.S --- djgpp.orig/src/dxe/init5.S 1970-01-01 00:00:00 +0000 +++ djgpp/src/dxe/init5.S 2013-06-16 14:06:38 +0000 @@ -0,0 +1,38 @@ +/* + * DXE3: frame info registration + construction + * + * Copyright (C) 2002 - Borca Daniel + * Email : dborca AT yahoo DOT com + * Web : http://www.geocities.com/dborca + */ + + + .text + + .p2align 2,,3 + .globl _init +_init: + pushl $eh_frame + pushl $___EH_FRAME_BEGIN__ + call ___register_frame_info + popl %eax + popl %edx + pushl %ebx + movl $djgpp_first_ctor, %ebx + 0: + cmpl $djgpp_last_ctor, %ebx + jnb 1f + call *(%ebx) + addl $4, %ebx + jmp 0b + 1: + popl %ebx + ret + +___register_frame_info: + pushl %ebp + movl %esp, %ebp + popl %ebp + ret + +.lcomm eh_frame, 32