GCC 8 for ARM in LTO mode is removing interrupt handlers and weak functions - how to prevent it?
My target device is an EFM32 Cortex-M3 based device. My toolchain is the official ARM GNU toolchain gcc-arm-none-eabi-8-2018-q4-major.
Everything works fine without LTO, but to make LTO work I have to mark all interrupt handler code with -fno-lto
. I would like to get rid of this workaround.
The problem is, every interrupt handler is getting removed from the final binary. (I am checking with arm-none-eabi-nm --print-size --size-sort --radix=d -C -n file.out
) This makes the resulting binary crash.
Digging deeper and after googling for similar problems:
- I tried marking such functions as
__attribute__((used))
,__attribute((interrupt))
to no avail - the interrupt handlers are getting removed in spite of these attributes. (related Prevent GCC LTO from deleting function) - Found possibly related discussion https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 - no solutions posted
Sample code from startup_efm32gg.c
defines default interrupt handlers as such:
void DMA_IRQHandler(void) __attribute__ ((weak, alias("Default_Handler")));
/* many other interrupts */
void Default_Handler(void) { while (1); }
The same problem happens for regular interrupt handler definitions as well (as in, no aliases and not weak)
It might be related but it seems that weak symbols are misbehaving in LTO mode in the same way.
Thank you in advance for any ideas!
Edit: See my reply to the marked answer for a full solution!
c gcc arm lto
add a comment |
My target device is an EFM32 Cortex-M3 based device. My toolchain is the official ARM GNU toolchain gcc-arm-none-eabi-8-2018-q4-major.
Everything works fine without LTO, but to make LTO work I have to mark all interrupt handler code with -fno-lto
. I would like to get rid of this workaround.
The problem is, every interrupt handler is getting removed from the final binary. (I am checking with arm-none-eabi-nm --print-size --size-sort --radix=d -C -n file.out
) This makes the resulting binary crash.
Digging deeper and after googling for similar problems:
- I tried marking such functions as
__attribute__((used))
,__attribute((interrupt))
to no avail - the interrupt handlers are getting removed in spite of these attributes. (related Prevent GCC LTO from deleting function) - Found possibly related discussion https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 - no solutions posted
Sample code from startup_efm32gg.c
defines default interrupt handlers as such:
void DMA_IRQHandler(void) __attribute__ ((weak, alias("Default_Handler")));
/* many other interrupts */
void Default_Handler(void) { while (1); }
The same problem happens for regular interrupt handler definitions as well (as in, no aliases and not weak)
It might be related but it seems that weak symbols are misbehaving in LTO mode in the same way.
Thank you in advance for any ideas!
Edit: See my reply to the marked answer for a full solution!
c gcc arm lto
add a comment |
My target device is an EFM32 Cortex-M3 based device. My toolchain is the official ARM GNU toolchain gcc-arm-none-eabi-8-2018-q4-major.
Everything works fine without LTO, but to make LTO work I have to mark all interrupt handler code with -fno-lto
. I would like to get rid of this workaround.
The problem is, every interrupt handler is getting removed from the final binary. (I am checking with arm-none-eabi-nm --print-size --size-sort --radix=d -C -n file.out
) This makes the resulting binary crash.
Digging deeper and after googling for similar problems:
- I tried marking such functions as
__attribute__((used))
,__attribute((interrupt))
to no avail - the interrupt handlers are getting removed in spite of these attributes. (related Prevent GCC LTO from deleting function) - Found possibly related discussion https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 - no solutions posted
Sample code from startup_efm32gg.c
defines default interrupt handlers as such:
void DMA_IRQHandler(void) __attribute__ ((weak, alias("Default_Handler")));
/* many other interrupts */
void Default_Handler(void) { while (1); }
The same problem happens for regular interrupt handler definitions as well (as in, no aliases and not weak)
It might be related but it seems that weak symbols are misbehaving in LTO mode in the same way.
Thank you in advance for any ideas!
Edit: See my reply to the marked answer for a full solution!
c gcc arm lto
My target device is an EFM32 Cortex-M3 based device. My toolchain is the official ARM GNU toolchain gcc-arm-none-eabi-8-2018-q4-major.
Everything works fine without LTO, but to make LTO work I have to mark all interrupt handler code with -fno-lto
. I would like to get rid of this workaround.
The problem is, every interrupt handler is getting removed from the final binary. (I am checking with arm-none-eabi-nm --print-size --size-sort --radix=d -C -n file.out
) This makes the resulting binary crash.
Digging deeper and after googling for similar problems:
- I tried marking such functions as
__attribute__((used))
,__attribute((interrupt))
to no avail - the interrupt handlers are getting removed in spite of these attributes. (related Prevent GCC LTO from deleting function) - Found possibly related discussion https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 - no solutions posted
Sample code from startup_efm32gg.c
defines default interrupt handlers as such:
void DMA_IRQHandler(void) __attribute__ ((weak, alias("Default_Handler")));
/* many other interrupts */
void Default_Handler(void) { while (1); }
The same problem happens for regular interrupt handler definitions as well (as in, no aliases and not weak)
It might be related but it seems that weak symbols are misbehaving in LTO mode in the same way.
Thank you in advance for any ideas!
Edit: See my reply to the marked answer for a full solution!
c gcc arm lto
c gcc arm lto
edited Jan 1 at 18:59
RushPL
asked Jan 1 at 16:44
RushPLRushPL
3,49012438
3,49012438
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Where are your interrupt handlers referenced from? Just like unreferenced static functions and objects will be removed from a single translation unit, external ones that are unused will be removed during LTO. In order to prevent this (and in order for your program to be valid anyway in the abstract model) there needs to be some chain of references, starting from the entry point, leading to the functions and objects; if none exists, then you're not actually using them in your program.
If the reference is from a linker script or asm source file, it's possible that this is a bug in LTO, and it's not seeing the references like it should. In this case you might be able to apply a hack like __attribute__((__used__))
to the affected function definitions. Alternatively you could make fake references to them, e.g. by storing their addresses to dummy volatile objects or using their addresses in input constraints to empty inline asm blocks. As yet another alternative, there may be a way to redo whatever you're doing with asm source files or linked scripts to make your interrupt table at the C level, with appropriate structs/arrays in special sections, so that the compiler can actually see the references without you having to fake them.
Thank you .. you have raised some good questions. The exception handlers are referenced in the same file that defines the default handlers:const pFunc __Vectors __attribute__ ((section(".vectors"))) = { /* Cortex-M Exception Handlers */ (pFunc)&__StackTop, /* Initial Stack Pointer */ Reset_Handler, /* Reset Handler */ NMI_Handler,
I will try marking this symbol as used and I'll let you know! But for the handlers themselves .. marking them as used does not help.
– RushPL
Jan 1 at 17:20
1
@RushPL: OK, then where is__Vectors
referenced from? I suspect this is your problem.
– R..
Jan 1 at 18:29
Thanks! Vectors is being referenced only by the linker script. I spent the last hour trying different things and indeed marking the__Vectors
symbol with theused
attribute, helps. It wasn't the whole solution though! Other important takeaway is that weak functions and their overrides should be compiled in the same way (either all LTO, or all no LTO) Having a basic weak implementation compiled with -fno-lto and its override in LTO (or vice versa) was causing the override to not work. In the end .. almost all of my code is compiling with LTO! Newlib overrides being the only exception.
– RushPL
Jan 1 at 18:54
@RushPL: I think you're mistaken about weak and the mechanism of your problem is something different. Strong definitions, if linked at all, replace weak definitions before any garbage collection of unreferenced code can happen; if this were not the case, LTO would break semantics badly and would be unusable for anything using weak definitions. Perhaps your strong definitions are in object files inside a.a
library and nothing causes those files to be pulled into the link at all? Maybe--whole-archive
is broken with LTO?
– R..
Jan 1 at 19:24
You may be right R.., I will try to find out what's going on and I'll keep this thread updated. Thanks again for your help.
– RushPL
Jan 2 at 10:51
|
show 2 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53997196%2fgcc-8-for-arm-in-lto-mode-is-removing-interrupt-handlers-and-weak-functions-ho%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Where are your interrupt handlers referenced from? Just like unreferenced static functions and objects will be removed from a single translation unit, external ones that are unused will be removed during LTO. In order to prevent this (and in order for your program to be valid anyway in the abstract model) there needs to be some chain of references, starting from the entry point, leading to the functions and objects; if none exists, then you're not actually using them in your program.
If the reference is from a linker script or asm source file, it's possible that this is a bug in LTO, and it's not seeing the references like it should. In this case you might be able to apply a hack like __attribute__((__used__))
to the affected function definitions. Alternatively you could make fake references to them, e.g. by storing their addresses to dummy volatile objects or using their addresses in input constraints to empty inline asm blocks. As yet another alternative, there may be a way to redo whatever you're doing with asm source files or linked scripts to make your interrupt table at the C level, with appropriate structs/arrays in special sections, so that the compiler can actually see the references without you having to fake them.
Thank you .. you have raised some good questions. The exception handlers are referenced in the same file that defines the default handlers:const pFunc __Vectors __attribute__ ((section(".vectors"))) = { /* Cortex-M Exception Handlers */ (pFunc)&__StackTop, /* Initial Stack Pointer */ Reset_Handler, /* Reset Handler */ NMI_Handler,
I will try marking this symbol as used and I'll let you know! But for the handlers themselves .. marking them as used does not help.
– RushPL
Jan 1 at 17:20
1
@RushPL: OK, then where is__Vectors
referenced from? I suspect this is your problem.
– R..
Jan 1 at 18:29
Thanks! Vectors is being referenced only by the linker script. I spent the last hour trying different things and indeed marking the__Vectors
symbol with theused
attribute, helps. It wasn't the whole solution though! Other important takeaway is that weak functions and their overrides should be compiled in the same way (either all LTO, or all no LTO) Having a basic weak implementation compiled with -fno-lto and its override in LTO (or vice versa) was causing the override to not work. In the end .. almost all of my code is compiling with LTO! Newlib overrides being the only exception.
– RushPL
Jan 1 at 18:54
@RushPL: I think you're mistaken about weak and the mechanism of your problem is something different. Strong definitions, if linked at all, replace weak definitions before any garbage collection of unreferenced code can happen; if this were not the case, LTO would break semantics badly and would be unusable for anything using weak definitions. Perhaps your strong definitions are in object files inside a.a
library and nothing causes those files to be pulled into the link at all? Maybe--whole-archive
is broken with LTO?
– R..
Jan 1 at 19:24
You may be right R.., I will try to find out what's going on and I'll keep this thread updated. Thanks again for your help.
– RushPL
Jan 2 at 10:51
|
show 2 more comments
Where are your interrupt handlers referenced from? Just like unreferenced static functions and objects will be removed from a single translation unit, external ones that are unused will be removed during LTO. In order to prevent this (and in order for your program to be valid anyway in the abstract model) there needs to be some chain of references, starting from the entry point, leading to the functions and objects; if none exists, then you're not actually using them in your program.
If the reference is from a linker script or asm source file, it's possible that this is a bug in LTO, and it's not seeing the references like it should. In this case you might be able to apply a hack like __attribute__((__used__))
to the affected function definitions. Alternatively you could make fake references to them, e.g. by storing their addresses to dummy volatile objects or using their addresses in input constraints to empty inline asm blocks. As yet another alternative, there may be a way to redo whatever you're doing with asm source files or linked scripts to make your interrupt table at the C level, with appropriate structs/arrays in special sections, so that the compiler can actually see the references without you having to fake them.
Thank you .. you have raised some good questions. The exception handlers are referenced in the same file that defines the default handlers:const pFunc __Vectors __attribute__ ((section(".vectors"))) = { /* Cortex-M Exception Handlers */ (pFunc)&__StackTop, /* Initial Stack Pointer */ Reset_Handler, /* Reset Handler */ NMI_Handler,
I will try marking this symbol as used and I'll let you know! But for the handlers themselves .. marking them as used does not help.
– RushPL
Jan 1 at 17:20
1
@RushPL: OK, then where is__Vectors
referenced from? I suspect this is your problem.
– R..
Jan 1 at 18:29
Thanks! Vectors is being referenced only by the linker script. I spent the last hour trying different things and indeed marking the__Vectors
symbol with theused
attribute, helps. It wasn't the whole solution though! Other important takeaway is that weak functions and their overrides should be compiled in the same way (either all LTO, or all no LTO) Having a basic weak implementation compiled with -fno-lto and its override in LTO (or vice versa) was causing the override to not work. In the end .. almost all of my code is compiling with LTO! Newlib overrides being the only exception.
– RushPL
Jan 1 at 18:54
@RushPL: I think you're mistaken about weak and the mechanism of your problem is something different. Strong definitions, if linked at all, replace weak definitions before any garbage collection of unreferenced code can happen; if this were not the case, LTO would break semantics badly and would be unusable for anything using weak definitions. Perhaps your strong definitions are in object files inside a.a
library and nothing causes those files to be pulled into the link at all? Maybe--whole-archive
is broken with LTO?
– R..
Jan 1 at 19:24
You may be right R.., I will try to find out what's going on and I'll keep this thread updated. Thanks again for your help.
– RushPL
Jan 2 at 10:51
|
show 2 more comments
Where are your interrupt handlers referenced from? Just like unreferenced static functions and objects will be removed from a single translation unit, external ones that are unused will be removed during LTO. In order to prevent this (and in order for your program to be valid anyway in the abstract model) there needs to be some chain of references, starting from the entry point, leading to the functions and objects; if none exists, then you're not actually using them in your program.
If the reference is from a linker script or asm source file, it's possible that this is a bug in LTO, and it's not seeing the references like it should. In this case you might be able to apply a hack like __attribute__((__used__))
to the affected function definitions. Alternatively you could make fake references to them, e.g. by storing their addresses to dummy volatile objects or using their addresses in input constraints to empty inline asm blocks. As yet another alternative, there may be a way to redo whatever you're doing with asm source files or linked scripts to make your interrupt table at the C level, with appropriate structs/arrays in special sections, so that the compiler can actually see the references without you having to fake them.
Where are your interrupt handlers referenced from? Just like unreferenced static functions and objects will be removed from a single translation unit, external ones that are unused will be removed during LTO. In order to prevent this (and in order for your program to be valid anyway in the abstract model) there needs to be some chain of references, starting from the entry point, leading to the functions and objects; if none exists, then you're not actually using them in your program.
If the reference is from a linker script or asm source file, it's possible that this is a bug in LTO, and it's not seeing the references like it should. In this case you might be able to apply a hack like __attribute__((__used__))
to the affected function definitions. Alternatively you could make fake references to them, e.g. by storing their addresses to dummy volatile objects or using their addresses in input constraints to empty inline asm blocks. As yet another alternative, there may be a way to redo whatever you're doing with asm source files or linked scripts to make your interrupt table at the C level, with appropriate structs/arrays in special sections, so that the compiler can actually see the references without you having to fake them.
answered Jan 1 at 16:58
R..R..
157k26261564
157k26261564
Thank you .. you have raised some good questions. The exception handlers are referenced in the same file that defines the default handlers:const pFunc __Vectors __attribute__ ((section(".vectors"))) = { /* Cortex-M Exception Handlers */ (pFunc)&__StackTop, /* Initial Stack Pointer */ Reset_Handler, /* Reset Handler */ NMI_Handler,
I will try marking this symbol as used and I'll let you know! But for the handlers themselves .. marking them as used does not help.
– RushPL
Jan 1 at 17:20
1
@RushPL: OK, then where is__Vectors
referenced from? I suspect this is your problem.
– R..
Jan 1 at 18:29
Thanks! Vectors is being referenced only by the linker script. I spent the last hour trying different things and indeed marking the__Vectors
symbol with theused
attribute, helps. It wasn't the whole solution though! Other important takeaway is that weak functions and their overrides should be compiled in the same way (either all LTO, or all no LTO) Having a basic weak implementation compiled with -fno-lto and its override in LTO (or vice versa) was causing the override to not work. In the end .. almost all of my code is compiling with LTO! Newlib overrides being the only exception.
– RushPL
Jan 1 at 18:54
@RushPL: I think you're mistaken about weak and the mechanism of your problem is something different. Strong definitions, if linked at all, replace weak definitions before any garbage collection of unreferenced code can happen; if this were not the case, LTO would break semantics badly and would be unusable for anything using weak definitions. Perhaps your strong definitions are in object files inside a.a
library and nothing causes those files to be pulled into the link at all? Maybe--whole-archive
is broken with LTO?
– R..
Jan 1 at 19:24
You may be right R.., I will try to find out what's going on and I'll keep this thread updated. Thanks again for your help.
– RushPL
Jan 2 at 10:51
|
show 2 more comments
Thank you .. you have raised some good questions. The exception handlers are referenced in the same file that defines the default handlers:const pFunc __Vectors __attribute__ ((section(".vectors"))) = { /* Cortex-M Exception Handlers */ (pFunc)&__StackTop, /* Initial Stack Pointer */ Reset_Handler, /* Reset Handler */ NMI_Handler,
I will try marking this symbol as used and I'll let you know! But for the handlers themselves .. marking them as used does not help.
– RushPL
Jan 1 at 17:20
1
@RushPL: OK, then where is__Vectors
referenced from? I suspect this is your problem.
– R..
Jan 1 at 18:29
Thanks! Vectors is being referenced only by the linker script. I spent the last hour trying different things and indeed marking the__Vectors
symbol with theused
attribute, helps. It wasn't the whole solution though! Other important takeaway is that weak functions and their overrides should be compiled in the same way (either all LTO, or all no LTO) Having a basic weak implementation compiled with -fno-lto and its override in LTO (or vice versa) was causing the override to not work. In the end .. almost all of my code is compiling with LTO! Newlib overrides being the only exception.
– RushPL
Jan 1 at 18:54
@RushPL: I think you're mistaken about weak and the mechanism of your problem is something different. Strong definitions, if linked at all, replace weak definitions before any garbage collection of unreferenced code can happen; if this were not the case, LTO would break semantics badly and would be unusable for anything using weak definitions. Perhaps your strong definitions are in object files inside a.a
library and nothing causes those files to be pulled into the link at all? Maybe--whole-archive
is broken with LTO?
– R..
Jan 1 at 19:24
You may be right R.., I will try to find out what's going on and I'll keep this thread updated. Thanks again for your help.
– RushPL
Jan 2 at 10:51
Thank you .. you have raised some good questions. The exception handlers are referenced in the same file that defines the default handlers:
const pFunc __Vectors __attribute__ ((section(".vectors"))) = { /* Cortex-M Exception Handlers */ (pFunc)&__StackTop, /* Initial Stack Pointer */ Reset_Handler, /* Reset Handler */ NMI_Handler,
I will try marking this symbol as used and I'll let you know! But for the handlers themselves .. marking them as used does not help.– RushPL
Jan 1 at 17:20
Thank you .. you have raised some good questions. The exception handlers are referenced in the same file that defines the default handlers:
const pFunc __Vectors __attribute__ ((section(".vectors"))) = { /* Cortex-M Exception Handlers */ (pFunc)&__StackTop, /* Initial Stack Pointer */ Reset_Handler, /* Reset Handler */ NMI_Handler,
I will try marking this symbol as used and I'll let you know! But for the handlers themselves .. marking them as used does not help.– RushPL
Jan 1 at 17:20
1
1
@RushPL: OK, then where is
__Vectors
referenced from? I suspect this is your problem.– R..
Jan 1 at 18:29
@RushPL: OK, then where is
__Vectors
referenced from? I suspect this is your problem.– R..
Jan 1 at 18:29
Thanks! Vectors is being referenced only by the linker script. I spent the last hour trying different things and indeed marking the
__Vectors
symbol with the used
attribute, helps. It wasn't the whole solution though! Other important takeaway is that weak functions and their overrides should be compiled in the same way (either all LTO, or all no LTO) Having a basic weak implementation compiled with -fno-lto and its override in LTO (or vice versa) was causing the override to not work. In the end .. almost all of my code is compiling with LTO! Newlib overrides being the only exception.– RushPL
Jan 1 at 18:54
Thanks! Vectors is being referenced only by the linker script. I spent the last hour trying different things and indeed marking the
__Vectors
symbol with the used
attribute, helps. It wasn't the whole solution though! Other important takeaway is that weak functions and their overrides should be compiled in the same way (either all LTO, or all no LTO) Having a basic weak implementation compiled with -fno-lto and its override in LTO (or vice versa) was causing the override to not work. In the end .. almost all of my code is compiling with LTO! Newlib overrides being the only exception.– RushPL
Jan 1 at 18:54
@RushPL: I think you're mistaken about weak and the mechanism of your problem is something different. Strong definitions, if linked at all, replace weak definitions before any garbage collection of unreferenced code can happen; if this were not the case, LTO would break semantics badly and would be unusable for anything using weak definitions. Perhaps your strong definitions are in object files inside a
.a
library and nothing causes those files to be pulled into the link at all? Maybe --whole-archive
is broken with LTO?– R..
Jan 1 at 19:24
@RushPL: I think you're mistaken about weak and the mechanism of your problem is something different. Strong definitions, if linked at all, replace weak definitions before any garbage collection of unreferenced code can happen; if this were not the case, LTO would break semantics badly and would be unusable for anything using weak definitions. Perhaps your strong definitions are in object files inside a
.a
library and nothing causes those files to be pulled into the link at all? Maybe --whole-archive
is broken with LTO?– R..
Jan 1 at 19:24
You may be right R.., I will try to find out what's going on and I'll keep this thread updated. Thanks again for your help.
– RushPL
Jan 2 at 10:51
You may be right R.., I will try to find out what's going on and I'll keep this thread updated. Thanks again for your help.
– RushPL
Jan 2 at 10:51
|
show 2 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53997196%2fgcc-8-for-arm-in-lto-mode-is-removing-interrupt-handlers-and-weak-functions-ho%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown