| Issue |
203678
|
| Summary |
[llvm-objcopy][MachO] Stripping debug info from dylib produces misaligned `__LINKEDIT` entries
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
goranmoomin
|
Stripping debug info from a Mach-O dylib with `llvm-objcopy --strip-debug` can produce a dylib with misaligned `__LINKEDIT` entries, e.g. the `__LINKEDIT` string pool offset is not aligned to the pointer size.
This is inconsistent with the behavior of Apple's [ld64](http://github.com/apple-oss-distributions/ld64/) nor lld-macho, where every `__LINKEDIT` entry is aligned to the pointer size (except for the code signature, which is aligned to 16 bytes).
ld64 behavior: https://github.com/apple-oss-distributions/ld64/blob/ld64-957.1/src/ld/LinkEditClassic.hpp#L63
lld-macho behavior: https://github.com/llvm/llvm-project/blob/llvmorg-22.1.7/lld/MachO/SyntheticSections.h#L62, see https://reviews.llvm.org/D94935
On macOS 27.0, dyld rejects dylibs with misaligned `__LINKEDIT` entries, revealing this issue.
(See rust-lang/rust#157750.)
Reproducer:
```shellsession
$ cat addr_puts.c
#include <stdint.h>
#include <stdio.h>
uintptr_t answer(void) { return (uintptr_t)&puts; }
$ clang -dynamiclib -g -O0 addr_puts.c -o libaddr_puts.dylib
$ cp libaddr_puts.dylib libaddr_puts.stripped.dylib
$ llvm-objcopy --strip-debug libaddr_puts.stripped.dylib
```
When looking at the __LINKEDIT entry offsets in the dylib:
```shellsession
$ otool -l libaddr_puts.dylib | grep 'symoff\|nsyms\|indirectsymoff\|nindirectsyms\|stroff'
symoff 32888
nsyms 11
stroff 33072
extrefsymoff 0
indirectsymoff 33064
nindirectsyms 1
$ otool -l libaddr_puts.stripped.dylib | grep 'symoff\|nsyms\|indirectsymoff\|nindirectsyms\|stroff'
symoff 32888
nsyms 2
stroff 32924
extrefsymoff 0
indirectsymoff 32920
nindirectsyms 1
```
>From the original dylib, the size of the symbol table is `sizeof(nlist_64)*nsyms + 4*nindirectsyms = 180`, therefore the symbol table is padded 4 bytes and the string table is aligned to 8 bytes, and placed at 33072.
However from the stripped dylib, the size of the symbol table is `sizeof(nlist_64)*nsyms + 4*nindirectsyms = 36`, so the string table is placed at 32924, misaligned. Therefore `dlopen`-ing the stripped dylib fails:
```shellsession
$ python3 -c 'import sys, ctypes; sys.tracebacklimit=0; ctypes.CDLL("libaddr_puts.dylib"); print("ok")'
ok
$ python3 -c 'import sys, ctypes; sys.tracebacklimit=0; ctypes.CDLL("libaddr_puts.stripped.dylib"); print("ok")'
OSError: dlopen(libaddr_puts.stripped.dylib, 0x0006): tried: 'libaddr_puts.stripped.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0000809C), '/System/Volumes/Preboot/Cryptexes/OSlibaddr_puts.stripped.dylib' (no such file), '/usr/lib/libaddr_puts.stripped.dylib' (no such file, not in dyld cache), 'libaddr_puts.stripped.dylib' (mis-aligned LINKEDIT string pool, fileOffset=0x0000809C)
```
While not included in the reproduction, stripping with `/usr/bin/strip` also places the string table aligned to 8 bytes.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs