升级到Catalina 10.15后,golang编译完成后,执行二进制文件报错:
dyld: malformed mach-o image: segment __DWARF has vmsize < filesize
下边我们简单的说一下 Mach-O 文件。
Mach-O
我们知道,进程是可执行文件在内存中加载得到的结果,而 Mach-O 就是一种 macOS 平台的可执行文件格式。
Mach-O 文件分为三个区域 Header、Load commands、Data。其中 Load commands 区的指令指导如何设置并加载二进制数据。
- LC_SEGMENT 对应的数据结构:segment_command
定义了这个文件中的一个 segment,在 Mach-O 文件被加载到时,这个 segment 会被映射到对应的地址空间。需要留意,segment_command 中有一个 segname,可通过 segname 来查找指定的 segment。
struct segment_command { /* for 32-bit architectures */
uint32_t cmd; /* LC_SEGMENT */
uint32_t cmdsize; /* includes sizeof section structs */
char segname[16]; /* segment name */
uint32_t vmaddr; /* memory address of this segment */
uint32_t vmsize; /* memory size of this segment */
uint32_t fileoff; /* file offset of this segment */
uint32_t filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
};
对于每一个 segment 而言,设置进程虚拟内存的过程就是将相应的内容加载到内存中,也就是从 Mach-O 文件的 fileoff 初加载 filesize 字节到虚拟内存地址的 vmaddr 处,占用 vmsize 字节。需要留意,对某些 segment 来说,vmsize 可能会大于 filesize,如__Data、__LINKEDIT。
目前解决办法,去掉DWARF调试信息:
编译的时候使用 go build -ldflags "-w" 这种方式编译。
-ldflags: 表示将后面的参数传给连接器(5/6/8l)
-s:去掉符号信息
-w:去掉DWARF调试信息
注意:
-w 去掉DWARF调试信息,得到的程序就不能用gdb调试了