Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Undefined symbols for architecture arm64" when linking a converted framework #7

Open
zachgrayio opened this issue Jan 11, 2022 · 12 comments

Comments

@zachgrayio
Copy link

Noticed there's a good amount of missing symbols after converting a few arm64 device binaries over and attempting to use them on the M1s - some examples coming from opencv:

  "cv::g_8x32fTab", referenced from:
      _cvRawDataToScalar in libopencv_arm64.a(array.o)
      cv::hal::cpu_baseline::mul8u(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long, int, int, double const*) in libopencv_arm64.a(arithm.dispatch.o)
      cv::hal::cpu_baseline::div8u(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long, int, int, double const*) in libopencv_arm64.a(arithm.dispatch.o)
      cv::hal::cpu_baseline::addWeighted8u(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long, int, int, double const*) in libopencv_arm64.a(arithm.dispatch.o)
      cv::hal::cpu_baseline::recip8u(unsigned char const*, unsigned long, unsigned char*, unsigned long, int, int, double const*) in libopencv_arm64.a(arithm.dispatch.o)
  "cv::g_Saturate8u", referenced from:
      void cv::reduceR_<unsigned char, unsigned char, cv::OpMax<unsigned char> >(cv::Mat const&, cv::Mat&) in libopencv_arm64.a(matrix_operations.o)
      void cv::reduceR_<unsigned char, unsigned char, cv::OpMin<unsigned char> >(cv::Mat const&, cv::Mat&) in libopencv_arm64.a(matrix_operations.o)
      void cv::reduceC_<unsigned char, unsigned char, cv::OpMax<unsigned char> >(cv::Mat const&, cv::Mat&) in libopencv_arm64.a(matrix_operations.o)
      void cv::reduceC_<unsigned char, unsigned char, cv::OpMin<unsigned char> >(cv::Mat const&, cv::Mat&) in libopencv_arm64.a(matrix_operations.o)
      cv::hal::cpu_baseline::add8u(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long, int, int) in libopencv_arm64.a(arithm.dispatch.o)
      cv::hal::cpu_baseline::sub8u(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long, int, int) in libopencv_arm64.a(arithm.dispatch.o)
      cv::hal::cpu_baseline::min8u(unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char*, unsigned long, int, int) in libopencv_arm64.a(arithm.dispatch.o)
      ...
@zachgrayio
Copy link
Author

zachgrayio commented Jan 11, 2022

I guess maybe this is somewhat unsurprising when diffing the contents of the x86_64 vs arm64 slices (opencv), which I included in full below for the sake of discussion.

The missing files here for the most part are expected as they're mostly AVX instruction set obj files, etc; of course they're not in the arm64 slice. I guess my question is really -- in cases like this, what's the expected behavior? and are the missing symbols here related to the difference in obj or not? 🤔 I haven't worked that out yet.

Here's the diff:

 __.SYMDEF
-accum.avx.o
-accum.avx2.o
 accum.dispatch.o
 accum.o
-accum.sse4_1.o
 algorithm.o
 alloc.o
 approx.o
-arithm.avx2.o
 arithm.dispatch.o
 arithm.o
-arithm.sse4_1.o
 array.o
 batch_distance.o
 bilateral_filter.o
 bindings_utils.o
 blend.o
 box_filter.o
 canny.o
 channels.o
 check.o
 clahe.o
 color.o
 color_hsv.o
 color_lab.o
 color_rgb.o
 color_yuv.o
 colormap.o
 command_line_parser.o
 conjugate_gradient.o
 connectedcomponents.o
 contours.o
 convert.o
 convert_c.o
 convert_scale.o
 convhull.o
 copy.o
-corner.avx.o
 corner.o
 cornersubpix.o
 count_non_zero.o
 cuda_gpu_mat.o
 cuda_host_mem.o
 cuda_info.o
 cuda_stream.o
 datafile.o
 datastructs.o
 demosaicing.o
 deriv.o
 directx.o
 distransform.o
 downhill_simplex.o
 drawing.o
 dxt.o
 emd.o
 featureselect.o
 filesystem.o
-filter.avx2.o
 filter.o
 floodfill.o
 gabor.o
 generalized_hough.o
 geometry.o
 gl_core_3_1.o
 glob.o
 grabcut.o
 hal_internal.o
 hershey_fonts.o
 histogram.o
 hough.o
-imgwarp.avx2.o
 imgwarp.o
-imgwarp.sse4_1.o
 intersection.o
 kmeans.o
 lapack.o
 lda.o
 linefit.o
 logger.o
 lpsolver.o
 lsd.o
 lut.o
 main.o
 matchcontours.o
 mathfuncs.o
-mathfuncs_core.avx.o
-mathfuncs_core.avx2.o
 mathfuncs_core.dispatch.o
 matmul.o
 matrix.o
 matrix_c.o
 matrix_decomp.o
 matrix_expressions.o
 matrix_iterator.o
 matrix_operations.o
 matrix_sparse.o
 matrix_wrap.o
 mean.o
 median_blur.o
 merge.o
 min_enclosing_triangle.o
 minmax.o
 moments.o
 morph.o
 norm.o
 ocl.o
 opencl_clamdblas.o
 opencl_clamdfft.o
 opencl_core.o
 opencl_kernels_core.o
 opencl_kernels_imgproc.o
 opengl.o
 out.o
 ovx.o
 parallel.o
 parallel_impl.o
 pca.o
 persistence.o
 persistence_base64.o
 persistence_c.o
 persistence_cpp.o
 persistence_json.o
 persistence_types.o
 persistence_xml.o
 persistence_yml.o
 phasecorr.o
 pyramids.o
 rand.o
-resize.avx2.o
 resize.o
-resize.sse4_1.o
 rotcalipers.o
 samplers.o
 samples.o
 segmentation.o
 shapedescr.o
 smooth.o
 softfloat.o
 spatialgradient.o
 split.o
-stat.avx2.o
 stat.dispatch.o
-stat.sse4_2.o
 stat_c.o
 stl.o
 subdivision2d.o
 sum.o
 sumpixels.o
 system.o
 tables.o
 templmatch.o
 thresh.o
 trace.o
 types.o
 umatrix.o
-undistort.avx2.o
 undistort.o
 utils.o
 va_intel.o

@zachgrayio zachgrayio changed the title "Undefined symbols for architecture arm64" during linking "Undefined symbols for architecture arm64" when linking a converted framework Jan 11, 2022
@zachgrayio
Copy link
Author

zachgrayio commented Jan 12, 2022

I'm reopening this--thought I'd worked it out but I haven't.

what im trying to do:

  • lipo -thin arm64 libopencv.a
  • ar x it
  • for file in *.o; do arm64-to-sim ...
  • ar crv the converted files
  • lipo -create the final result
  • links in OK without mismatch arch warnings but always missing objects.

FWIW I'm moving in another direction here (no good reason to really be converting this one) but maybe it's worth figuring out if .a's are a valid use case.

maybe it's safe to chalk this up to incompatibility with CC archives produced by opencv's build tools and close?

@zachgrayio zachgrayio reopened this Jan 12, 2022
@hendych
Copy link

hendych commented Feb 7, 2022

I'm also experiencing this issue. This time I tried to convert Realm framework. The realm framework used prebuilt librealmcore-ios.a as it's core library. The issue seems when we ar x the .a library, some symbols will be missing.

@zachgrayio
Copy link
Author

zachgrayio commented Feb 7, 2022

@hendych what symbols are missing in your case? because another issue I know a few users of this hack have seen is missing swift std lib, and theres a specific way we managed to work past that.

I'll try to PR to the readme sometime on that. its a somewhat separate issue than this one

@bogo
Copy link
Owner

bogo commented Feb 7, 2022

Sorry to have gone MIA on this!

I am not entirely surprised by some libraries having missing symbols – it's entirely possible they were compiled out entirely through usage of TARGET_IPHONE_SIMULATOR macro or other build-time conditionals. For OpenCV that would make a lot of sense, since it's partially developed by Intel, likely leading to x86-specific implementations of some algorithms. (the fact the missing objects refer to AVX2 and SSE4, i.e. extended instruction sets in modern x86, would confirm this)

If that's the case, there is not a whole lot that could be done here. One thing I would try is to break up the x86 and ARM Simulator frameworks into two separate ones, where the Simulator ARM one is using the original Native ARM headers. Might make ld and LLVM happier, if the headers match up sufficiently. If you point me to the specific Realm framework version, I'm happy to take a look!

@bogo
Copy link
Owner

bogo commented Feb 7, 2022

@zachgrayio - if you can share, would be super interested to hear how you solve the Swift standard library linking! Is this related to the usage of TAPIs/swiftmodules in any way? Would love to learn more about this.

@zachgrayio
Copy link
Author

@bogo for sure. do you want to come on our podcast to talk about all this stuff?? was thinking it'd be a cool episode anyways lol. https://podcasts.apple.com/ca/podcast/the-bazel-show/id1544005904 😆

@hendych
Copy link

hendych commented Feb 9, 2022

@bogo in realm, this symbol should've exist in both simulator or device. The missing symbol was supposed to be make_in_realm_history something. This were supposed to not only exist in specific CPU arch only. Sorry the log was missing since I was testing it 3 days ago using Xcode.

What is happening?

What I found is that, when I unarchive using ar x this specific symbol were in history.o object when I checked using nm but after unarchive, the symbol is not in history.o rather in __.SYMDEF file. When I run ar crv again, the symbol is missing.

What I understand from man ar is that when we create an archive using ar the symbol table gets re-writed based on the *.o objects.

I was trying to convert Realm version 3.21.0.

Workaround

Luckily, Realm version 3.21.0 support SPM. Using SPM, the 3rd party is downloaded with pure source code (instead of cocoapods, it's still using prebuilt core librealmcore.a).

After the source code is compiled, SPM will produce Realm.o and RealmCore.o in DerivedData. Then I created Realm static library from it using ar

@tapthaker
Copy link

Hey @hendych,
We saw this happening as well but it is because the ar utility cannot extract files correctly if there are more than 2 object entries with the same name. As a solution, you can use this script that which handles this edge case: https://github.com/tapthaker/extract-archive

I tried this is Realm and clearly history.o is repeated twice:

tapanth@tapanth-JK90543C2F ios % ar -t /tmp/realm_arm64 | grep -i history
history.o
client_history_impl.o
object_id_history_state.o
history.o

@bogo
Copy link
Owner

bogo commented Mar 15, 2022

Ooh, duplicate names in ar is an interesting edge case I never considered. I should probably amend the articles to mention that, hah.

@tarbaiev-smg
Copy link

Another workaround is searching for the missing symbols on GitHub, then building them for arm64 simulator and merging them together using libtool. This way I successfully patched MLKit, which had missing symbols from the abseil library and some more string escaping functions copied across multiple Google repos. Though I had to perform some adjustments, such as renaming namespaces using -Dabsl=MLKITx_absl in Other C Flags as well as writing a couple of missing adapter functions and changing int to to long.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants