-
Notifications
You must be signed in to change notification settings - Fork 75
Description
We have successfully built NCAR Graphics 6.6.2 on ARM64 macOS (Apple Silicon M1/M2/M3) and identified several source code changes required. The most critical is a bug in gsbytes.c that causes SIGSEGV crashes on ARM64.
Environment
- macOS on Apple Silicon (ARM64)
- Homebrew GCC 15 / gfortran
- XQuartz for X11
Critical Bug Fix: gsbytes.c
Problem
On ARM64 architectures, long is 64-bit (8 bytes), but the code in common/src/libncarg_c/gsbytes.c assumes 32-bit words (#define SWORD 32). This mismatch causes:
- Incorrect bit shifting operations
- Memory corruption and buffer overflows
- SIGSEGV crashes when using NCGM workstation (type 1)
The crash occurs in the SBYTES/GBYTES bit-packing routines called during metafile generation.
Fix
Change all long declarations to int in gsbytes.c:
// Original (crashes on ARM64):
extern void NGCALLF(gbyte,GBYTE)(long *p, long *u, long *q, long *b);
extern void NGCALLF(sbyte,SBYTE)(long *p, long *u, long *q, long *b);
void NGCALLF(gbytes,GBYTES)(p, u, q, b, s, n)
long *p, *u, *q, *b, *s, *n;
{
register long i = 0, jp = 0;
long jq = *q;
// Fixed (works on ARM64):
extern void NGCALLF(gbyte,GBYTE)(int *p, int *u, int *q, int *b);
extern void NGCALLF(sbyte,SBYTE)(int *p, int *u, int *q, int *b);
void NGCALLF(gbytes,GBYTES)(p, u, q, b, s, n)
int *p, *u, *q, *b, *s, *n;
{
register int i = 0, jp = 0;
int jq = *q;Functions requiring this change:
gbytes()- unpack multiple bytessbytes()- pack multiple bytesgbyte()- unpack single bytesbyte()- pack single byteg8bits()- get 8-bit bytess8bits()- store 8-bit bytes
New Configuration File: config/Darwin_ARM64
A new configuration file is needed for ARM64 macOS builds:
/*
* Description: Configuration for gfortran/gcc build on ARM64 (Apple Silicon) Mac.
* Created for macOS on M1/M2/M3 chips.
*/
#define HdfDefines -DDARWIN
#define StdDefines -DSYSV -D_POSIX_SOURCE -D_XOPEN_SOURCE -DByteSwapped -D__UNIXOS2__ -D_DARWIN_C_SOURCE
#define ByteSwapped
#define Cstatic
#define Cdynamic
#define CppCommand '/usr/bin/cpp -traditional'
#define CCompiler /opt/homebrew/bin/gcc-15
#define CxxCompiler /opt/homebrew/bin/g++-15
#define FCompiler /opt/homebrew/bin/gfortran
#define CcOptions -fPIC -fopenmp -std=gnu89 -Wno-implicit-int -Wno-implicit-function-declaration
#define FcOptions -fPIC -fno-range-check -fopenmp -fallow-argument-mismatch -fallow-invalid-boz
#define CtoFLibraries -L/opt/homebrew/lib -lgfortran -lquadmath
#define CtoFLibrariesUser -lgfortran -lquadmath
#define XToolLibrary -lXt -lSM -lICE
#define BuildShared NO
#define XLibrary -lXpm -lX11 -lXext
#define LibSearchUser -L/opt/X11/lib -L/opt/homebrew/lib
#define IncSearchUser -I/opt/X11/include -I/opt/homebrew/include -I/opt/homebrew/include/freetype2
#define ArchRecLibSearch -L/opt/X11/lib -L/opt/homebrew/lib
#define ArchRecIncSearch -I/opt/X11/include -I/opt/homebrew/include
FC = $(F77)Fortran BOZ Literal Constants (~97 files)
Modern gfortran rejects BOZ literal constants (e.g., Z'40000000') in certain contexts. These need to be converted to decimal integers.
Example change in ncarg2d/src/libncarg_gks/bwi/argb2ci.f:
! Original (fails with modern gfortran):
parameter (ARGBMASK = Z'40000000')
parameter (RMASK = Z'00FF0000')
r = (iand(index, RMASK) / Z'0000FFFF') / 255.
! Fixed (decimal equivalents):
parameter (ARGBMASK = 1073741824)
parameter (RMASK = 16711680)
parameter (RSHIFT = 65535)
r = (iand(index, RMASK) / RSHIFT) / 255.Fortran compiler flags that help:
-fallow-invalid-boz- Allows some BOZ usage (but not all)-fno-range-check- Relaxes range checking
Summary of Required Changes
- Critical: Fix
common/src/libncarg_c/gsbytes.c- changelongtoint - New file: Add
config/Darwin_ARM64configuration - ~97 Fortran files: Convert BOZ literals to decimal integers
- Site.local: Configure with
BuildShared NOfor static libraries
Testing
After these changes:
- GKS workstation type 1 (NCGM) works correctly
- gmeta files are generated successfully
- ctrans converts gmeta to PostScript and other formats
- All basic NCAR Graphics functionality tested and working
Notes
- The gsbytes.c fix may also apply to other 64-bit platforms where
sizeof(long) != 4 - Consider using
int32_tfrom<stdint.h>for maximum portability - The Fortran BOZ changes could potentially be automated with a script
Tested on macOS Sequoia (ARM64) with Homebrew GCC 15, XQuartz, December 2025