www.digitalmars.com         C & C++   DMDScript  

D.gnu - Exceptions in ARM

reply "Timo Sintonen" <t.sintonen luukku.com> writes:
I started to update minlibd with gdc head from last saturday. 
While testing if exceptions work, the program just stops and does 
not reach catch or abort.

Before investigating further, I want to ask the status of arm 
exceptions: are they known to work, known not to work or is the 
status just unknown?

Does anybody know if there are any good articles of exceptions 
and unwinding in gcc or in general?
Jan 01 2014
next sibling parent reply Iain Buclaw <ibuclaw gdcproject.org> writes:
On 1 Jan 2014 14:05, "Timo Sintonen" <t.sintonen luukku.com> wrote:
 I started to update minlibd with gdc head from last saturday. While
testing if exceptions work, the program just stops and does not reach catch or abort.
 Before investigating further, I want to ask the status of arm exceptions:
are they known to work, known not to work or is the status just unknown?
 Does anybody know if there are any good articles of exceptions and
unwinding in gcc or in general?

How are exceptions implemented in minilibd? I assume that you don't
use/copy from the gdc compiler runtime folders (rt.* and gcc.*)
Jan 01 2014
next sibling parent "Timo Sintonen" <t.sintonen luukku.com> writes:
On Wednesday, 1 January 2014 at 15:19:01 UTC, Iain Buclaw wrote:
 On 1 Jan 2014 14:05, "Timo Sintonen" <t.sintonen luukku.com> 
 wrote:
 I started to update minlibd with gdc head from last saturday. 
 While
testing if exceptions work, the program just stops and does not reach catch or abort.
 Before investigating further, I want to ask the status of arm 
 exceptions:
are they known to work, known not to work or is the status just unknown?
 Does anybody know if there are any good articles of exceptions 
 and
unwinding in gcc or in general?

 How are exceptions implemented in minilibd? I assume that you 
 don't
 use/copy from the gdc compiler runtime folders (rt.* and gcc.*)
I do not have my own code here. I just add those files that are needed to link the test program. Currently I have rt/deh.d, gcc/deh.d, gcc/unwind/pe.d, gcc/unwind/arm.d and core/exception.d Meanwhile I found an exception abi documentation from arm: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf and now I know a little how this is supposed to work. By looking the asm I think that at the throw point it generates the exception object and then the unwind_control_block struct and then calls _Unwind_Resume. The unwind tables have already been in linker script. Then the unwind system should at some point call the personality functions in gcc/deh.d. Maybe I have to check if there is meaningful data in the unwind tables and if the personality functions ever get called.
Jan 01 2014
prev sibling parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
I have fond one thing that confuses me. I have defined 
ARM_EABI_UNWINDER but gcc/deh.d has checks for 
GNU_ARM_EABI_Unwinder. Is this what I should have? When using 
this I get an error in line 116: static assert ( 8 == 4 ) is 
false.
Jan 01 2014
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Thursday, 2 January 2014 at 06:54:18 UTC, Timo Sintonen wrote:
 I have fond one thing that confuses me. I have defined 
 ARM_EABI_UNWINDER but gcc/deh.d has checks for 
 GNU_ARM_EABI_Unwinder. Is this what I should have? When using 
 this I get an error in line 116: static assert ( 8 == 4 ) is 
 false.
I think that this code in gcc/deh.d line 105 may not get it right // To place 'obj' behing unwindHeader. enum UNWIND_PAD = (Phase1Info.sizeof + Object.sizeof) % _Unwind_Exception.alignof; static if (UNWIND_PAD > 0) byte[UNWIND_PAD] _pad; Object obj; // The exception object must be directly behind unwindHeader. // (See build_exception_object.) static assert(unwindHeader.offsetof - obj.offsetof == obj.sizeof); // The generic exception header _Unwind_Exception unwindHeader; Its purpose seems to add padding so that obj is aligned at the end of align block just before unwindHeader. Fitst, if I uderstand correct, the amount to pad should be align - modulo, not modulo. The current code happens to work anyway if align is 8 and modulo is 0 or 4 which is usually the case. Second, When I define GNU_ARM_EABI_Unwinder, the assertion fails. Nothing changes in calculation of UNWIND_PAD but the alignment is not correct and the assert fails. With this define the whole size of struct if 96 bytes and 40 bytes without. Something is aligned differently such a way that this calculation cannot find it. I can not print offsetof with pragma msg so I do not know what happens.
Jan 05 2014
parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 05 Jan 2014 08:26:16 +0000
schrieb "Timo Sintonen" <t.sintonen luukku.com>:

 On Thursday, 2 January 2014 at 06:54:18 UTC, Timo Sintonen wrote:
 I have fond one thing that confuses me. I have defined 
 ARM_EABI_UNWINDER but gcc/deh.d has checks for 
 GNU_ARM_EABI_Unwinder. Is this what I should have? When using 
 this I get an error in line 116: static assert ( 8 == 4 ) is 
 false.
I think that this code in gcc/deh.d line 105 may not get it right // To place 'obj' behing unwindHeader. enum UNWIND_PAD = (Phase1Info.sizeof + Object.sizeof) % _Unwind_Exception.alignof; static if (UNWIND_PAD > 0) byte[UNWIND_PAD] _pad; Object obj; // The exception object must be directly behind unwindHeader. // (See build_exception_object.) static assert(unwindHeader.offsetof - obj.offsetof == obj.sizeof); // The generic exception header _Unwind_Exception unwindHeader; Its purpose seems to add padding so that obj is aligned at the end of align block just before unwindHeader. Fitst, if I uderstand correct, the amount to pad should be align - modulo, not modulo. The current code happens to work anyway if align is 8 and modulo is 0 or 4 which is usually the case. Second, When I define GNU_ARM_EABI_Unwinder, the assertion fails. Nothing changes in calculation of UNWIND_PAD but the alignment is not correct and the assert fails. With this define the whole size of struct if 96 bytes and 40 bytes without. Something is aligned differently such a way that this calculation cannot find it. I can not print offsetof with pragma msg so I do not know what happens.
I should really start pushing my local ARM changes upstream. Here's a fix for the EABI unwinder: https://github.com/jpf91/GDC/commit/262e432e95cbe31a6764cd337f64022a56011eda IIRC I also thought the code in gcc/deh.d wasn't correct. As it wouldn't work for the eabi unwinder anyway (no Phase1Info member) I didn't investigate that though.
Jan 05 2014
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Sunday, 5 January 2014 at 10:06:48 UTC, Johannes Pfau wrote:

 I should really start pushing my local ARM changes upstream. 
 Here's a
 fix for the EABI unwinder:
 https://github.com/jpf91/GDC/commit/262e432e95cbe31a6764cd337f64022a56011eda

 IIRC I also thought the code in gcc/deh.d wasn't correct. As it 
 wouldn't
 work for the eabi unwinder anyway (no Phase1Info member) I 
 didn't
 investigate that though.
Meanwhile I got it to pass with this: align(8) int _pad; Exceptions still not working, but this is a start
Jan 05 2014
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Sunday, 5 January 2014 at 10:21:36 UTC, Timo Sintonen wrote:
 On Sunday, 5 January 2014 at 10:06:48 UTC, Johannes Pfau wrote:

 I should really start pushing my local ARM changes upstream. 
 Here's a
 fix for the EABI unwinder:
 https://github.com/jpf91/GDC/commit/262e432e95cbe31a6764cd337f64022a56011eda

 IIRC I also thought the code in gcc/deh.d wasn't correct. As 
 it wouldn't
 work for the eabi unwinder anyway (no Phase1Info member) I 
 didn't
 investigate that though.
Meanwhile I got it to pass with this: align(8) int _pad;
Exceptions still not working. The code call the unwind routine in libgcc but that never calls back to personality routine. Neither it resumes to the error callback nor abort. There are several addresses in tables like the call to cleanup code and jump to the catch routine. Are they called in libgcc side or in personality routine? I was just wondering if thumb mode has been taken into account. Cortex processors have only the 16 bit 'thumb' instruction set. This is indicated by setting the lsb of the address to 1 in any address that is used in jumps or calls or any address loads to pc. If the lsb is 0 it will result to illegal instruction fault in Cortex. When compiling with -mthumb the compiler always sets this bit for any address and there is a separate libgcc for thumb mode. When calculating address offsets from exception tables the compiler can not know they are used as jump addresses. It may be possible that callback functions are called in wrong mode. Any thoughts?
Jan 08 2014
next sibling parent Iain Buclaw <ibuclaw gdcproject.org> writes:
On 8 January 2014 08:37, Timo Sintonen <t.sintonen luukku.com> wrote:
 On Sunday, 5 January 2014 at 10:21:36 UTC, Timo Sintonen wrote:
 On Sunday, 5 January 2014 at 10:06:48 UTC, Johannes Pfau wrote:

 I should really start pushing my local ARM changes upstream. Here's a
 fix for the EABI unwinder:

 https://github.com/jpf91/GDC/commit/262e432e95cbe31a6764cd337f64022a56011eda

 IIRC I also thought the code in gcc/deh.d wasn't correct. As it wouldn't
 work for the eabi unwinder anyway (no Phase1Info member) I didn't
 investigate that though.
Meanwhile I got it to pass with this: align(8) int _pad;
Exceptions still not working. The code call the unwind routine in libgcc but that never calls back to personality routine. Neither it resumes to the error callback nor abort.
Hmm, could maybe try some alignment test: struct test { byte space; byte[0] end; } struct OurUnwindException { ... enum UNWIND_PAD = (Object.sizeof < test.sizeof) ? test.sizeof - Object.sizeof : 0; byte[UNWIND_PAD] _pad; Object obj; ... } Will have to take a relook at the unwind code again sometime incase there has been changes since it was last updated. Regards Iain
Jan 08 2014
prev sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Wed, 08 Jan 2014 08:37:43 +0000
schrieb "Timo Sintonen" <t.sintonen luukku.com>:

 On Sunday, 5 January 2014 at 10:21:36 UTC, Timo Sintonen wrote:
 On Sunday, 5 January 2014 at 10:06:48 UTC, Johannes Pfau wrote:

 I should really start pushing my local ARM changes upstream. 
 Here's a
 fix for the EABI unwinder:
 https://github.com/jpf91/GDC/commit/262e432e95cbe31a6764cd337f64022a56011eda

 IIRC I also thought the code in gcc/deh.d wasn't correct. As 
 it wouldn't
 work for the eabi unwinder anyway (no Phase1Info member) I 
 didn't
 investigate that though.
Meanwhile I got it to pass with this: align(8) int _pad;
Exceptions still not working. The code call the unwind routine in libgcc but that never calls back to personality routine. Neither it resumes to the error callback nor abort. There are several addresses in tables like the call to cleanup code and jump to the catch routine. Are they called in libgcc side or in personality routine? I was just wondering if thumb mode has been taken into account. Cortex processors have only the 16 bit 'thumb' instruction set. This is indicated by setting the lsb of the address to 1 in any address that is used in jumps or calls or any address loads to pc. If the lsb is 0 it will result to illegal instruction fault in Cortex. When compiling with -mthumb the compiler always sets this bit for any address and there is a separate libgcc for thumb mode. When calculating address offsets from exception tables the compiler can not know they are used as jump addresses. It may be possible that callback functions are called in wrong mode. Any thoughts?
Stupid question, but are C++ exceptions working for you? I think we don't change anything inthe compiler related to exception handling, so if C++ worked and D didn't it could only be a problem with the runtime code?
Jan 08 2014
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Wednesday, 8 January 2014 at 15:52:25 UTC, Johannes Pfau wrote:

 Stupid question, but are C++ exceptions working for you? I 
 think we
 don't change anything inthe compiler related to exception 
 handling, so
 if C++ worked and D didn't it could only be a problem with the 
 runtime
 code?
I have never used c++ in this platform and I do not know what it would require. Some commercial toolsets use gcc as backend but I do not know if they have c++.
Jan 08 2014
next sibling parent "Mike" <none none.com> writes:
On Wednesday, 8 January 2014 at 19:13:36 UTC, Timo Sintonen wrote:
 On Wednesday, 8 January 2014 at 15:52:25 UTC, Johannes Pfau 
 wrote:

 Stupid question, but are C++ exceptions working for you? I 
 think we
 don't change anything inthe compiler related to exception 
 handling, so
 if C++ worked and D didn't it could only be a problem with the 
 runtime
 code?
I have never used c++ in this platform and I do not know what it would require. Some commercial toolsets use gcc as backend but I do not know if they have c++.
I use C++ exceptions on an STM32F4 (ARM Cortex-M4F) with the GNU Tools for ARM Embedded Processors (https://launchpad.net/gcc-arm-embedded). To get it to work, however, I had to make changes to my linker script. Here's the linker script I'm currently using: /******************************************************* Memory Spaces Definitions *********************************************************/ MEMORY { CCRAM (rxw) : ORIGIN = 0x10000000, LENGTH = 64k RAM (rxw) : ORIGIN = 0x20000000, LENGTH = 128k FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024k } /****************************************************** higher address of the user mode stack *********************************************************/ _estack = ORIGIN(CCRAM) + LENGTH(CCRAM); /******************************************************** Section Definitions **********************************************************/ SECTIONS { .ccm (NOLOAD) : { . = ALIGN(4); *(.ccm) . = ALIGN(4); } >CCRAM .isr_vector : /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */ { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >FLASH .text : /* the program code is stored in the .text section, which goes to Flash */ { . = ALIGN(4); *(.text) /* remaining code */ *(.text.*) /* remaining code */ *(.rodata) /* read-only data (constants) */ *(.rodata*) *(.glue_7) *(.glue_7t) *(.eh_frame) /* C++ Exception Handling */ . = ALIGN(4); /* now make sure we keep the C++ constructors */ KEEP (*(.init)) . = ALIGN(4); KEEP (*(.fini)) . = ALIGN(4); __preinit_array_start = .; KEEP (*(.preinit_array)) __preinit_array_end = .; . = ALIGN(4); __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; . = ALIGN(4); __fini_array_start = .; KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) __fini_array_end = .; . = ALIGN(0x4); KEEP (*crtbegin.o(.ctors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*crtend.o(.ctors)) . = ALIGN(0x4); KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*crtend.o(.dtors)) . = ALIGN(4); _etext = .; } >FLASH .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } >FLASH _sidata = .; /* This is used by the startup in order to initialize the .data secion */ /****************************************************** This is the initialized data section. It is one task of the startup to copy the initial values from FLASH to RAM. ******************************************************/ .data : AT ( _sidata ) { . = ALIGN(4); _sdata = . ; /* This is used by the startup in order to initialize the .data secion */ _data = . ; *(.data) *(.data.*) *(.RAMtext) . = ALIGN(4); _edata = . ; /* This is used by the startup in order to initialize the .data secion */ } >RAM _eidata = _sidata + (_edata - _sdata); /*calculate end address of idata*/ _lastdataromaddress = ORIGIN(FLASH) + LENGTH(FLASH); /*check that idata remains in FLASH region*/ ___toobig___ = ( _eidata > _lastdataromaddress) ? 1 : 0 ; ___toobigmsg___ = ( ___toobig___ ) ? "!!!!!!!!! FLASH IS FULL !!!!!!!!!" : 0 ; /***************************************************** This is the uninitialized data section **********************************************/ .bss : { . = ALIGN(4); _sbss = .; /* This is used by the startup in order to initialize the .bss secion */ _bss = .; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _ebss = . ; /* This is used by the startup in order to initialize the .bss secion */ } >RAM PROVIDE ( end = _ebss ); PROVIDE ( _end = _ebss ); /************************************************************ Discard debug info ******************************************************/ /DISCARD/ : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) libstdc++.a ( * ) libsupc++.a ( * ) } .ARM.attributes 0 : { *(.ARM.attributes) } }
Jan 08 2014
prev sibling parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Wednesday, 8 January 2014 at 19:13:36 UTC, Timo Sintonen wrote:
 On Wednesday, 8 January 2014 at 15:52:25 UTC, Johannes Pfau 
 wrote:

 Stupid question, but are C++ exceptions working for you? I 
 think we
 don't change anything inthe compiler related to exception 
 handling, so
 if C++ worked and D didn't it could only be a problem with the 
 runtime
 code?
I investigated this a little. It seems that the processor gets a fault interrupt when calling _Unwind_RaiseException in _d_throw. The status bits indicate an invalid instruction code. When looking at the disassembly I see that the call is a blx instruction with address. In Cortex-m4 blx can only take a register argument. Is this a bug in gdc or gcc?
Feb 28 2014
parent reply "Mike" <none none.com> writes:
On Friday, 28 February 2014 at 21:18:05 UTC, Timo Sintonen wrote:
 On Wednesday, 8 January 2014 at 19:13:36 UTC, Timo Sintonen 
 wrote:
 On Wednesday, 8 January 2014 at 15:52:25 UTC, Johannes Pfau 
 wrote:

 Stupid question, but are C++ exceptions working for you? I 
 think we
 don't change anything inthe compiler related to exception 
 handling, so
 if C++ worked and D didn't it could only be a problem with 
 the runtime
 code?
I investigated this a little. It seems that the processor gets a fault interrupt when calling _Unwind_RaiseException in _d_throw. The status bits indicate an invalid instruction code. When looking at the disassembly I see that the call is a blx instruction with address. In Cortex-m4 blx can only take a register argument. Is this a bug in gdc or gcc?
blx can also take a label. Are you sure it's an address and not a label?
Feb 28 2014
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Saturday, 1 March 2014 at 02:59:37 UTC, Mike wrote:
 On Friday, 28 February 2014 at 21:18:05 UTC, Timo Sintonen 
 wrote:
 On Wednesday, 8 January 2014 at 19:13:36 UTC, Timo Sintonen 
 wrote:
 On Wednesday, 8 January 2014 at 15:52:25 UTC, Johannes Pfau 
 wrote:

 Stupid question, but are C++ exceptions working for you? I 
 think we
 don't change anything inthe compiler related to exception 
 handling, so
 if C++ worked and D didn't it could only be a problem with 
 the runtime
 code?
I investigated this a little. It seems that the processor gets a fault interrupt when calling _Unwind_RaiseException in _d_throw. The status bits indicate an invalid instruction code. When looking at the disassembly I see that the call is a blx instruction with address. In Cortex-m4 blx can only take a register argument. Is this a bug in gdc or gcc?
blx can also take a label. Are you sure it's an address and not a label?
According to the instruction card http://infocenter.arm.com/help/topic/com.arm.doc.qrc0006e/QRC0006_UAL16.pdf blx with label is valid in thumb instruction set. But it is a 32 bit instruction so I think it does not exist in any thumb only processors. Here we can see it is not valid in M4: http://infocenter.arm.com/help/topic/com.arm.doc.dui0553a/BABEFHAE.html
Feb 28 2014
parent reply "Mike" <none none.com> writes:
On Saturday, 1 March 2014 at 07:26:16 UTC, Timo Sintonen wrote:
 I investigated this a little. It seems that the processor 
 gets a fault interrupt when calling _Unwind_RaiseException in 
 _d_throw. The status bits indicate an invalid instruction 
 code.
 When looking at the disassembly I see that the call is a blx 
 instruction with address. In Cortex-m4 blx can only take a 
 register argument.
 Is this a bug in gdc or gcc?
blx can also take a label. Are you sure it's an address and not a label?
According to the instruction card http://infocenter.arm.com/help/topic/com.arm.doc.qrc0006e/QRC0006_UAL16.pdf blx with label is valid in thumb instruction set. But it is a 32 bit instruction so I think it does not exist in any thumb only processors. Here we can see it is not valid in M4: http://infocenter.arm.com/help/topic/com.arm.doc.dui0553a/BABEFHAE.html
It is my understanding that Thumb is 16-bit only, but Thumb-2 is a mix of 16 and 32-bit instructions (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471c/CHDFEDDB.html). Under the "Specifications" tab of this site (http://www.arm.com/products/processors/cortex-m/cortex-m4-processor.php) it shows the Cortex-M4 as a Thumb-2 capable core. I don't know how to tell GDC/GCC to only generate Thumb-1 as opposed to Thumb-2 so it's my assumption it will default the latest Thumb based on the specified arch or cpu argument. In that case, I think it will generate Thumb-2 instructions. Correct me if I'm wrong. Here's the instruction card for Thumb-2 (http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf). It shows the blx <label> instruction is valid for 5T and later architectures. The Cortex-M4 is ARMv7EM architecture, so I think it should be good to go. However, your second think doesn't show the blx {label} syntax, so I'm a little confused. Can you post the assembly code?
Feb 28 2014
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Saturday, 1 March 2014 at 07:53:45 UTC, Mike wrote:
 On Saturday, 1 March 2014 at 07:26:16 UTC, Timo Sintonen wrote:
 I investigated this a little. It seems that the processor 
 gets a fault interrupt when calling _Unwind_RaiseException 
 in _d_throw. The status bits indicate an invalid instruction 
 code.
 When looking at the disassembly I see that the call is a blx 
 instruction with address. In Cortex-m4 blx can only take a 
 register argument.
 Is this a bug in gdc or gcc?
blx can also take a label. Are you sure it's an address and not a label?
According to the instruction card http://infocenter.arm.com/help/topic/com.arm.doc.qrc0006e/QRC0006_UAL16.pdf blx with label is valid in thumb instruction set. But it is a 32 bit instruction so I think it does not exist in any thumb only processors. Here we can see it is not valid in M4: http://infocenter.arm.com/help/topic/com.arm.doc.dui0553a/BABEFHAE.html
It is my understanding that Thumb is 16-bit only, but Thumb-2 is a mix of 16 and 32-bit instructions (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471c/CHDFEDDB.html). Under the "Specifications" tab of this site (http://www.arm.com/products/processors/cortex-m/cortex-m4-processor.php) it shows the Cortex-M4 as a Thumb-2 capable core. I don't know how to tell GDC/GCC to only generate Thumb-1 as opposed to Thumb-2 so it's my assumption it will default the latest Thumb based on the specified arch or cpu argument. In that case, I think it will generate Thumb-2 instructions. Correct me if I'm wrong. Here's the instruction card for Thumb-2 (http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf). It shows the blx <label> instruction is valid for 5T and later architectures. The Cortex-M4 is ARMv7EM architecture, so I think it should be good to go. However, your second think doesn't show the blx {label} syntax, so I'm a little confused. Can you post the assembly code?
Here, (chapter 1.1) http://infocenter.arm.com/help/topic/com.arm.doc.dui0553a/DUI0553A_cortex_m4_dgug.pdf "The Cortex-M4 implements a __version__ of the thumb instruction set __based__ on thumb2." So it is thumb2 but maybe a little modified. There is nothing interesting in the assembly, only this wrong call. This form of instruction is just missing in M4 and it gives an invalid instruction fault. So what are we arguing about? If this is so hard for us to find, no wonder the compiler writers have not noticed this.
Mar 01 2014
parent reply "Mike" <none none.com> writes:
On Saturday, 1 March 2014 at 08:56:26 UTC, Timo Sintonen wrote:
 There is nothing interesting in the assembly, only this wrong
 call.
 This form of instruction is just missing in M4 and it gives an
 invalid instruction fault. So what are we arguing about?

 If this is so hard for us to find, no wonder the compiler 
 writers
 have not noticed this.
Well, I yield then to the compiler folks. Hopefully Iain or Johannes can provide some insight.
Mar 01 2014
parent reply "Johannes Pfau" <nospam example.com> writes:
On Saturday, 1 March 2014 at 09:24:40 UTC, Mike wrote:
 On Saturday, 1 March 2014 at 08:56:26 UTC, Timo Sintonen wrote:
 There is nothing interesting in the assembly, only this wrong
 call.
 This form of instruction is just missing in M4 and it gives an
 invalid instruction fault. So what are we arguing about?

 If this is so hard for us to find, no wonder the compiler 
 writers
 have not noticed this.
Well, I yield then to the compiler folks. Hopefully Iain or Johannes can provide some insight.
AFAIK the call to _Unwind_RaiseException [1] is just a normal function call [2] to a extern(C) function in a different compilation unit. It's not even a builtin so it doesn't look like a gdc bug. GCC bug is more likely but I wonder what exactly makes this case special? Why does this not happen for every function call to a extern(C) function? Please try the following: * Verify your --with-cpu, --with-arch, --with-tune flags for gcc configure. Also make sure that binutils is configured with the correct flags. * Have a look at the build log how gcc/deh.d is compiled. Use the same compile command, but generate assembly via -S. Then look at the asm code to check whether the compiler or the assembler/linker is to blame. * Try to reduce the example / understand why exactly this happens only in this case. * When you have a reduced example, try to port it to C and see if GCC handles it correctly. [1] https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/deh.d#L151 [2] https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/unwind/arm.d#L191
Mar 01 2014
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Saturday, 1 March 2014 at 10:49:57 UTC, Johannes Pfau wrote:
 On Saturday, 1 March 2014 at 09:24:40 UTC, Mike wrote:
 On Saturday, 1 March 2014 at 08:56:26 UTC, Timo Sintonen wrote:
 There is nothing interesting in the assembly, only this wrong
 call.
 This form of instruction is just missing in M4 and it gives an
 invalid instruction fault. So what are we arguing about?

 If this is so hard for us to find, no wonder the compiler 
 writers
 have not noticed this.
Well, I yield then to the compiler folks. Hopefully Iain or Johannes can provide some insight.
AFAIK the call to _Unwind_RaiseException [1] is just a normal function call [2] to a extern(C) function in a different compilation unit. It's not even a builtin so it doesn't look like a gdc bug. GCC bug is more likely but I wonder what exactly makes this case special? Why does this not happen for every function call to a extern(C) function? Please try the following: * Verify your --with-cpu, --with-arch, --with-tune flags for gcc configure. Also make sure that binutils is configured with the correct flags. * Have a look at the build log how gcc/deh.d is compiled. Use the same compile command, but generate assembly via -S. Then look at the asm code to check whether the compiler or the assembler/linker is to blame. * Try to reduce the example / understand why exactly this happens only in this case. * When you have a reduced example, try to port it to C and see if GCC handles it correctly. [1] https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/deh.d#L151 [2] https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/gcc/unwind/arm.d#L191
I checked my code and the library code and there is no other call like this. I think there is one thing that makes this function special: if I understand correct, this function will not return. If there is some noreturn attribute somewhere this function might be handled in a different way. Is it so that gdc does not generate any assembly directly? So this would be a bug in gcc side and I may report it there.
Mar 01 2014
parent reply "Johannes Pfau" <nospam example.com> writes:
On Saturday, 1 March 2014 at 11:46:03 UTC, Timo Sintonen wrote:
 I checked my code and the library code and there is no other 
 call like this. I think there is one thing that makes this 
 function special: if I understand correct, this function will 
 not return. If there is some noreturn attribute somewhere this 
 function might be handled in a different way.

 Is it so that gdc does not generate any assembly directly? So 
 this would be a bug in gcc side and I may report it there.
It's not marked as noreturn though, neither in C nor in the D code. The function can return if there is some kind of error (http://refspecs.linuxfoundation.org/LSB_3.1.0/LSB-Core-S390/LSB-Core-S390/baselib--unwind-raiseexception.html) Some google-fu shows that someone reported this bug here: http://gcc.gnu.org/ml/gcc-help/2013-06/msg00091.html https://sourceware.org/bugzilla/show_bug.cgi?id=15628 However, someone also had this problem on this german site: http://www.mikrocontroller.net/topic/312956 and the solution was that -mcpu alone was not good enough, he had to specify -march flags as well so please double-check your flags. It's possible that binutils doesn't work properly with -mcpu so I'd do this: -march=armv7e-m -mcpu=cortex-m4 -mthumb -mtune=cortex-m4 Or better at configure time: --with-arch=armv7e-m --with-cpu=cortex-m4 --with-mode=thumb --with-tune=cortex-m4 Oh, and if that works: Please add a comment tu the bintuils issue that specifying -march helps.
Mar 01 2014
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Saturday, 1 March 2014 at 12:53:14 UTC, Johannes Pfau wrote:

 However, someone also had this problem on this german site:
 http://www.mikrocontroller.net/topic/312956

 and the solution was that -mcpu alone was not good enough, he 
 had to specify -march flags as well so please double-check your 
 flags.
 It's possible that binutils doesn't work properly with -mcpu so 
 I'd do this:

 -march=armv7e-m -mcpu=cortex-m4 -mthumb -mtune=cortex-m4

 Or better at configure time:

 --with-arch=armv7e-m --with-cpu=cortex-m4 --with-mode=thumb 
 --with-tune=cortex-m4
I read somewhere that -march is ignored when the more specific -mcpu is present. On the other hand, ld has no cpu option, only --architecture. That did not have any effect. A little background: I have the main makefile and all definitions in toplevel directory. Libraries and projects are in subdirs. Any subdir makefile includes settings from topdir. In topdir I just give export projectdir=xxx and then run make. Any project in any language is run from the same makefile with the same settings. I use separate compiling and pass myself options to gcc, as and ld. A reduced version of this toolset is in the minlibd repo in tools directory. I decided to rebuild all my apps and libs. Now I have lots of blx instructions in my code. So this is not related to exceptions. I just triggered this when playing with deh.d. I have not been able to confirm this, but this may be something like when linking libraries that have unresolved symbols. If the symbol is already available, the call is bl, but if the symbol will be resolved from a later library, the call will be blx. Libgcc is always the last so any call to its functions will be blx. When I compile my c only project, I will not get these calls. I have compared the object list files but I can not find any meaningful difference. Could it be possible that gdc generated asm files have some attribute/directive/segment name/whatever that changes the behavior in ld. Obviously there are more segments in d executable, like unwind and debug info. What is the thing that makes it different for ld?
Mar 02 2014
parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 02 Mar 2014 11:20:53 +0000
schrieb "Timo Sintonen" <t.sintonen luukku.com>:

 On Saturday, 1 March 2014 at 12:53:14 UTC, Johannes Pfau wrote:
 
 However, someone also had this problem on this german site:
 http://www.mikrocontroller.net/topic/312956

 and the solution was that -mcpu alone was not good enough, he 
 had to specify -march flags as well so please double-check your 
 flags.
 It's possible that binutils doesn't work properly with -mcpu so 
 I'd do this:

 -march=armv7e-m -mcpu=cortex-m4 -mthumb -mtune=cortex-m4

 Or better at configure time:

 --with-arch=armv7e-m --with-cpu=cortex-m4 --with-mode=thumb 
 --with-tune=cortex-m4
I read somewhere that -march is ignored when the more specific -mcpu is present. On the other hand, ld has no cpu option, only --architecture. That did not have any effect. A little background: I have the main makefile and all definitions in toplevel directory. Libraries and projects are in subdirs. Any subdir makefile includes settings from topdir. In topdir I just give export projectdir=xxx and then run make. Any project in any language is run from the same makefile with the same settings. I use separate compiling and pass myself options to gcc, as and ld. A reduced version of this toolset is in the minlibd repo in tools directory.
OK, but at least for the initial problem the question is how did you build _libgcc_. I guess it was build as part of the normal gcc ./configure & make & make install process. To make sure that libgcc is built correctly for Cortex-M4 you have to specify "--with-arch=armv7e-m --with-cpu=cortex-m4 --with-mode=thumb --with-tune=" when configuring gcc/gdc. (And I don't see these flags mentioned in https://bitbucket.org/timosi/minlibd/src/691c76aa2b543998bb573e6ce6d96951a80817bd/README.gdc?at=default)
 
 I decided to rebuild all my apps and libs. Now I have lots of blx 
 instructions in my code. So this is not related to exceptions. I 
 just triggered this when playing with deh.d.
 
 I have not been able to confirm this, but this may be something 
 like when linking libraries that have unresolved symbols. If the 
 symbol is already available, the call is bl, but if the symbol 
 will be resolved from a later library, the call will be blx. 
 Libgcc is always the last so any call to its functions will be 
 blx.
Sounds strange, I don't think we could cause this in the gdc frontend. I guess binutils generates blx if thumb code calls arm code or the other way round. So I'd verify which libraries are really picked up by ld (ld --verbose) then check if the entry points are in thumb or arm mode: http://stackoverflow.com/a/15931232 This sounds a lot as if calls to the same library/object file generate bl instructions as the code is in the same mode, but functions in external libraries are in a different mode and therefore generate blx.
 
 When I compile my c only project, I will not get these calls. I 
 have compared the object list files but I can not find any 
 meaningful difference. Could it be possible that gdc generated 
 asm files have some attribute/directive/segment name/whatever 
 that changes the behavior in ld. Obviously there are more 
 segments in d executable, like unwind and debug info. What is the 
 thing that makes it different for ld?
 
I'm not sure but I still don't think we could cause this. This low-level stuff is usually part of the backend, the frontend doesn't know much about thumb/arm. Did you use the same gcc which was compiled with your gdc or did you use a gcc from a different toolchain? In either case I probably need a reduced test case, otherwise I'm just guessing here ;-)
Mar 02 2014
parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
On Sunday, 2 March 2014 at 15:36:01 UTC, Johannes Pfau wrote:
 To make sure  that libgcc
 is built correctly for Cortex-M4 you have to specify
 "--with-arch=armv7e-m --with-cpu=cortex-m4 --with-mode=thumb
 --with-tune=" when configuring gcc/gdc.

 (And I don't see these flags mentioned in
 https://bitbucket.org/timosi/minlibd/src/691c76aa2b543998bb573e6ce6d96951a80817bd/README.gdc?at=default)
Gcc build fails with these. It will take time to check them one by one. Also enable/disable-multilib may affect to this. Then I updated my host binutils and gcc to latest head and with these I compiled cross binutils and gcc/gdc from head. I used my current settings. Now my own code and minlibd do not have any blx instructions but libgcc has some.
 Sounds strange, I don't think we could cause this in the gdc 
 frontend.
I am not saying it is a gdc bug. It may very well be a side effect of a flag that is related to maybe umwinding or relocation. I do have two kind of object files now in my executable and I just like to know what is the difference between them.
 I guess binutils generates blx if thumb code calls arm code or 
 the
 other way round. So I'd verify which libraries are really 
 picked up by
 ld (ld --verbose) then check if the entry points are in thumb 
 or arm
 mode:
 http://stackoverflow.com/a/15931232

 This sounds a lot as if calls to the same library/object file 
 generate
 bl instructions as the code is in the same mode, but functions 
 in
 external libraries are in a different mode and therefore 
 generate blx.
Yes, I think blx is for this. M4 does not have arm mode and there is no this instruction, so it should be a linker error if the user try to mix objects with different modes. As I mentioned, I pass manually everything, including libgcc. Nothing is picked by default. The multilib thing should be just because of this. There are 4 variants of libgcc. If I pick the m4-fpu library it should be already compiled with the right flags. If it is not, I think that is a gcc bug. How can I check from the library which modes/flags is has?
 I'm not sure but I still don't think we could cause this. This
 low-level stuff is usually part of the backend, the frontend 
 doesn't
 know much about thumb/arm.
Yes, this is going a little off-topic now
Mar 02 2014
parent reply Johannes Pfau <nospam example.com> writes:
Am Sun, 02 Mar 2014 18:33:00 +0000
schrieb "Timo Sintonen" <t.sintonen luukku.com>:

 On Sunday, 2 March 2014 at 15:36:01 UTC, Johannes Pfau wrote:
 To make sure  that libgcc
 is built correctly for Cortex-M4 you have to specify
 "--with-arch=armv7e-m --with-cpu=cortex-m4 --with-mode=thumb
 --with-tune=" when configuring gcc/gdc.

 (And I don't see these flags mentioned in
 https://bitbucket.org/timosi/minlibd/src/691c76aa2b543998bb573e6ce6d96951a80817bd/README.gdc?at=default)
Gcc build fails with these. It will take time to check them one by one. Also enable/disable-multilib may affect to this.
Multilib is indeed special. AFAIK it's not possible to change multilib flags without changing some file in gcc (gcc/config/t-arm or something like that).
 I am not saying it is a gdc bug. It may very well be a side 
 effect of a flag that is related to maybe umwinding or 
 relocation. I do have two kind of object files now in my 
 executable and I just like to know what is the difference between 
 them.
I'd like to know the reason as well, but I think I really need a small test case to continue looking into this. Could you upload your toolchain binaries somewhere?

 Yes, I think blx is for this. M4 does not have arm mode and there 
 is no this instruction, so it should be a linker error if the 
 user try to mix objects with different modes.
 As I mentioned, I pass manually everything, including libgcc. 
 Nothing is picked by default. The multilib thing should be just 
 because of this. There are 4 variants of libgcc. If I pick the 
 m4-fpu library it should be already compiled with the right 
 flags. If it is not, I think that is a gcc bug.
 How can I check from the library which modes/flags is has?
 
You seem to be right that binutils doesn't have an architecture flag and therefore the linker can't even know you're targeting Cortex-M4. http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf 4.5.3 ---------- In addition to the normal rules for symbol values the following rules shall also apply to symbols of type STT_FUNC : If the symbol addresses a Thumb instruction, its value is the address of the instruction with bit zero set (in a relocatable object, the section offset with bit zero set) ---------- However, objdump is 'clever' and removes this bit m( But with readelf: readelf liba.o -s 8: 00000000 28 FUNC GLOBAL DEFAULT 1 test readelf libt.o -s 8: 00000001 18 FUNC GLOBAL DEFAULT 1 test In my simple tests ld does really only use blx for arm->thumb / thumb->arm calls. In all other cases it uses bl. And it's indeed the linker making this decision, the compiler always emits 'bl'. Would be great if you could confirm if it's a linker issue in your case as well.
Mar 07 2014
next sibling parent "Timo Sintonen" <t.sintonen luukku.com> writes:
On Friday, 7 March 2014 at 18:41:35 UTC, Johannes Pfau wrote:
 To make sure  that libgcc
 is built correctly for Cortex-M4 you have to specify
 "--with-arch=armv7e-m --with-cpu=cortex-m4 --with-mode=thumb
 --with-tune=" when configuring gcc/gdc.
Gcc build fails with these. It will take time to check them one by one. Also enable/disable-multilib may affect to this.
It seems that the gcc compilation fails with any of these. These flags do set the features of the compiler which in turn have effect to the libraries it builds. These do not set the libgcc build process and I get similar errors than Mike reported a while ago. The reason is that the build process still try to make arm mode libraries even when the compiler is thumb only.
 Multilib is indeed special. AFAIK it's not possible to change 
 multilib
 flags without changing some file in gcc (gcc/config/t-arm or 
 something
 like that).
It has been my plan to investigate the library build process this weekend
 I'd like to know the reason as well, but I think I really need 
 a small
 test case to continue looking into this. Could you upload your
 toolchain binaries somewhere?
 You seem to be right that binutils doesn't have an architecture 
 flag and
 therefore the linker can't even know you're targeting Cortex-M4.

 In my simple tests ld does really only use blx for arm->thumb /
 thumb->arm calls. In all other cases it uses bl. And it's 
 indeed the
 linker making this decision, the compiler always emits 'bl'. 
 Would be
 great if you could confirm if it's a linker issue in your case 
 as well.
I was getting different object files from the same sources with different versions of the compiler. I tried to find what was the difference between those files. An oo language naturally makes a little bit different object file than pure c. There was something that made ld think the files are different and needed the interworking call. I just could not find what was the flag or attribute or section that made ld to think so. As I told, then I updated everything to latest head versions and I think I am now where I was before. I do not have the original binaries any more. Binutils 2-23 and gcc/gdc heads between mid of january to mid of february at least caused the problem. There still is some blx instructions but I think they have always been there. I just have not needed those functions before I started with exceptions. The linking process seems to be controlled by those arm attributes. I did not know readelf can also read .o files. It lists attributes and all kind of info much better than objdump. Next I will investigate my files with this and try to find out how to affect to libgcc generation.
Mar 08 2014
prev sibling parent reply "Timo Sintonen" <t.sintonen luukku.com> writes:
Now I got the exceptions to work.

I have not been able to find how to control the libgcc build 
process. The configure script seems not to know that I give 
different defaults for the compiler in --with switches. Configure 
still assumes the compiler defaults arm mode although it is in 
thumb mode. I should also be able to give different default 
values to all four libraries that are built.

I solved this by building with defaults and then hacked the 
makefile of that libgcc directory I use. (fpu) Then I remade the 
library. Changing LIBGCC_FLAGS at line 229 did the trick.

So exceptions seems to work now. There is one thing: because I do 
not have gc, the OurUnwindException struct that is allocated in 
_d_throw is never freed. This is an issue for anybody not using 
gc, so there should be a general solution.

The three problems in this project were:
- struct alignment issue that Iain has fixed
- a change/bug in gcc in january-february causing different 
object generation. Seems to be fixed in head now.
- building libgcc with the same settings than the rest of the 
application. I am  still looking a way to control the library 
build process.
Mar 08 2014
next sibling parent "Mike" <none none.com> writes:
On Sunday, 9 March 2014 at 07:57:46 UTC, Timo Sintonen wrote:
 Now I got the exceptions to work.
Nice Work! Congratulations! I read your wiki, but didn't see your source code yet (I assume its coming, yes?). Anyway, thanks for sharing this information. Mike
Mar 09 2014
prev sibling parent Johannes Pfau <nospam example.com> writes:
Am Sun, 09 Mar 2014 07:57:45 +0000
schrieb "Timo Sintonen" <t.sintonen luukku.com>:

 Now I got the exceptions to work.
 
 I have not been able to find how to control the libgcc build 
 process. The configure script seems not to know that I give 
 different defaults for the compiler in --with switches. Configure 
 still assumes the compiler defaults arm mode although it is in 
 thumb mode. I should also be able to give different default 
 values to all four libraries that are built.
 
 I solved this by building with defaults and then hacked the 
 makefile of that libgcc directory I use. (fpu) Then I remade the 
 library. Changing LIBGCC_FLAGS at line 229 did the trick.
 [...]
 
Great! The configure script doesn't really have to know about the "-with-*" flags - these are used by default if you don't pass any arguments to gcc/gdc. However this can't work for your multilib setup. libgcc should really build with the correct multilib flags, so that's strange. You can check the used multilib flags with gcc -print-multi-lib You might have to edit gcc/config/arm/t-arm-elf You could check how the gcc-arm-embedded project modifies that file, IIRC they build special multilibs for cortex m3/m4 (the default gcc configuration only builds thumb/not-thumb*) https://launchpad.net/gcc-arm-embedded http://airs.com/ian/configure/configure_8.html http://gcc.gnu.org/onlinedocs/gccint/Target-Fragment.html * BTW: This can explain invalid instructions in libgcc: it's only build with -mthumb but not with -march in the default multilib configuration.
Mar 09 2014
prev sibling parent Johannes Pfau <nospam example.com> writes:
Am Wed, 01 Jan 2014 14:02:42 +0000
schrieb "Timo Sintonen" <t.sintonen luukku.com>:

 I started to update minlibd with gdc head from last saturday. 
 While testing if exceptions work, the program just stops and does 
 not reach catch or abort.
 
 Before investigating further, I want to ask the status of arm 
 exceptions: are they known to work, known not to work or is the 
 status just unknown?
They work just as well on ARM/linux/glibc as on x86/glibc/linux. (Exception chaining isn't working on any architecture, IIRC). There's a problem with nothrow functions on ARM though: GDC currently marks nothrow functions with TREE_NOTHROW. However, if such a functions throws an Error (which is legal in D) the program crashes. The solution is not setting TREE_NOTHROW, see here: https://github.com/jpf91/GDC/commit/935198bda01ada89d946ee28819253cca872bea5
 
 Does anybody know if there are any good articles of exceptions 
 and unwinding in gcc or in general?
 
 
The keywords here are 'dwarf exceptions' and 'sjlj exceptions' (or setjump/longjump exceptions) and you probably want 'dwarf exceptions'. http://gcc.gnu.org/ml/gcc/2002-07/msg00391.html
Jan 01 2014