This is really a linker / object-file question, but tagging with assembly since compilers never do this. (Although maybe they could!)
Consider this function, where
There's a simple way to make this look totally normal: put a non-global label in front of the code. This makes it look like (or actually be) a static
helper function.
Non-global functions can call each other with any calling convention they want. C compilers can even make code like this with link-time / whole-program optimization, or even just optimization of static
functions within a compilation unit. Jumps (rather than calls) to another function are already used for tail-call optimization.
The "helper function" code can jump into the main function at somewhere other than the entry point. I'm sure that's not a problem for linkers though. That would only break if a linker changed the distance between the helper and the main function (by inserting something between them) without adjusting relative jumps that cross the gap that it widened. I don't think any linker would insert anything that way in the first place, and doing so without fixing any branches is clearly a bug.
I'm not sure if there are any pitfalls in generating .size
ELF metadata. I think I've read that it's important for functions that will be linked into shared libraries.
The following should work fine with any tool that deals with object files:
.globl __nextafter_pjc // double __nextafter_pjc(double x, double y)
.p2align 6 // unrealistic 64B alignment, just for the sake of argument
nextafter_helper: # not a local label, but not .globl either
.Lequal_or_unordered:
jp .Lunordered
movaps %xmm1, %xmm0 # ISO C11 requires returning y, not x. (matters for -0.0 == +0.0)
ret
######### Function entry point / global symbol here #############
// .p2align something?
__nextafter_pjc:
ucomisd %xmm1, %xmm0
je .Lequal_or_unordered
...
ret
We don't need a plain label and a "local" label, but using different labels for different purposes means less modification is needed when re-arranging things. (e.g. you can put the .Lequal_or_unordered
block somewhere else without renaming it back to a .L
and changing all the jumps that target it.) nextafter_equal_or_unordered
would work as a single name.