<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
Hi Lang<br>
<br>
Thanks for explaining the new mocking and testing feature in the
llvm-jitlink tool in such great detail! Indeed, it sounds like an
interesting by-product of your jitlink efforts.<br>
<br>
"a lot of non-trivial surface area" is a very polite description of
the C++ symbols disaster :)<br>
<br>
Best<br>
Stefan<br>
<br>
<div class="moz-cite-prefix">On 10/08/2020 08:26, Lang Hames wrote:<br>
</div>
<blockquote type="cite"
cite="mid:CALLttgp_fjpCu1pDoSx7Oc1y0Ov7d2H2PbJdiboMgu8aP2Xscg@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="ltr">Hi All,
<div><br>
</div>
<div>There was no update last week -- I'm still trying to get
back into a regular schedule.</div>
<div><br>
</div>
<div>Open-source changes since the last update were:</div>
<div><br>
</div>
<div>(1) Some bug fixes for JITLink MachO / arm64 support
(PAGE21/PAGEOFF12 now handle addends correctly).</div>
<div>(2) llvm-jitlink now supports loading archives as well as
relocatable objects.</div>
<div>(3) llvm-jitlink now supports basic object-file level
mocking and testing.</div>
<div><br>
</div>
<div>That last one is unusual so I want to expand on it. The
llvm-jitlink tool acquired a couple of new options to support
this feature: "--phony-externals" which resolves all otherwise
unresolved symbols to null instead of erroring, and "-harness"
which allows a set of objects to be designated as a test
harness, with the regular object files implicitly treated as
objects to be tested. If the -harness option is passed
llvm-jitlink installs a JITLink plugin to make some
modifications to the usual linker rules:</div>
<div><br>
</div>
<div>-- All symbols referenced by the harness object(s) are
promoted to default visibility so that the harness can
directly access static symbols inside the test object(s)</div>
<div>-- All symbols defined by the harness object(s) override
(rather than clashing with) symbols defined in the test
object(s).</div>
<div><br>
</div>
<div>With these modifications in place we can selectively test
functions in an object file by mocking their callees. For
example, suppose we have an object file, test_code.o, compiled
from the following C source (which we do not have access to):</div>
<div><br>
</div>
<div><font face="monospace">void irrelevant_function() {
irrelevant_external(); }</font></div>
<div><font face="monospace"><br>
</font></div>
<div><font face="monospace">int function_to_mock(int X) {</font></div>
<div><font face="monospace"> return /* some function of X */;</font></div>
<div><font face="monospace">}<br>
</font></div>
<div><font face="monospace"><br>
</font></div>
<div><font face="monospace">static void function_to_test() {</font></div>
<div><font face="monospace"> ...</font></div>
<div><font face="monospace"> int Y = function_to_mock();</font></div>
<div><font face="monospace"> printf("Y is %i\n", Y);</font></div>
<div><font face="monospace">}</font></div>
<div><br>
</div>
<div>We would like to know how function_to_test behaves when
we change the behavior of function_to_mock. We can do this by
writing a test harness:</div>
<div><br>
</div>
<div><font face="monospace">void function_to_test();</font></div>
<div><font face="monospace"><br>
</font></div>
<div><font face="monospace">int function_to_mock(int X) {</font></div>
<div><font face="monospace"> printf("used mock utility
function\n");</font></div>
<div><font face="monospace"> return 42;</font></div>
<div><font face="monospace">}</font></div>
<div><font face="monospace"><br>
</font></div>
<div><font face="monospace">int main(int argc, char *argv[]) {</font></div>
<div><font face="monospace"> function_to_test():</font></div>
<div><font face="monospace"> return 0; </font></div>
<div><font face="monospace">}</font></div>
<div><br>
</div>
<div>This harness code could not be linked against test_code.o
under normal circumstances: function_to_test is static and
will fail to resolve from the harness code, function_to_mock
is a duplicate definition, and irrelevant_external is
undefined. Our new llvm-jitlink options take care of these
issues however, and running the test looks like:</div>
<div><br>
</div>
<div><span style="font-family:monospace">% clang -c -o
test_code_harness.o test_code_harness.c</span><br>
</div>
<div><font face="monospace">% llvm-jitlink -phony-externals
test_code.o -harness test_code_harness.o</font></div>
<div><font face="monospace">used mock utility function</font></div>
<div><font face="monospace">Y is 42</font></div>
<div><br>
</div>
<div>This utility may be of interest to people who want to
perform some very late testing on build products to verify
that compiled code behaves as expected. On basic C test cases
it works reasonably well. C++ test cases are another matter:
Any code involving classes tends to have a lot of non-trivial
surface area (e.g. vtables) that would require great care to
mock. Perhaps we need a new tool to tackle that problem.</div>
<div><br>
</div>
<div>In the meantime, if nothing else this provides a neat
example of how JITLink plugins can be used to modify the
default linker behavior.</div>
<div><br>
</div>
<div>Regards,</div>
<div>Lang. </div>
</div>
</blockquote>
<pre class="moz-signature" cols="72">--
<a class="moz-txt-link-freetext" href="https://flowcrypt.com/pub/stefan.graenitz@gmail.com">https://flowcrypt.com/pub/stefan.graenitz@gmail.com</a></pre>
</body>
</html>