# Learning .NET Core Backwards: Introduction

I have mentioned before that learning .NET Core on _nwp_ s11 Non-Windows platforms. can be an exercise in frustration, because everything is so… different22 In many cases in a good way, but with missing documentation.. When I started my current employment at a .NET shop just over a year ago, I had not touched .NET with a stick before. I have now used .NET Core profesionally for over a year, and during that time I have (mostly) treated it as a black box: high level code goes into the machinery, and at the end of the month a paycheck comes out of it.

This approach has had mixed results. I sometimes find myself feeling like a commercial jet pilot, thinking33 This is actually a thing: commerical jets are automated beyond the pilots’ understanding., “and what’s it doing now?”

So I’m going to learn .NET backwards. From the basic building blocks. This is going to be painful, but also extremely illuminating. I hope you will read this with a feeling of, “Ooh, so that’s how that works?”, or “Ah, this thing makes much more sense now.”

This introduction article is split into three parts: the background you just read, a quick description of how .NET Core is normally used, and then the main part is where I describe how to get the tools we need to even start this journey: the IL assembler and a minimal runtime.

What I’m going to do is not normal. This section describes how you should use .NET Core if you ended up in this article by accident, and just want to get on with your life.

I recommend you read my Introduction to .NET through a historic lens in case you haven’t already: it will explain terminology that is central to understanding how to use .NET.

Summary for people in a hurry: .NET is an umbrella term for three things:

• A runtime platform (called clr) with a bytecode language (called IL);
• A standard library (in our case, called Core _fx_); and
• Some high level languages that compile to the platform (e.g. C#).

The latest attempt by Microsoft to embrace, extend, extinguish^W^W^W^W other platforms is a cross-platform version of .NET, which they call .NET Core. This runs on non-Windows platforms.44 Although of course it runs better on WIndows…

The latest version of .NET Core is 3.0 at the time of writing, and there are actually not that many things you need to know to use it:

You should download and install the latest sdk, which you can find by making an internet search for “.NET Core 3.0 sdk download.” Then there are basically just five commands that will take you a long way:

• To create a new project: dotnet new console
• To add an external library: dotnet add package NameOfLibrary
• To run your project: dotnet run
• To compile your project to a single executable: dotnet publish -r linux-x64 /p:PublishSingleFile=true

Congratulations, you now know how to use .NET Core! That’s it.

This is good, because it’s easy to use in day-to-day operation. But it hides a lot of what is happening under the bonnet. This robs you of an opportunity to learn about the system and how it is put together – knowledge that is vital when things go wrong.

From this point forward, I assume that you have successfully built a couple of .NET Core applications before, and you know want a better understanding of what you are doing.

.NET code runs on the clr, which is a virtual machine of sorts. This machine runs a bytecode known as IL.

Although the .NET Core sdk ships with the clr, it only gives you access to it through a high-level interface, the dotnet command. This isn’t going to cut it for us. We will start out with two very specific applications: ilasm and corehost.

The first, ilasm, is an IL assembler. This means that it takes a textual description of the bytecode you want to run, and outputs a file containing that bytecode. The other tool, corehost, takes a file containing IL bytecode, and runs it on the clr. Together, they allow us to go from a low-level specification of bytecode to a running program.

Note that this is not the lowest level we could start at. We could, for example, write the bytecode directly, or manually load it onto the clr by writing our own runner. Whatever level you start at is never the lowest level55 Unless you start by making the universe.. I picked the ilasm-and-corehost level because it seemed like a reasonable compromise between understanding and distraction.

Unfortunately, the only way I know of that will actually give us ilasm and corehost is to download the source code to Core _clr_ and compile it ourselves. You can get the sources from the Core _clr_ GitHub page.

The specifics of how to build Core _clr_ will vary from platform to platform, and the documentation is highly approximate. On a Debian-like system, I had to do something is something like this66 Although maybe the CMake version in the repositories was too old.:

$sudo apt install build-essential clang cmake python libicu-dev liblttng-ust-dev$ for tool in "ar link nm objdump"; do \
sudo cp /usr/bin/$tool /usr/bin/llvm-$tool; done
\$ ./build.sh


This is going to take a long time. It is a big project!

# Mono

If you are determined to follow along using Mono instead, you’re made a smart choice. When you install Mono, ilasm is automatically installed with it! To run your program, simply use mono instead of corehost.

Some things are going to be different between Mono and .NET Core, but I’m going to do my best to add instructions for Mono, because

1. It’s frankly still easier to work with on _nwp_ s, and
2. I think it’s healthy with competing implementations.

# Next Steps

In the next article, we will create simple .NET programs. We will not use C#, F#, Visual Basic, or any other high-level language – instead, we will write our desired IL instructions by hand.