P.S. If you ever modify an application bundle and it doesn’t behave, there’s a possibility it’s due to failing codesigning checks, fix that by using chmod +x /Applications/ApplicationBundle.app/Contents/MacOS/* && sudo codesign -fs - /Applications/ApplicationBundle.app

When it comes to getting Adobe products to work on non-Intel CPUs, back then you only had XLNC’s original patch and while it did do the job, there were some edge cases where the original patches weren’t enough. Taking what I can from the comments section and noting down what worked, I tried my hand at making a script and it did the job for me, though since then, a better patch has come along and I’d recommend using that instead.

Though I’ll still keep mine for reference for those who might need it (also because there’s a bit of sentimental value attached to it as it’s my first patch variant! Small victories and all that!)

Additional Resources

How to get Discord to behave on macOS

UPDATE: 3rd January 2022, the original blogpost did not include this method as I personally was weary with setting global environment variables but it hadn’t dawned on me at the time that Discord updates itself… rather frequently, which overwrites the patch, rather frequently, which is annoying; and as I’m a zsh user, dropping into a bash prompt and pasting my own script by visitng my own article to the point where I bookmarked my own post felt ridiculous.

Also, entering voice chat only for the app to crash causing a misunderstanding, was very annoying. So here’s a new way.

# This is a fork of https://gist.github.com/naveenkrdy/26760ac5135deed6d0bb8902f6ceb6bd
#
# I actually use the above script as now I'm back to using Adobe products
# but my install resulted using the fakeintel library patch, which 
# doesn't work for Discord.
#
# It's quite possible that what this does is already done by the above
# patch, this script should only be used if you 
# a) Aren't using Adobe products; or
# b) Use Adobe products but the fakeintel patch was applied by the above script

agent_dir="${HOME}/Library/LaunchAgents"
env_file="${agent_dir}/environment_mkl.plist"

mkl_value=$(
    sysctl -n machdep.cpu.brand_string | grep FX >/dev/null 2>&1
    echo $(($? != 0 ? 5 : 4))
)

[[ ! -d $agent_dir ]] && mkdir $agent_dir
cat >$env_file <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>Label</key>
 <string>mkl-debugenv</string>
 <key>ProgramArguments</key>
 <array>
 <string>sh</string>
 <string>-c</string>
    <string>launchctl setenv MKL_DEBUG_CPU_TYPE $mkl_value;</string>
 </array>
 <key>RunAtLoad</key>
 <true/>
</dict>
</plist>
EOF

# Courtesy of https://developer.apple.com/forums/thread/665661
launchctl unload ${AGENT} >/dev/null 2>&1 

launchctl load -w ${AGENT} >/dev/null 2>&1
launchctl start ${AGENT} >/dev/null 2>&1

Ordinarily I’d delete the old method but I figure the explanation of how it works might be useful to someone, so I’ve kept it here.

#!/usr/bin/env bash

# DO NOT USE ME, I NOT A PERSISTENT PATCH AND EVERY DISCORD UPDATE
# WILL REVERT ME, DO NOT USE THIS PATCH!!!!

function _mkldebug_patch {
  BUNDLE_ROOT=$1
  BUNDLE_NAME=$(echo "$1" | sed 's@.*/@@' | sed 's/.app//g')
  echo "MKL_DEBUG_CPU_TYPE=5 ./$BUNDLE_NAME" > "$BUNDLE_ROOT"/Contents/MacOS/dLauncher && chmod +x "$BUNDLE_ROOT"/Contents/MacOS/dLauncher
  plutil -replace CFBundleExecutable -string "dLauncher" "$BUNDLE_ROOT"/Contents/Info.plist
}

export -f _mkldebug_patch
find /Applications -type d -iname "*Discord*.app" -depth 1 | xargs -I {} bash -c '_mkldebug_patch "$@"' _ {}

Let’s break this script down, shall we?

It’s a simple script.

It’s essentially an automation of u/neoney's method (see “Additional Resources”) that extends to all variants of Discord (including Canary, which I use because I love Powercord and Public Test Builds)

#!/usr/bin/env bash

The #! (also known as a shebang or hash-bang) tells the program loader to use a particular interpreter to parse and execute our shell script.

A lot of scripts (including some of my older ones), tend to use the Bash interpreter located at /bin/ instead of /usr/local/bin (where Homebrew installs packages on macOS) and while that might do the job (as long as the version disparity between the two versions isn’t too large and you’re not attempting to use the latest Bash features), I’d still prefer to invoke a version of bash that’s preferred by the user.

For example, I update my version of bash using Homebrew as macOS no longer ships with updated versions for legal reasons and using the interpreter defined through /usr/bin/env will execute my script using GNU bash, version 5.1.8(1)-release (x86_64-apple-darwin18.7.0) (the latest version of Bash as of this writing), while using the interpreter in /bin/ will run with the version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18) which was last updated in 2007.

function _mkldebug_patch {
  BUNDLE_ROOT=$1

We are defining a function _mkldebug_patch that will accept one argument. Unlike programming languages like C++, you don’t explicitly specify the type of argument or its name, you only get a number, $0 referencing itself, $1 representing the first argument and so on….

To keep things easier to track, I assign $1's value to a variable named BUNDLE_ROOT so it’s easier for me to keep track of what that argument is used for.

  BUNDLE_NAME=$(echo "$BUNDLE_ROOT" | sed 's@.*/@@' | sed 's/.app//g')

This variable takes the first argument (which is the location of the Discord application bundle, usually /Applications/Discord.app and pipes it through a program called sed, the first call everything before (and including) the last forward slash and the second sed call simply replaces all instances of .app (which we can safely presume to be 1) with nothing, effectively removing it.

So, if BUNDLE_ROOT is set to /Applications/Discord Canary.app, then BUNDLE_NAME will be Discord Canary.

  echo "MKL_DEBUG_CPU_TYPE=5 ./$BUNDLE_NAME" > "$BUNDLE_ROOT"/Contents/MacOS/dLauncher && chmod +x "$BUNDLE_ROOT"/Contents/MacOS/dLauncher

The magic sauce to XLNC’s patches are the usage of an undocumented environment variable (specifically MKL_DEBUG_CPU_TYPE) that allows non-Intel CPUs to use optimised code paths that are otherwise artificially restricted to Intel CPUs (the fact that we can run them on non-Intel systems show that there isn’t a technical reason as to why they can’t run on non-Intel x86_64 processors)

Normally, this should give you only a speed improvement, it shouldn’t be a prerequisite to an application functioning at all but in macOS-land, where Intel-only processors are the norm, there’s no reason for the binary to account for non-Intel processors.

So it tries to run under the presumption that it’s an Intel-based machine and it crashes, by using this flag it skips over the crash-inducing check and then we’re golden! We basically create a small script setting this magic variable before running the actual Discord binary and mark it as executable using chmod

  plutil -replace CFBundleExecutable -string "dLauncher" "$BUNDLE_ROOT"/Contents/Info.plist
}

Let me let you in on a little secret, /Applications/Discord Canary.app isn’t actually an application, it’s a folder… more specifically called an Application Bundle, double-click-to-execute-folders-as-bundles are a thing macOS has inherited from NeXTStep and the binary that’s actually executed is defined by an XML file called Info.plist located within Contents

By default, macOS will launch the binary located within the MacOS directory within Contents, so when you launch open /Applications/Discord Canary.app, macOS is guided to open the binary /Applications/Discord Canary.app/Contents/MacOS/Discord Canary which is all good but we don’t want that behaviour here.

We want it to open our script, which will open Discord with the set variable, so by using a Property List manipulation tool that comes with macOS, we change the value of CFBundleExecutable, a key that dictates what should be launched from the MacOS directory when executing the bundle from Discord Canary to dLauncher (the script we just created)

export -f _mkldebug_patch

Since we are planning to use this function on every Discord application bundle found (which will be done using find, we will be spinning up new instances of the Bash interpreter, so we need to ensure that our function is globally accessible, hence the export.

find /Applications -type d -iname "*Discord*.app" -depth 1 | xargs -I {} bash -c '_mkldebug_patch "$@"' _ {}

Let’s break this command down even further…

  • find /Applications, search in the Applications directory at the root of the volume
  • -type d, only list directories
  • -iname "*Discord*.app", that contain the word Discord before or after it, excluding the extension and…
  • -depth 1, to go only one level deep, we don’t need a thorough recursive search. This is to avoid false positives.

This command alone would print on my computer

bash-5.1$ find /Applications -type d -iname "*Discord*.app" -depth 1
/Applications/Discord Canary.app
/Applications/Discord.app

Okay, we found our Discord appbundles but now we must run the patch on it, since our patch cannot accept multiple variables (it only expects one), we have to run the function twice, once for each bundle found.

We pipe the output of find using the | operator and then run xargs -I {} bash -c '_mkldebug_patch "$@"' _ {} which runs a new Bash instance that’ll run the patch function, accepting the contents of each line as the first argument.

How to get Adobe products to behave on macOS

Use the naveenkrdy patch but if that doesn’t work, here’s mine which is also a Github Gist!

#!/usr/bin/env bash

cpuname=$(sysctl -n machdep.cpu.brand_string)

# Patch Lightroom Classic first
sudo perl -i -pe 's|\x90\x90\x90\x90\x56\xE8\x3A\x00|\x90\x90\x90\x90\x56\xE8\x1A\x00|sg' /Applications/Adobe\ Lightroom\ Classic/Adobe\ Lightroom\ Classic.app/Contents/Frameworks/CameraRaw.lrtoolkit/CameraRaw
sudo perl -i -pe 's|\x90\x90\x90\x90\x56\xE8\x5A\x00|\x90\x90\x90\x90\x56\xE8\x3A\x00|sg' /Applications/Adobe\ Lightroom\ Classic/Adobe\ Lightroom\ Classic.app/Contents/Frameworks/CameraRaw.lrtoolkit/CameraRaw

# Patch MMXCore and FastCore instances in all other applications
find /Applications/Adobe* -type f -name "MMXCore" -print0 | sudo xargs -0 -I "{}" perl -i -pe 's|\x90\x90\x90\x90\x56\xE8\x5A\x00|\x90\x90\x90\x90\x56\xE8\x3A\x00|sg' "{}"
find /Applications/Adobe* -type f -name "MMXCore" -print0 | sudo xargs -0 -I "{}" perl -i -pe 's|\x90\x90\x90\x90\x56\xE8\x6A\x00|\x90\x90\x90\x90\x56\xE8\x3A\x00|sg' "{}"
find /Applications/Adobe* -type f -name "FastCore" -print0 | sudo xargs -0 -I "{}" perl -i -pe 's|\x90\x90\x90\x90\x56\xE8\x5A\x00|\x90\x90\x90\x90\x56\xE8\x3A\x00|sg' "{}"
find /Applications/Adobe* -type f -name "FastCore" -print0 | sudo xargs -0 -I "{}" perl -i -pe 's|\x90\x90\x90\x90\x56\xE8\x6A\x00|\x90\x90\x90\x90\x56\xE8\x3A\x00|sg' "{}"

#Patch Camera Raw
sudo perl -i -pe 's|\x90\x90\x90\x90\x56\xE8\x3A\x00|\x90\x90\x90\x90\x56\xE8\x1A\x00|sg' /Library/Application\ Support/Adobe/Plug-Ins/CC/File\ Formats/Camera\ Raw.plugin/Contents/MacOS/Camera\ Raw
sudo perl -i -pe 's|\x90\x90\x90\x90\x56\xE8\x5A\x00|\x90\x90\x90\x90\x56\xE8\x3A\x00|sg' /Library/Application\ Support/Adobe/Plug-Ins/CC/File\ Formats/Camera\ Raw.plugin/Contents/MacOS/Camera\ Raw

# Delete Camera Raw
#sudo rm -rf /Library/Application\ Support/Adobe/Plug-Ins/CC/File\ Formats/Camera\ Raw.plugin

# Photoshop and Illustrator specific fix
sudo rm -rf /Applications/Adobe\ Photoshop*/Adobe\ Photoshop*/Contents/Required/Deep_Font
sudo rm -rf /Applications/Adobe\ Illustrator*/Adobe\ Illustrator*/Contents/Required/Plug-ins/Text\ Filters/TextModel.aip

# Re-sign the binary (this may break activation, can't really get around that)
sudo codesign -fs - /Applications/Adobe*/Adobe*.app
sudo codesign -fs - /Library/Application\ Support/Adobe/Plug-Ins/CC/File\ Formats/Camera\ Raw.plugin

# Generate environment variable plist from base64
echo "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KIDxrZXk+TGFiZWw8L2tleT4KIDxzdHJpbmc+bXkuc3RhcnR1cDwvc3RyaW5nPgogPGtleT5Qcm9ncmFtQXJndW1lbnRzPC9rZXk+CiA8YXJyYXk+CiA8c3RyaW5nPnNoPC9zdHJpbmc+CiA8c3RyaW5nPi1jPC9zdHJpbmc+CiA8c3RyaW5nPmxhdW5jaGN0bCBzZXRlbnYgTUtMX0RFQlVHX0NQVV9UWVBFPTQ8L3N0cmluZz4KIDwvYXJyYXk+CiA8a2V5PlJ1bkF0TG9hZDwva2V5PgogPHRydWUvPgo8L2RpY3Q+CjwvcGxpc3Q+" | base64 --decode > onemomentplease.plist

# Upgrade version if necessary and copy to launchdaemons folder
if [[ $cpuname == *"Ryzen"* ]]; then
  cat onemomentplease.plist | tr '4' '5' > onemomentplease2.plist
  sudo cp onemomentplease2.plist /Library/LaunchDaemons/startupadobepatch.plist
else
  sudo cp onemomentplease.plist /Library/LaunchDaemons/startupadobepatch.plist
fi

# Run for current instance
launchctl load /Library/LaunchDaemons/startupadobepatch.plist
launchctl start /Library/LaunchDaemons/startupadobepatch.plist

# Cleanup
rm onemomentplease*.plist