Skip to content

Commit

Permalink
Mostly unbreak macOS build.
Browse files Browse the repository at this point in the history
We try as best as we can to support special linker sections on
both ELF and Mach-O binary formats, but we are not able to do it
perfectly. Of note, on macOS .lua.open_array.preload will always
be empty.
  • Loading branch information
obilaniu committed Jul 12, 2021
1 parent a94f1ae commit 48eb09d
Show file tree
Hide file tree
Showing 15 changed files with 215 additions and 105 deletions.
117 changes: 78 additions & 39 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,84 @@ FUNCP_SIZE = cc.sizeof(FUNCP)
assert(CHARP_SIZE == cxx.sizeof(FUNCP), f'C and C++ compilers disagree on sizeof(@FUNCP@)!')
assert(VOIDP_SIZE == CHARP_SIZE, f'Pointers to void and char not of equal size!')
assert(VOIDP_SIZE == FUNCP_SIZE, f'Pointers to void and function not of equal size!')
add_global_arguments([f'-DGASPOINTERSIZE=@VOIDP_SIZE@',
f'-DGASPOINTERWORD=.@VOIDP_SIZE@byte'], language: ['c','cpp'])


#
# Add predefined macros identifying the:
# - C & C++ compilers
# - CPU family
# - Operating System
#
MACRO_COMPILER_CC = 'BENZINA_COMPILER_'
MACRO_COMPILER_CXX = 'BENZINA_COMPILER_'
MACRO_CPU_FAMILY = 'BENZINA_CPU_FAMILY_'
MACRO_OS = 'BENZINA_OS_'
MACRO_COMPILER_CC += {'clang-cl': 'clang',
'intel-cl': 'intel'}.get(CC_ID, CC_ID)
MACRO_COMPILER_CXX += {'clang-cl': 'clang',
'intel-cl': 'intel'}.get(CXX_ID, CXX_ID)
MACRO_CPU_FAMILY += host_machine.cpu_family()
MACRO_OS += host_machine.system()
MACRO_COMPILER_CC = MACRO_COMPILER_CC .to_upper().underscorify()
MACRO_COMPILER_CXX = MACRO_COMPILER_CXX.to_upper().underscorify()
MACRO_CPU_FAMILY = MACRO_CPU_FAMILY .to_upper().underscorify()
MACRO_OS = MACRO_OS .to_upper().underscorify()
add_global_arguments([f'-D@MACRO_COMPILER_CC@=1'], language: 'c')
add_global_arguments([f'-D@MACRO_COMPILER_CXX@=1'], language: 'cpp')
add_global_arguments([f'-D@MACRO_CPU_FAMILY@=1',
f'-D@MACRO_OS@=1',
f'-DBENZINA_COMPILER_IDENTIFIED=1',
f'-DBENZINA_CPU_FAMILY_IDENTIFIED=1',
f'-DBENZINA_OS_IDENTIFIED=1'], language: ['c', 'cpp'])


#
# Add predefined macros for use by the preprocessed assembly code, identifying:
#
# - Pointer size
# - Underscore prefixing
# - Section/segment+section names and attributes
#
# The section names must be <=15 characters long due to
# A) macOS's Mach-O binary format imposing a limitation of 16 characters and
# B) macOS's Mach-O binary format using a naming convention of
# __SEGM,__sect
# which we adhere to by underscorifying the equivalent ELF section name
# and adding an additional prefix underscore.
#
# Because of this, plus other difficulties, we do not currently support
# preloading Lua modules in Lua states on macOS.
#
add_global_arguments([f'-DASM_PTR_SIZE=@VOIDP_SIZE@',
f'-DASM_PTR_DECL=.@VOIDP_SIZE@byte'], language: ['c', 'cpp'])
SECT_DICT = {
'BSS': {'name': '.bss', 'elf_attr': '', 'macho_segm': '__DATA', 'macho_attr': ''},
'CSTRING': {'name': '.rodata.str1.1', 'elf_attr': '"aMS", @progbits, 1', 'macho_segm': '__TEXT', 'macho_attr': 'cstring_literals'},
'LICENSE': {'name': '.license', 'elf_attr': '"a"', 'macho_segm': '__TEXT', 'macho_attr': 'regular, no_dead_strip'},
'RODATALZ4': {'name': '.rodata.lz4', 'elf_attr': '"a"', 'macho_segm': '__TEXT', 'macho_attr': 'regular, no_dead_strip'},
'LZ4CMDARRAY': {'name': '.lz4.cmd_array', 'elf_attr': '"aw"', 'macho_segm': '__DATA', 'macho_attr': 'regular, no_dead_strip'},
'TOOLARRAY': {'name': '.tool_array', 'elf_attr': '"aw"', 'macho_segm': '__DATA', 'macho_attr': 'regular, no_dead_strip'},
'LUAOPENARRAY': {'name': '.lua.open_array', 'elf_attr': '"aw"', 'macho_segm': '__DATA', 'macho_attr': 'regular, no_dead_strip'},
'LUAOPENARRAYPRELOAD': {'name': '.lua.open_array.preload', 'elf_attr': '"aw"', 'macho_segm': '__DATA', 'macho_attr': 'regular, no_dead_strip'},
'LUATEXTARRAY': {'name': '.lua.text_array', 'elf_attr': '"aw"', 'macho_segm': '__DATA', 'macho_attr': 'regular, no_dead_strip'},
}
foreach sect, dict : SECT_DICT
if IS_HOST_DARWIN
sect_name = dict['macho_segm'] + ',_' + {
'LUAOPENARRAYPRELOAD': '.lua.open_array', # Name too long for Mach-O
'CSTRING': '.cstring', # Mach-O uses __cstring for mergeable strings
}.get(sect, dict['name']).underscorify()
sect_attr = dict['macho_attr']
else
sect_name = dict['name']
sect_attr = dict['elf_attr']
endif
sect_attr = sect_attr == '' ? sect_attr : ', '+sect_attr
add_global_arguments([
f'-DASM_SECT_@sect@_NAME="@sect_name@"',
f'-DASM_SECT_@sect@_DECL=.section @sect_name@@sect_attr@',
], language: ['c', 'cpp'])
endforeach


#
Expand Down Expand Up @@ -168,43 +244,6 @@ openmp = dependency('openmp', required: false)
threads = dependency('threads')


#
# Add predefined macros identifying the:
# - C & C++ compilers
# - CPU family
# - Operating System
#
MACRO_COMPILER_CC = 'BENZINA_COMPILER_'
MACRO_COMPILER_CXX = 'BENZINA_COMPILER_'
MACRO_CPU_FAMILY = 'BENZINA_CPU_FAMILY_'
MACRO_OS = 'BENZINA_OS_'
MACRO_COMPILER_CC += {'clang-cl': 'clang',
'intel-cl': 'intel'}.get(CC_ID, CC_ID)
MACRO_COMPILER_CXX += {'clang-cl': 'clang',
'intel-cl': 'intel'}.get(CXX_ID, CXX_ID)
MACRO_CPU_FAMILY += host_machine.cpu_family()
MACRO_OS += host_machine.system()
MACRO_COMPILER_CC = MACRO_COMPILER_CC .to_upper().underscorify()
MACRO_COMPILER_CXX = MACRO_COMPILER_CXX.to_upper().underscorify()
MACRO_CPU_FAMILY = MACRO_CPU_FAMILY .to_upper().underscorify()
MACRO_OS = MACRO_OS .to_upper().underscorify()

add_project_arguments(['-D'+MACRO_COMPILER_CC+'=1',
'-DBENZINA_COMPILER_IDENTIFIED=1'], language: 'c')
add_project_arguments(['-D'+MACRO_COMPILER_CXX+'=1',
'-DBENZINA_COMPILER_IDENTIFIED=1'], language: 'cpp')

add_project_arguments(['-D'+MACRO_CPU_FAMILY+'=1',
'-DBENZINA_CPU_FAMILY_IDENTIFIED=1'], language: 'c')
add_project_arguments(['-D'+MACRO_CPU_FAMILY+'=1',
'-DBENZINA_CPU_FAMILY_IDENTIFIED=1'], language: 'cpp')

add_project_arguments(['-D'+MACRO_OS+'=1',
'-DBENZINA_OS_IDENTIFIED=1'], language: 'c')
add_project_arguments(['-D'+MACRO_OS+'=1',
'-DBENZINA_OS_IDENTIFIED=1'], language: 'cpp')


#
# Configuration Data
#
Expand Down
18 changes: 9 additions & 9 deletions scripts/lz4-lua-pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@

payload_unc = bytearray()
with open(out_S, "w") as f:
f.write('.section .rodata.str1.1, "aMS", @progbits, 1\n')
f.write('ASM_SECT_CSTRING_DECL\n')
for i, name in enumerate(sortednames):
f.write(f' .Lname{i}: .asciz "{name}"\n')
f.write('\n\n')
f.write('.section .bss\n')
f.write('.align 4096\n')
f.write('ASM_SECT_BSS_DECL\n')
f.write('.p2align 12\n')
f.write('.Ldst_start:\n')
for i, name in enumerate(sortednames):
filecontents = open(D[name], "rb").read()
Expand All @@ -26,11 +26,11 @@
f.write(f'.Lend{i}: .skip 1\n')
f.write('.Ldst_end:\n')
f.write(' .skip 8\n')
f.write('.align 4096\n')
f.write('.p2align 12\n')
f.write('\n\n')
f.write('.section .lua.text_array, "aw", @progbits\n')
f.write('ASM_SECT_LUATEXTARRAY_DECL\n')
for i, name in enumerate(sortednames):
f.write(f' GASPOINTERWORD .Lname{i}, .Lstart{i}, .Lend{i}\n')
f.write(f' ASM_PTR_DECL .Lname{i}, .Lstart{i}, .Lend{i}\n')
f.write('\n\n')

#
Expand All @@ -46,11 +46,11 @@
incbinpath = os.path.relpath(out_lz4, os.path.dirname(out_S))
incbinsize = os.stat(out_lz4, follow_symlinks=True).st_size

f.write('.section .rodata.lz4, "a", @progbits\n')
f.write('ASM_SECT_RODATALZ4_DECL\n')
f.write('.Lsrc_start:\n')
f.write(f' .incbin "{incbinpath}", 0, {incbinsize}\n')
f.write('.Lsrc_end:\n')
f.write(' .8byte 0\n')
f.write('\n\n')
f.write('.section .lz4.decompress_array, "aw", @progbits\n')
f.write(' GASPOINTERWORD .Lsrc_start, .Lsrc_end, .Ldst_start, .Ldst_end\n')
f.write('ASM_SECT_LZ4CMDARRAY_DECL\n')
f.write(' ASM_PTR_DECL .Lsrc_start, .Lsrc_end, .Ldst_start, .Ldst_end\n')
45 changes: 23 additions & 22 deletions scripts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,28 +105,29 @@ def run(self):
subprocess.check_call(["ninja", "install"],
stdin = subprocess.DEVNULL,
cwd = self.build_meson)
# START HACK
# Due to Meson build-system shenanigans, what actually ends up installed
# does not include the symlinks
# libbenzina.so -> libbenzina.so.X -> libbenzina.so.X.Y.Z
# Instead, they are all regular file copies of libbenzina.so.X.Y.Z.
# Replace them with the desired symlinks.
target_name = "libbenzina.so."
for meson_out_file in self._get_meson_outputs():
if os.path.basename(meson_out_file).startswith(os.path.basename(target_name)):
target_name = meson_out_file
libbenzina_so_x_y_z = target_name
libbenzina_so_x = '.'.join(libbenzina_so_x_y_z.split('.')[:-2])
libbenzina_so = '.'.join(libbenzina_so_x_y_z.split('.')[:-3])
base_libbenzina_so_x_y_z = os.path.basename(libbenzina_so_x_y_z)
base_libbenzina_so_x = os.path.basename(libbenzina_so_x)
build_libbenzina_so_x = os.path.join(self.build_lib, libbenzina_so_x)
build_libbenzina_so = os.path.join(self.build_lib, libbenzina_so)
os.unlink (build_libbenzina_so_x)
os.unlink (build_libbenzina_so)
os.symlink(base_libbenzina_so_x_y_z, build_libbenzina_so_x)
os.symlink(base_libbenzina_so_x, build_libbenzina_so)
# END HACK
if sys.platform != 'darwin':
# START HACK
# Due to Meson build-system shenanigans, what actually ends up installed
# does not include the symlinks
# libbenzina.so -> libbenzina.so.X -> libbenzina.so.X.Y.Z
# Instead, they are all regular file copies of libbenzina.so.X.Y.Z.
# Replace them with the desired symlinks.
target_name = "libbenzina.so."
for meson_out_file in self._get_meson_outputs():
if os.path.basename(meson_out_file).startswith(os.path.basename(target_name)):
target_name = meson_out_file
libbenzina_so_x_y_z = target_name
libbenzina_so_x = '.'.join(libbenzina_so_x_y_z.split('.')[:-2])
libbenzina_so = '.'.join(libbenzina_so_x_y_z.split('.')[:-3])
base_libbenzina_so_x_y_z = os.path.basename(libbenzina_so_x_y_z)
base_libbenzina_so_x = os.path.basename(libbenzina_so_x)
build_libbenzina_so_x = os.path.join(self.build_lib, libbenzina_so_x)
build_libbenzina_so = os.path.join(self.build_lib, libbenzina_so)
os.unlink (build_libbenzina_so_x)
os.unlink (build_libbenzina_so)
os.symlink(base_libbenzina_so_x_y_z, build_libbenzina_so_x)
os.symlink(base_libbenzina_so_x, build_libbenzina_so)
# END HACK
super().run()

def copy_extensions_to_source(self):
Expand Down
4 changes: 2 additions & 2 deletions src/libbenzina/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ BENZINA_STATIC void benz_init_lz4(void){
LZ4F_decompressOptions_t dopt = {.stableDst=1};
size_t dO, dB, dM, sO, sB, sM;

for(p=__lz4_decompress_array_start;
p<__lz4_decompress_array_end; p++){
for(p=__lz4_cmd_array_start;
p<__lz4_cmd_array_end; p++){
if(p->src_end>p->src_start && p->dst_end>p->dst_start){
sB = sM = p->src_end - p->src_start;
dB = dM = p->dst_end - p->dst_start;
Expand Down
12 changes: 6 additions & 6 deletions src/libbenzina/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@
#define __BENZINA_REGISTER(a) ___BENZINA_REGISTER(a, __COUNTER__)
#define BENZINA_LUAOPEN_REGISTER(name, func) \
BENZINA_ATTRIBUTE_USED \
BENZINA_ATTRIBUTE_SECTION(".lua.open_array") \
BENZINA_ATTRIBUTE_SECTION(ASM_SECT_LUAOPENARRAY_NAME) \
static const luaL_Reg __BENZINA_REGISTER(__benz_luaopen_entry_) = {("" name),(func)};
#define BENZINA_LUAOPEN_REGISTER_PRELOAD(name, func) \
BENZINA_ATTRIBUTE_USED \
BENZINA_ATTRIBUTE_SECTION(".lua.open_array.preload") \
BENZINA_ATTRIBUTE_SECTION(ASM_SECT_LUAOPENARRAYPRELOAD_NAME) \
static const luaL_Reg __BENZINA_REGISTER(__benz_luaopen_entry_) = {("" name),(func)};
#define BENZINA_TOOL_REGISTER(name, func) \
BENZINA_ATTRIBUTE_USED \
BENZINA_ATTRIBUTE_SECTION(".tool_array") \
BENZINA_ATTRIBUTE_SECTION(ASM_SECT_TOOLARRAY_NAME) \
static const BENZ_TOOL_ENTRY __BENZINA_REGISTER(__benz_tool_entry_) = {("" name),(func)};


Expand All @@ -83,14 +83,14 @@
BENZINA_HIDDEN extern const char license_benzina[];


/*** .lz4.decompress_array ***/
/*** .lz4.cmd_array ***/
typedef struct BENZ_LZ4_ENTRY BENZ_LZ4_ENTRY;
struct BENZ_LZ4_ENTRY{
const char* src_start, *src_end;
char* dst_start, *dst_end;
};
BENZINA_HIDDEN extern const BENZ_LZ4_ENTRY __lz4_decompress_array_start[];
BENZINA_HIDDEN extern const BENZ_LZ4_ENTRY __lz4_decompress_array_end[];
BENZINA_HIDDEN extern const BENZ_LZ4_ENTRY __lz4_cmd_array_start[];
BENZINA_HIDDEN extern const BENZ_LZ4_ENTRY __lz4_cmd_array_end[];


/*** .tool_array ***/
Expand Down
38 changes: 37 additions & 1 deletion src/libbenzina/internal.noarch.S
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
.section .license, "a"
ASM_SECT_LICENSE_DECL
.incbin "../../LICENSE.md"
.ascii "\n\n"

#if BENZINA_OS_DARWIN
#
# On Darwin-based systems, we cannot make use of linker scripts because the
# system linker, ld64, doesn't support them.
#
# We declare here certain "magic" symbols and make them global.
# Then, we define them in terms of section start and end addresses,
# synthesized by the linker.
#
.globl _license_benzina
.globl ___lz4_cmd_array_start
.globl ___lz4_cmd_array_end
.globl ___tool_array_start
.globl ___tool_array_end
.globl ___lua_open_array_start
.globl ___lua_open_array_preload_start
.globl ___lua_open_array_preload_end
.globl ___lua_open_array_end
.globl ___lua_text_array_start
.globl ___lua_text_array_end

.set _license_benzina, section$start$__TEXT$__license
.set ___lz4_cmd_array_start, section$start$__DATA$__lz4_cmd_array
.set ___lz4_cmd_array_end, section$start$__DATA$__lz4_cmd_array
.set ___tool_array_start, section$start$__DATA$__tool_array
.set ___tool_array_end, section$start$__DATA$__tool_array
.set ___lua_open_array_start, section$start$__DATA$__lua_open_array
# Mach-O doesn't support sections with >16-character names, so we disable
# support for that sub-array. The following two entries are *not* mistakes!
.set ___lua_open_array_preload_start, section$start$__DATA$__lua_open_array
.set ___lua_open_array_preload_end, section$start$__DATA$__lua_open_array
.set ___lua_open_array_end, section$end$__DATA$__lua_open_array
.set ___lua_text_array_start, section$start$__DATA$__lua_text_array
.set ___lua_text_array_end, section$end$__DATA$__lua_text_array
#endif
14 changes: 7 additions & 7 deletions src/libbenzina/libbenzina.lds
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
* - Linker script terminates string concatenation with a NUL byte to make
* the symbol above usable as a C string.
*
* .section .lz4.decompress_array, "aw"
* .section .lz4.cmd_array, "aw"
* - A concatenation of entries
* struct lz4_entry{const char* src_start, *src_end;
* char* dst_start, *dst_end;};
* somewhat modelled on .init_array.
* - Array start: lz4_entry __lz4_decompress_array_start[]
* - Array end: lz4_entry __lz4_decompress_array_end[]
* - Array start: lz4_entry __lz4_cmd_array_start[]
* - Array end: lz4_entry __lz4_cmd_array_end[]
* - Every entry represents one decompression order.
*
* .section .tool_array, "aw"
Expand Down Expand Up @@ -80,10 +80,10 @@ SECTIONS {
} INSERT AFTER .rodata;

SECTIONS {
.lz4.decompress_array : ALIGN(32) {
HIDDEN(__lz4_decompress_array_start = .);
KEEP(*(.lz4.decompress_array .lz4.decompress_array.*));
HIDDEN(__lz4_decompress_array_end = .);
.lz4.cmd_array : ALIGN(32) {
HIDDEN(__lz4_cmd_array_start = .);
KEEP(*(.lz4.cmd_array .lz4.cmd_array.*));
HIDDEN(__lz4_cmd_array_end = .);
QUAD(0); QUAD(0); QUAD(0); QUAD(0); /* NULL sentinel */
}
.tool_array : ALIGN(16) {
Expand Down
Loading

0 comments on commit 48eb09d

Please sign in to comment.