Summary: | relax_segment can't stabilize .gcc_except_table | ||
---|---|---|---|
Product: | binutils | Reporter: | Andreas Schwab <schwab> |
Component: | gas | Assignee: | Alan Modra <amodra> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | bug-binutils, hjl.tools, jeremip11, rprichard |
Priority: | P2 | ||
Version: | 2.18 | ||
Target Milestone: | --- | ||
Host: | Target: | x86-64-*-* | |
Build: | Last reconfirmed: | ||
Attachments: |
Testcase
A kludge |
Description
Andreas Schwab
2007-02-12 16:31:34 UTC
Created attachment 1549 [details]
Testcase
The problem is with rs_leb128 processing. When size needed for the new value is 0x3fff is 2 and the old size is 3, growth is -1. Then the next time the new value becomes 0x4000 and its size becomes 3. That is an infinite loop. Created attachment 1564 [details]
A kludge
This kludge compiles the testcase. But I am not sure if it is correct.
A patch is posted at http://sourceware.org/ml/binutils/2007-02/msg00280.html Reduced testcase. .data .align 4 .byte 0, 0 .uleb128 end - start start: .space 128*128 - 1 /* or -2 or -3 */ .align 4 end: I don't believe this is a gas bug. Instead, I believe gcc is asking the impossible of gas. The original testcase or the reduced one above has no correct solution. ie. this problem is caused by a design fault in the layout of .gcc_except_table data. Consider: We know the uleb128 is either two or three bytes long. If end-start is 128*128-1 or somewhat less, then it will be two bytes. If 128*128 or a little larger, then it will be three bytes. But, if the uleb128 is two bytes in size, then end-start is 128*128 If the uleb128 is three bytes, then end-start is 128*128-1 This results in a contradiction. Assembler can do better to help gcc. We can turn it into .data .align 4 .byte 0, 0 .uleb128 end - start start: .space 128*128 - 1 /* or -2 or -3 */ .align 8 end: Yes, we can modify the output, but we must do so in a way that does not confuse consumers of .gcc_except_table. I don't believe changing the .align is correct, because data normally follows the .align (a number of .long's before the end label). Changing alignment in a way that cures the uleb128 problem necessarily inserts zero bytes, which I think will confuse the unwinder. The assembly code in question is .align 4 .long DW.ref._ZTIN10DSEBuiltin17ExceptionDeadLockE-. .long DW.ref._ZTI7DSEBomb-. .long DW.ref._ZTI12DSEException-. .long DW.ref._ZTISt9exception-. .long 0 .LLSDATT5533: If those data are accessed via .LLSDATT5533 as base, it is s safe to change .align 4 to .align 8. I think .align 8 is compatible with .align 4. If it isn't true, it is a bug in assembly code. Andreas, can you upload the preprocessed C++ source and assembly code generated with -dA? A patch is posted at http://sourceware.org/ml/binutils/2007-03/msg00107.html Ah, yes, it does seem as if the type_info table is stored in reverse order and accessed from the end. In that case increasing alignment padding should work. http://sourceware.org/ml/binutils-cvs/2007-03/msg00070.html http://sourceware.org/ml/binutils-cvs/2007-03/msg00071.html Fixed FWIW: This issue affects the LLVM assembler, too: https://bugs.llvm.org/show_bug.cgi?id=35809. |