<div dir="ltr"><div>Hi,</div><div><br></div><div>I'm investigating the size of Clang's generated binaries relative to GCC, when targeting Android, and I've noticed that Clang's exception tables are much larger -- the .ARM.extab section is about 2.5 times as large in two examples.</div><div><br></div><div>I noticed a couple of differences between Clang and GCC:</div><div><div><br></div><div><div>1. <b>ULEB128 encoding.</b></div><div><br></div><div>In the call site table, GCC encodes offsets using a ULEB128 variable-length encoding, whereas LLVM uses fixed-size 32-bit values (udata4).</div><div><br></div><div>Switching to ULEB128 is a large size improvement. For instance, I'm currently playing with Qt5, and the libQt5Core.so binary is about 4MB with a 215KB .ARM.extab section. Switching the encoding cuts the .ARM.extab section down to 100KB for an overall file size reduction of about 2.9%.</div><div><br></div><div>There is a complication with ULEB128: there is a ULEB128 field near the front of the EH table pointing to aligned typeinfo values near the end of the table. It can look like this:<br></div><div><br></div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">     <span> </span></span>  .uleb128 (.ttbase - .start)   # offset to aligned type infos</div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline"><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">   <span> </span></span>.start</span>:</div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">     <span> </span></span>  ...</div><div>        .balign 4<br></div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">   <span>   </span></span>  .long _ZTIi   # type info for int</div><div>    .ttbase:</div><div><br></div><div>An assembler might start by assuming that the .uleb128 directive occupies only 1 byte, then calculate (.ttbase - .start) as 0x80, which requires 2 bytes. Increasing the .uleb128 directive to 2 bytes could reduce the (.ttbase - .start) difference to 0x7F, though, which can be represented with a 1-byte uleb128. (The LLVM assembler apparently alternates between these two encodings forever -- <a href="https://bugs.llvm.org/show_bug.cgi?id=35809" style="color:rgb(17,85,204);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255)" target="_blank">https://bugs.llvm.org/show_bug<wbr>.cgi?id=35809</a>.)</div><div><br></div><div>The <span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">EHStreamer::<wbr>emitExceptionTable code currently avoids this complication by calculating the size of everything in the EH table before-hand, and then aligning type infos using extra-large ULEB128 values (e.g. by encoding 0x20 as A0 80 00). <span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">Calculating the size of the EH table like this, though, requires using udata4 for code offsets, because we don't know how large the code offsets are until we've finished assembling the object file.</span></span></div><div><br></div><div>Here's the comment from EHStreamer::emitExceptionTable describing the problem:</div><div><span style="text-align:start;text-indent:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline"><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px;text-align:start;text-indent:0px;text-decoration-style:initial;text-decoration-color:initial"><br></div><blockquote class="gmail_quote" style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px;margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex;text-align:start">The type infos need to be aligned. GCC does this by inserting padding just<br>before the type infos. However, this changes the size of the exception<br>table, so you need to take this into account when you output the exception<br>table size. However, the size is output using a variable length encoding.<br>So by increasing the size by inserting padding, you may increase the number<br>of bytes used for writing the size. If it increases, say by one byte, then<br>you now need to output one less byte of padding to get the type infos<br>aligned. However this decreases the size of the exception table. This<br>changes the value you have to output for the exception table size. Due to<br>the variable length encoding, the number of bytes used for writing the<br>length may decrease. If so, you then have to increase the amount of<br>padding. And so on. If you look carefully at the GCC code you will see that<br>it indeed does this in a loop, going on and on until the values stabilize.<br>We chose another solution: don't output padding inside the table like GCC<br>does, instead output it before the table.</blockquote><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px">I have patches to LLVM that switch the encoding over to ULEB128. Generally, they make LLVM behave like GCC. Specifically they:<br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"> - Output .uleb128 label differences for (a) the type table base offset, (b) the size of the call site table, and (c) code offsets in the call site table</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"> - Align the type table by inserting padding before them.</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"> - Guarantee LLVM assembler termination by never shrinking an LEB fragment (and using extra-large LEB encodings). This patch is trivial; it's posted on the LLVM bugzilla. It doesn't make the LLVM assembler behave the same way as the GNU assembler, though -- I don't understand what GNU's assembler is doing.<br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px">The complication is dealt with in the assembler, via the general relaxation system, and in LLVM's case, the sizes of the LEB128 fragments should stabilize very quickly (in one or two iterations). I'm not sure what other assemblers do, but I'm inclined to think the change is still OK -- we're simply matching what GCC does.</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px">Is there another problem I'm not seeing? Has anyone else noticed this size difference?</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px"><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline"><br></span></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-transform:none;white-space:normal;word-spacing:0px">2. <b>Termination landing pads.</b><br></div></span></div><div><br></div><div>Clang sometimes uses a landing pad that calls <span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">__clang_call_terminate to terminate the program</span>. GCC instead leaves a gap in the call site table, and the personality routine calls <span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">std::</span>terminate. For the 4MB libQt5Core.so sample I'm looking at, I think it'd reduce the size of .text and .ARM.extab by maybe 7000 bytes (about 0.18%). (I see about 500 calls to __clang_call_terminate, and I estimate 14 bytes per call, assuming the call site table is using ULEB128 already.)</div><div><br></div><div>I tried to implement this in LLVM, but couldn't find a good way to represent the calls that must be omitted from the call site table.</div><div><br></div><div>Is there a reason LLVM doesn't handle this like GCC?</div><div><br></div><div>Examples:</div><div> - C++03: <a href="https://godbolt.org/g/7BYbdG">https://godbolt.org/g/7BYbdG</a></div><div> - C++11: <a href="https://godbolt.org/g/bnHLvH">https://godbolt.org/g/bnHLvH</a></div><div><br></div><div>Thanks,</div><div>-Ryan</div><div><br></div></div></div></div>