graphitemaster / incbin

Include binary files in C/C++
The Unlicense
938 stars 87 forks source link

INCBIN_EXTERN doesn't work on AppleClang 9.1.0.9020039 #30

Closed andyli closed 4 years ago

andyli commented 6 years ago

The build error: https://travis-ci.org/andyli/incbin/builds/367773037

Undefined symbols for architecture x86_64:
  "_gLoremData", referenced from:
      _main in asserts.c.o
  "_gLoremEnd", referenced from:
      _main in asserts.c.o
  "_gLoremSize", referenced from:
      _main in asserts.c.o
  "_gOnebyteData", referenced from:
      _main in asserts.c.o
  "_gOnebyteEnd", referenced from:
      _main in asserts.c.o
  "_gOnebyteSize", referenced from:
      _main in asserts.c.o
  "_gSevenbytesData", referenced from:
      _main in asserts.c.o
  "_gSevenbytesEnd", referenced from:
      _main in asserts.c.o
  "_gSevenbytesSize", referenced from:
      _main in asserts.c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [asserts] Error 1
make[1]: *** [CMakeFiles/asserts.dir/all] Error 2
make: *** [all] Error 2

My test code can be seen at https://github.com/andyli/incbin/commit/47c3b76c833c9d40d13d1dbf84274638db9d6911

Notice that the test passed in the Linux builds.

graphitemaster commented 6 years ago

Looks like maybe Apple Clang uses different name mangling for symbols, can you check if it defines __USER_LABEL_PREFIX__ and maybe dump the contents of the object file's symbols with nm -g file.o. Once I know what is happening here I can fix the header to use the right prefix

andyli commented 6 years ago

__USER_LABEL_PREFIX__ is defined as _.

$ nm -g CMakeFiles/asserts.dir/resources.c.o
                 U gLoremData
                 U gLoremEnd
                 U gLoremSize
                 U gOnebyteData
                 U gOnebyteEnd
                 U gOnebyteSize
                 U gSevenbytesData
                 U gSevenbytesEnd
                 U gSevenbytesSize
$ nm CMakeFiles/asserts.dir/resources.c.o
0000000000000000 s _gLoremData
00000000000003c2 s _gLoremEnd
00000000000003d0 s _gLoremSize
00000000000003e0 s _gOnebyteData
00000000000003e1 s _gOnebyteEnd
00000000000003f0 s _gOnebyteSize
0000000000000400 s _gSevenbytesData
0000000000000407 s _gSevenbytesEnd
0000000000000410 s _gSevenbytesSize
                 U gLoremData
                 U gLoremEnd
                 U gLoremSize
                 U gOnebyteData
                 U gOnebyteEnd
                 U gOnebyteSize
                 U gSevenbytesData
                 U gSevenbytesEnd
                 U gSevenbytesSize
graphitemaster commented 6 years ago

That is strange. It appears the symbols are there, maybe the linker expects one to specify symbol visibility ?

andyli commented 6 years ago

I don't know. But I found that the data.c produced by the incbin program can be used with the INCBIN_EXTERN header file. Maybe it is useful for you to look at the data.c.o object: data.c.zip

FYI:

$ nm CMakeFiles/asserts.dir/data.c.o
0000000000000000 S _gLoremData
00000000000003f0 S _gLoremEnd
00000000000003c4 S _gLoremSize
00000000000003d0 S _gOnebyteData
0000000000000400 S _gOnebyteEnd
00000000000003d4 S _gOnebyteSize
00000000000003e0 S _gSevenbytesData
0000000000000410 S _gSevenbytesEnd
00000000000003e8 S _gSevenbytesSize
graphitemaster commented 6 years ago

nm on both seems the same s and S are the same according to my man, this seems weird, the U ones are really interesting tho. I don't have an Apple to dig deeper into this.

rogual commented 4 years ago

Can reproduce this on Apple clang 11.0.0

I think it does have to do with symbol visibility. man nm says:

Each symbol name is preceded by its value (blanks if undefined). Unless the -m option is specified, this value is followed by one of the following characters, representing the symbol type: U (undefined), A (absolute), T (text section symbol), D (data section symbol), B (bss section symbol), C (common symbol), - (for debugger symbol table entries; see -a below), S (symbol in a section other than those above), or I (indirect symbol). If the symbol is local (non-external), the symbol's type is instead represented by the corresponding lowercase letter. A lower case u in a dynamic shared library indicates a undefined reference to a private external in another module in the same library.

It looks like the linker is looking for the _-prefixed symbols, but those are “local” so it's not finding them?

rogual commented 4 years ago

I found a workaround. Everything works for me if I change the definition of INCBIN_GLOBAL to:

#  define INCBIN_GLOBAL(NAME)    ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"

I don't know much about assemblers so not sure if it's the right fix.

pjturpeau commented 4 years ago

@rogual: thank you for this workaround, it just helped me to resolve a similar problem when switching from 64 bits compilation to 32 bits compilation with MingW (x86_64-8.1.0-release-win32-seh-rt_v6-rev0 vs i686-8.1.0-release-win32-dwarf-rt_v6-rev0). I've yet to confirm this workaround is still compatible with my 64 bits environment.

graphitemaster commented 4 years ago

I'm beginning to think __APPLE__ case never worked. Can someone confirm if it works in any version of AppleClang without any of these changes. If not we may need to put the INCBIN_MANGLE on the front here.

graphitemaster commented 4 years ago

Fixed