[llvm] [SystemZ][z/OS] Use a function descriptor for external functions in initializers (PR #226682)

MMS IT GmbH via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 27 08:34:23 PDT 2026


mms-it-ch wrote:

A problem with this approach that showed up since: with a function descriptor of its own in the
ADA, a pointer to an **external** function from a static initializer is callable, but it does not
compare equal to the address of the same function taken in code.

```c
#include <stdio.h>
void f(void) {}
static void g(void) {}
void (*pf)(void) = f;
void (*pg)(void) = g;
int main(void) {
  void (*volatile lf)(void) = f;
  void (*volatile lg)(void) = g;
  printf("f: %s\n", lf == pf ? "equal" : "DIFFERENT");
  printf("g: %s\n", lg == pg ? "equal" : "DIFFERENT");
  return !(lf == pf && lg == pg);
}
```

With this patch, on z/OS 3.1: `f: DIFFERENT`, `g: equal`.

Code takes the address of a non-internal function from an ADA slot `MO_ADA_INDIRECT_FUNC_DESC`
(`DC VD(f at indirect)`), which the binder resolves to the function descriptor of `f`. The initializer
gets `DC AD(AD(<name>#S)+XL8'56')`, i.e. the separate descriptor `DC RD(f)` / `DC VD(f)` in the ADA.

Using the indirect symbol in the initializer as well fixes it (both lines `equal` on z/OS):

```cpp
  if (IsFunc) {
    OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
    const GlobalValue *FGV = GA ? static_cast<const GlobalValue *>(GA)
                                : static_cast<const GlobalValue *>(FV);
    if (!FGV->hasInternalLinkage() && !FGV->hasPrivateLinkage()) {
      // Same descriptor as code taking the address; the slot is inserted only
      // to have the indirect symbol defined.
      ADATable.insert(Sym, SystemZII::MO_ADA_INDIRECT_FUNC_DESC);
      MCSymbol *Alias = OutContext.getOrCreateSymbol(
          Twine(Sym->getName()).concat("@indirect"));
      return MCSpecifierExpr::create(MCSymbolRefExpr::create(Alias, OutContext),
                                     SystemZ::S_VCon, OutContext);
    }
    // internal functions: function descriptor in the ADA, as before
```

The initializer then becomes `DC VD(f at indirect)`. `zos-lower-constant.ll` would check
`DC VD(bar at indirect)` for `@func_e` and the ADA slot `pointer to function descriptor bar`.
This PR should be updated accordingly before it is merged. (Found with method pointers in typed constants in Free Pascal,
which compared unequal to `@Method`.)

---
*Drafted with the help of Claude Code (Anthropic), in line with the LLVM AI Tool Use Policy. The
test was run on z/OS 3.1 with the results given above.*


https://github.com/llvm/llvm-project/pull/226682


More information about the llvm-commits mailing list