Skip to content
Open
13 changes: 11 additions & 2 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,13 @@ ifneq ($(filter 386 486 586 686 i386 i486 i586 i686,$(TARGET_ARCH)),)
TARGET_ARCH := x86
endif

# Normalize TARGET_ARCH to arm
ifneq ($(filter arm%,$(TARGET_ARCH)),)
# Normalize TARGET_ARCH to aarch64 (macOS reports arm64)
ifneq ($(filter aarch64 arm64,$(TARGET_ARCH)),)
TARGET_ARCH := aarch64
endif

# Normalize TARGET_ARCH to arm (32-bit only, after aarch64 is handled)
ifneq ($(filter armv% arm,$(TARGET_ARCH)),)
TARGET_ARCH := arm
endif

Expand Down Expand Up @@ -585,6 +590,10 @@ ifeq ($(TARGET_OS),darwin)
ALLFBCFLAGS += -d ENABLE_XQUARTZ
else
ALLCFLAGS += -DDISABLE_X11
# FB's OpenGL support lives in the X11 driver, so without XQuartz there is
# no GL driver at all. gfx_opengl.c otherwise still calls the driver hook
# fb_hGL_GetProcAddress(), leaving libfbgfx with an undefined symbol.
ALLCFLAGS += -DDISABLE_OPENGL
endif
endif

Expand Down
15 changes: 13 additions & 2 deletions src/compiler/ast-node-data.bas
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,20 @@ end function

private sub hCreateDataDesc( )
static as FBARRAYDIM dTB(0)
dim as integer byalign

'' Using FIELD = 1, to pack it as done by the rtlib -- except on Darwin,
'' where the linker requires pointer-sized relocations to be aligned to
'' the pointer size. A packed { short, void* } puts the DATA entries'
'' pointers at offset 2 (and every 10 bytes after that), which ld64
'' rejects ("pointer not aligned ...", fatal on arm64). There the layout
'' must use the natural pointer alignment, matching src/rtlib/fb_data.h.
byalign = 1
if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then
byalign = env.pointersize
end if

'' Using FIELD = 1, to pack it as done by the rtlib
ast.data.desc = symbStructBegin( NULL, NULL, NULL, "__FB_DATADESC$", NULL, FALSE, 1, FALSE, 0, 0 )
ast.data.desc = symbStructBegin( NULL, NULL, NULL, "__FB_DATADESC$", NULL, FALSE, byalign, FALSE, 0, 0 )

'' type as short
symbAddField( ast.data.desc, "type", 0, dTB(), _
Expand Down
10 changes: 9 additions & 1 deletion src/compiler/fb.bas
Original file line number Diff line number Diff line change
Expand Up @@ -1768,7 +1768,15 @@ function fbGetBackendValistType _
typedef = FB_CVA_LIST_BUILTIN_ARM

case FB_CPUFAMILY_AARCH64
typedef = FB_CVA_LIST_BUILTIN_AARCH64
select case env.clopt.target
case FB_COMPTARGET_DARWIN
'' Apple's arm64 ABI uses a plain pointer-like va_list (8 bytes,
'' sizeof(va_list) == sizeof(char*)), not the AAPCS64
'' __va_list_tag struct that Linux/BSD aarch64 use.
typedef = FB_CVA_LIST_BUILTIN_POINTER
case else
typedef = FB_CVA_LIST_BUILTIN_AARCH64
end select

case FB_CPUFAMILY_PPC
typedef = FB_CVA_LIST_BUILTIN_POINTER
Expand Down
50 changes: 38 additions & 12 deletions src/compiler/fbc.bas
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,13 @@ private sub hSetOutName( )
select case( fbGetOption( FB_COMPOPT_TARGET ) )
case FB_COMPTARGET_CYGWIN, FB_COMPTARGET_WIN32
fbc.outname += ".dll"
case FB_COMPTARGET_LINUX, FB_COMPTARGET_DARWIN, _
case FB_COMPTARGET_DARWIN
'' Mach-O shared libraries are .dylib; .so is the loadable
'' bundle extension, and fb_DylibLoad() looks for the .dylib
'' name first on Darwin.
fbc.outname = hStripFilename( fbc.outname ) + _
"lib" + hStripPath( fbc.outname ) + ".dylib"
case FB_COMPTARGET_LINUX, _
FB_COMPTARGET_FREEBSD, FB_COMPTARGET_OPENBSD, _
FB_COMPTARGET_NETBSD, FB_COMPTARGET_DRAGONFLY, _
FB_COMPTARGET_SOLARIS, FB_COMPTARGET_ANDROID
Expand Down Expand Up @@ -840,6 +846,8 @@ private function hLinkFiles( ) as integer
case FB_CPUFAMILY_ARM
'' fixme: this is clearly too specific
ldcline += "-arch armv6 "
case FB_CPUFAMILY_AARCH64
ldcline += "-arch arm64 "
end select
end select

Expand Down Expand Up @@ -945,7 +953,13 @@ private function hLinkFiles( ) as integer

if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB ) then
dllname = hStripPath( hStripExt( fbc.outname ) )
ldcline += " -shared -h" + hStripPath( fbc.outname )
if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then
'' Darwin's linker (ld64) has no -shared/-h; it uses -dynamiclib
'' and records the install name via -install_name.
ldcline += " -dynamiclib -install_name " + QUOTE + dllname + QUOTE
else
ldcline += " -shared -h" + hStripPath( fbc.outname )
end if

'' Turn libfoo into foo, so it can be checked against -l foo below
if( left( dllname, 3 ) = "lib" ) then
Expand Down Expand Up @@ -987,7 +1001,13 @@ private function hLinkFiles( ) as integer
if( (fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB) or _
fbGetOption( FB_COMPOPT_EXPORT ) ) and _
(fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_SOLARIS) then
ldcline += " --export-dynamic"
'' Darwin links through the clang driver, which wants the option
'' spelled with -Wl, rather than passed through as --export-dynamic
if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then
ldcline += " -Wl,-export_dynamic"
else
ldcline += " --export-dynamic"
end if
end if

case FB_COMPTARGET_XBOX
Expand Down Expand Up @@ -1166,7 +1186,10 @@ private function hLinkFiles( ) as integer
FB_COMPTARGET_FREEBSD, FB_COMPTARGET_OPENBSD, _
FB_COMPTARGET_NETBSD, FB_COMPTARGET_DRAGONFLY, FB_COMPTARGET_SOLARIS

if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_EXECUTABLE) then
'' Darwin's linker takes no explicit crt1.o; the C compiler driver
'' supplies the startup object (it lives inside libSystem).
if( (fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_EXECUTABLE) and _
(fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) ) then
if( fbGetOption( FB_COMPOPT_PROFILE ) ) then
select case as const fbGetOption( FB_COMPOPT_TARGET )
case FB_COMPTARGET_OPENBSD, FB_COMPTARGET_NETBSD
Expand Down Expand Up @@ -1322,18 +1345,17 @@ private function hLinkFiles( ) as integer

end select

if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then
ldcline += " -macosx_version_min 10.4"
end if
'' Note: on Darwin the deployment target (-mmacosx-version-min) is supplied
'' by the C compiler driver used for linking, not hard-coded here.

'' This is required for 64-bit modules on *nix-y platforms
'' for the unwind tables to have any effect
'' Windows doesn't need this option
'' (ld64 rejects --eh-frame-hdr; Darwin is handled by clang instead)
select case as const fbGetOption( FB_COMPOPT_TARGET )
case FB_COMPTARGET_LINUX, FB_COMPTARGET_FREEBSD, _
FB_COMPTARGET_OPENBSD, FB_COMPTARGET_NETBSD, _
FB_COMPTARGET_DRAGONFLY, FB_COMPTARGET_SOLARIS, _
FB_COMPTARGET_DARWIN
FB_COMPTARGET_DRAGONFLY, FB_COMPTARGET_SOLARIS
dim as long outtype = fbGetOption( FB_COMPOPT_OUTTYPE )
if outtype = FB_OUTTYPE_EXECUTABLE OrElse outtype = FB_OUTTYPE_DYNAMICLIB Then
dim as long cpufamily = fbGetCpuFamily( )
Expand Down Expand Up @@ -1408,6 +1430,10 @@ private function hLinkFiles( ) as integer
var ld = FBCTOOL_LD
if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_JS ) then
ld = FBCTOOL_EMLD
elseif( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then
'' ld64 can't be driven like GNU ld (different crt handling, and it
'' rejects several GNU options), so use the C compiler driver to link.
ld = FBCTOOL_CLANG
end if

if( fbcRunBin( "linking", ld, ldcline ) = FALSE ) then
Expand Down Expand Up @@ -4308,9 +4334,9 @@ private sub hAddDefaultLibs( )
end if

case FB_COMPTARGET_DARWIN
fbcAddDefLib( "gcc" )
fbcAddDefLib( "System" )
fbcAddDefLib( "pthread" )
'' There is no libgcc on macOS unless a GCC toolchain is installed;
'' the clang driver pulls in libSystem (and thus libc/libm/pthread)
'' by itself. libncurses is still needed by the FB runtime.
fbcAddDefLib( "ncurses" )

case FB_COMPTARGET_DOS
Expand Down
19 changes: 17 additions & 2 deletions src/compiler/rtl-error.bas
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,16 @@ function rtlErrorCheck( byval expr as ASTNODE ptr ) as ASTNODE ptr
t = astNewLINK( t, astNewBOP( AST_OP_EQ, expr, astNewCONSTi( 0 ), nxtlabel, AST_OPOPT_NONE ), AST_LINK_RETURN_NONE )

'' fb_ErrorThrow()
t = astNewLINK( t, astNewBRANCH( AST_OP_JUMPPTR, NULL, hErrorThrow( reslabel, nxtlabel ) ), AST_LINK_RETURN_NONE )
'' Only -ex (-exx) enables RESUME support, and only then is a resume
'' label handed to the throw. Without one the throw can never return
'' a usable jump target, so a plain call is equivalent -- and it keeps
'' the generated C acceptable to clang, which rejects `goto *ptr` in
'' functions that take no label address.
if( env.clopt.resumeerr ) then
t = astNewLINK( t, astNewBRANCH( AST_OP_JUMPPTR, NULL, hErrorThrow( reslabel, nxtlabel ) ), AST_LINK_RETURN_NONE )
else
t = astNewLINK( t, hErrorThrow( reslabel, nxtlabel ), AST_LINK_RETURN_NONE )
end if

'' end if
t = astNewLINK( t, astNewLABEL( nxtlabel ), AST_LINK_RETURN_NONE )
Expand Down Expand Up @@ -361,7 +370,13 @@ sub rtlErrorThrow _
end if

'' dst
astAdd( astNewBRANCH( AST_OP_JUMPPTR, NULL, proc ) )
'' As in rtlErrorCheck(): an indirect jump is only meaningful when RESUME
'' support (-ex) is enabled and a resume label was passed along.
if( env.clopt.resumeerr ) then
astAdd( astNewBRANCH( AST_OP_JUMPPTR, NULL, proc ) )
else
astAdd( proc )
end if

astAdd( astNewLABEL( nxtlabel ) )
end sub
Expand Down
13 changes: 12 additions & 1 deletion src/rtlib/fb_data.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
/* Mach-O (Darwin) requires pointer-sized relocations to be aligned; the packed
layout would place the embedded pointers at 2-byte offsets, which ld64
rejects ("pointer not aligned ...", a hard error on arm64). The compiler
emits the matching naturally-aligned layout for Darwin targets, see
hCreateDataDesc() in src/compiler/ast-node-data.bas. */
#if defined(__APPLE__)
#define FB_DATADESC_PACKED
#else
#define FB_DATADESC_PACKED FBPACKED
#endif

struct _FB_DATADESC {
short len;
union {
Expand All @@ -6,7 +17,7 @@ struct _FB_DATADESC {
void *ofs;
struct _FB_DATADESC *next;
};
} FBPACKED;
} FB_DATADESC_PACKED;

typedef struct _FB_DATADESC FB_DATADESC;

Expand Down
19 changes: 18 additions & 1 deletion src/rtlib/profile_cycles.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,20 @@ typedef struct _FB_PROFILER_CYCLES
*/
#if !defined(HOST_DOS)

/* Mach-O section names are limited to 16 characters and, unlike ELF, the
linker does not synthesise __start_/__stop_ boundary symbols, so the
profiler's section scan cannot work the ELF way there; keep the record as a
plain used object instead. */
#if defined(HOST_DARWIN)
#define FB_PROFILE_SECTION_ATTR __attribute__((used))
#else
#define FB_PROFILE_SECTION_ATTR __attribute__((section("fb_profilecycledata"), used))
#endif

/* make sure there is at least one record in the profile data section */
static FB_PROFILE_RECORD_VERSION
__attribute__ ((aligned (16))) prof_data_version
__attribute__((section("fb_profilecycledata"), used)) =
FB_PROFILE_SECTION_ATTR =
{
sizeof( FB_PROFILE_RECORD_VERSION ),
FB_PROFILE_RECORD_VERSION_ID,
Expand Down Expand Up @@ -301,8 +311,15 @@ static void hProfilerWriteReport( FB_PROFILER_CYCLES *prof )
fprintf( f, "Total program execution time: %5.4g seconds\n", fb_Timer() - prof->start_time );
}

#if defined(HOST_DARWIN)
/* No __start_/__stop_ section symbols on Mach-O; fall back to the single
version record so the report is simply empty. */
data = (unsigned char *)&prof_data_version;
length = sizeof( prof_data_version );
#else
data = (unsigned char *)&__start_fb_profilecycledata[0];
length = (ssize_t)&__stop_fb_profilecycledata - (ssize_t)&__start_fb_profilecycledata[0];
#endif

count = hProfilerCountProcs( data, length );
if( count ) {
Expand Down
9 changes: 9 additions & 0 deletions src/rtlib/unix/fb_private_scancodes_x11.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@ typedef Display *(*XOPENDISPLAY)(char *);
typedef int (*XCLOSEDISPLAY)(Display *);
typedef void (*XQUERYKEYMAP)(Display *, unsigned char *);
typedef int (*XDISPLAYKEYCODES)(Display *, int *, int *);
/* XGetKeyboardMapping()'s first_keycode parameter is declared as KeyCode
(unsigned char) or as unsigned int depending on NeedWidePrototypes, which
Xfuncproto.h defaults to 1 unless NARROWPROTO is defined. Mirror Xlib's own
declaration, otherwise the function pointers do not match and clang (unlike
GCC, which merely warns) rejects the call. */
#if defined(NeedWidePrototypes) && NeedWidePrototypes
typedef KeySym* (*XGETKEYBOARDMAPPING)(Display *, unsigned int, int, int *);
#else
typedef KeySym* (*XGETKEYBOARDMAPPING)(Display *, KeyCode, int, int *);
#endif
typedef int (*XFREE)(void *);

extern unsigned char fb_x11keycode_to_scancode[256];
Expand Down