Mac OS M1下PyBind11链接库时__DATA_CONST错误排查
问题:Mac M1环境下链接PyBind11模块时__DATA_CONST段权限错误
我开发了一款面向Mac OS的科学计算库,该库在Linux环境下可正常编译运行,但在Mac OS M1环境中,将其链接到PyBind11模块时出现如下错误:
ld: __DATA_CONST segment missing SG_READ_ONLY flag in '/Users/ec2-user/libdescriptor/bin/libdescriptor.dylib'
或
ld: __DATA_CONST segment permissions is not 'rw-' in '/Users/ec2-user/libdescriptor/bin/libdescriptor.dylib'
该库编译时使用LLVM 13及lld链接器(因需调用自定义LTO插件Enzyme进行函数微分),编译过程无报错。以下是相关构建文件及工具输出:
1. libdescriptor.dylib的Makefile
CXX := /opt/homebrew/Cellar/llvm@13/13.0.1_2/bin/clang++ CXXFLAGS := -std=c++17 -O3 -dynamiclib -fuse-ld=lld -flto -Iinclude #Enzyme lib location ENZYME_LIB := /usr/local/lib/LLDEnzyme-13.dylib # Directories SRCDIR := src INCDIR := include OBJDIR := obj BINDIR := bin # Output library TARGET := $(BINDIR)/libdescriptor.dylib # Source files SRCFILES := $(wildcard $(SRCDIR)/*.cpp) $(wildcard $(SRCDIR)/*/*.cpp) # Object files OBJFILES := $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SRCFILES)) # Create directories if they don't exist $(shell mkdir -p $(BINDIR) $(OBJDIR) $(OBJDIR)/maths) # Default target all: $(TARGET) # Link the executable $(TARGET): $(OBJFILES) $(CXX) -flto $(CXXFLAGS) -o $@ $^ -Wl,--lto-legacy-pass-manager -Wl,-mllvm -load=$(ENZYME_LIB) -Wl,-mllvm,-enzyme-loose-types # -Wl,-segprot,__DATA_CONST,r,r <- modifications suggested by ChatGPT #-Wl,-segprot,__DATA_CONST,ro,ro # Compile source files into object files $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(CXX) $(CXXFLAGS) -c $< -o $@ # Clean up build files clean: rm -rf $(OBJDIR) $(BINDIR) .PHONY: all clean
2. PyBind11模块的CMakefile
cmake_minimum_required(VERSION 3.16) project(libdescriptor) set(CMAKE_BUILD_TYPE Release) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED YES) # Ensure using LLVM's LLD linker set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld -Wl,-segprot,__DATA_CONST,r,r") # Include directories include_directories(include) # Pybind11 find_package(pybind11 REQUIRED) # Source files for the Pybind11 module file(GLOB PYSOURCES python_bindings/*.cpp python_bindings/**/*.cpp) # Create the Pybind11 module pybind11_add_module(libdescriptor ${PYSOURCES}) # Path to your custom library set(MY_CUSTOM_LIB_PATH /Users/ec2-user/libdescriptor/bin) find_library(DESCRIPTOR_LIB NAMES descriptor PATHS ${MY_CUSTOM_LIB_PATH}) if(NOT DESCRIPTOR_LIB) message(FATAL_ERROR "libdescriptor.dylib not found in ${MY_CUSTOM_LIB_PATH}") endif() # Link the Pybind11 module against the custom library target_link_libraries(libdescriptor PUBLIC ${DESCRIPTOR_LIB}) target_include_directories(libdescriptor PUBLIC ${MY_CUSTOM_LIB_PATH})
3. otools输出(__DATA_CONST段信息)
(python3) ec2-user@ip-172-31-22-4 bin % otool -l ../bin/libdescriptor.dylib | grep -A 20 '__DATA_CONST' segname __DATA_CONST vmaddr 0x0000000000064000 vmsize 0x0000000000004000 fileoff 409600 filesize 16384 maxprot 0x00000003 initprot 0x00000003 nsects 2 flags 0x0 Section sectname __got segname __DATA_CONST addr 0x0000000000064000 size 0x0000000000000110 offset 409600 align 2^3 (8) reloff 0 nreloc 0 flags 0x00000006 reserved1 0 (index into indirect symbol table) reserved2 0 Section sectname __const segname __DATA_CONST addr 0x0000000000064110 size 0x0000000000000a30 offset 409872 align 2^3 (8) reloff 0 nreloc 0 flags 0x00000000 reserved1 0 reserved2 0 Load command 2 cmd LC_SEGMENT_64 cmdsize 312 segname __DATA vmaddr 0x0000000000068000 vmsize 0x0000000000064000 fileoff 425984 filesize 327680 maxprot 0x00000003 initprot 0x00000003 nsects 3
原因分析
从otools输出可以明确:
- __DATA_CONST段的
maxprot和initprot均为0x3,对应权限是rw-(可读可写),但Mac OS标准中__DATA_CONST段应为只读(r--) - 段的
flags为0x0,缺失SG_READ_ONLY标志(该标志对应值为0x1)
问题根源在于LLVM 13的lld链接器在Apple Silicon(M1)平台上,处理__DATA_CONST段权限时存在兼容性问题,再加上Enzyme LTO插件的介入,导致段权限和标志未正确设置。
解决步骤
1. 修复libdescriptor.dylib的段权限
修改libdescriptor的Makefile,在链接阶段显式指定__DATA_CONST段的权限和只读标志:
找到链接目标$(TARGET)的规则,添加-Wl,-segprot,__DATA_CONST,r,r和-Wl,-segattr,__DATA_CONST,SG_READ_ONLY参数:
$(TARGET): $(OBJFILES) $(CXX) -flto $(CXXFLAGS) -o $@ $^ -Wl,--lto-legacy-pass-manager -Wl,-mllvm -load=$(ENZYME_LIB) -Wl,-mllvm,-enzyme-loose-types -Wl,-segprot,__DATA_CONST,r,r -Wl,-segattr,__DATA_CONST,SG_READ_ONLY
说明:
-Wl,-segprot,__DATA_CONST,r,r:设置__DATA_CONST段的最大权限和初始权限为只读(r,r对应maxprot和initprot为0x1)-Wl,-segattr,__DATA_CONST,SG_READ_ONLY:添加SG_READ_ONLY标志到__DATA_CONST段
修改后重新编译库:
make clean && make all
2. 调整PyBind11模块的链接配置
移除CMakefile中不必要的段权限设置(因为库本身已经修复),确保链接器一致性:
修改CMakefile中的CMAKE_SHARED_LINKER_FLAGS:
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld")
然后重新构建PyBind11模块:
rm -rf build && mkdir build && cd build && cmake .. && make
验证修复结果
重新编译后,用otools检查__DATA_CONST段的权限和标志:
otool -l libdescriptor.dylib | grep -A 10 '__DATA_CONST'
确认输出中:
maxprot和initprot变为0x1(只读)flags包含0x1(SG_READ_ONLY标志)
内容的提问来源于stack exchange,提问作者ipcamit
相关产品推荐
相关产品推荐

