1

In the file /usr/include/dirent.h of MacOSX10.14 I see this line:

struct _telldir;        /* forward reference */

In the same file the identifier is used:

 struct _telldir *__dd_td;

Nowhere else in the include files is _telldir defined but in the same file the function telldir is declared:

long telldir(DIR *) __DARWIN_ALIAS_I(telldir);

I see the __DARWIN_ALIAS_I macro is defined as

#define __DARWIN_ALIAS_I(sym)       __asm("_" __STRING(sym) __DARWIN_SUF_64_BIT_INO_T __DARWIN_SUF_UNIX03)**

I understand this is "inline assembler" and that this defines _telldir but I would like to know more about this definition.

Thanks in advance

diciotto
  • 69
  • 3

1 Answers1

1

It's not exactly inline asm as in instructions, it's just overriding the name mangling for symbol names. (e.g. static int foo on MacOS normally has a symbol name of _foo. e.g. in the compiler asm output, you'd have _foo: .long 0).

In GNU C, int foo asm("foobar"); has an asm symbol name of foobar instead of the default _foo. See https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html and this SO answer: Adding leading underscores to assembly symbols with GCC on Win32?

Try it yourself on https://godbolt.org/ if you're curious.


In this case, we have C preprocessor string literal concatenation of the macro expansions. e.g.

"_" "telldir" "_ino64"

is exactly equivalent to "_telldir_ino64" in all contexts, including in
long telldir(DIR *dirp) asm("_" "telldir" "_ino64");

This use-case appears to be choosing which telldir implementation in libc by setting the name based on a few other CPP macros. So if __DARWIN_SUF_64_BIT_INO_T is defined as "_ino64" and __DARWIN_SUF_UNIX03 is defined as empty or /**/, then this sets the symbol name to "_telldir_ino64"

(No idea how MacOS would typically actually define those other macros, but the syntax of the line you show is just string literal concatenation inside an asm("") to set the symbol name.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Thanks Peter for you very detailed explanation, however I'm still a bit baffled by the syntax of __asm("xxx") which according to your answer is used to change the function name in symbol table. I googled a lot but can't find such usage, the closest one is https://learn.microsoft.com/en-us/cpp/assembler/inline/using-operators-in-asm-blocks?view=msvc-170 but it only mentions __asm{...} where ... is actual assembly code. Could you collaborate more? Much appreciated. – mzoz Jan 03 '23 at 13:06
  • 1
    @mzoz: My answer links the docs for this usage of it: https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html . If you want the C name to be `foo()`, but the compiler to emit `call bar` in the asm, you use `int foo(void) asm("bar")`. – Peter Cordes Jan 03 '23 at 13:09
  • cool got it so __asm is just a macos variant of asm in gcc – mzoz Jan 04 '23 at 13:30
  • 1
    @mzoz: GCC and clang both accept `asm`, `__asm__`, and `__asm` as equivalent for all targets. In `-std=c11` mode (instead of the default `-std=gnu11`), `asm` isn't recognized, to keep the namespace clean. https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html . It seems `_asm` is only MSVC. https://godbolt.org/z/jv9nTvrGK IDK why MacOS devs picked `__asm` instead of the GCC-documented `__asm__`. Maybe clang does document `__asm`. – Peter Cordes Jan 04 '23 at 13:34