Believe it or not, it’s possible to develop Assembly programs inside of Replit, and it’s pretty easy too.
I learned some very basic Assembly earlier today after watching a couple of online videos. It’s much simpler than you may think, and I got a working program within minutes. Using a tool called
nasm, I assembled a program, linked it, and executed it on GitHub Codespaces after doing some installing. It’s actually much easier here on Replit though.
Well, lets get started!
First, create a Blank Repl, delete any packages from
replit.nix and anything else you think you won’t need, as its good to have a clean workspace. Secondly, install
nasm through Nix. Originally, you would have to download, unpack, etc, but Nix supports it from the start! Simply query
nasm in either Console or Shell and type
Y to install.
And it was that simple! Everything should be configured for you to start making your first Assembly programs. Keep in mind Replit is using the
Let’s talk about actually creating a basic Assembly program.
Now, keep in mind, Assembly code is different across different computer architectures. The following code only works on x86-64 systems with a Linux kernel. This means that if you have a modern processor and are running a distro of Linux, it should work for you. However, you will not be able to use this program on any Windows (unless your using
wsl) or Mac.
First, lets create a file called
hello.asm. Add the following code to it.
bits 64 section .data hello: db "Hello, World!", 10 length: equ $-hello section .text global _start _start: mov rax, 1 mov rdi, 1 mov rsi, hello mov rdx, length syscall mov rax, 60 xor rdi, rdi syscall
This program prints
Hello, World! to the screen. This is pretty complex compared to high-level programming languages, but hopefully this is what you expected, as Assembly is basically the “lowest-level” you can get without directly writing machine code.
Let’s assemble, link, and run our program! If you want, you can just copy the following command to run instantly.
nasm -felf64 app.asm && ld app.o -o app && ./app
First, we need to invoke
nasm -felf64 [dir], or in our case
nasm -felf64 app.asm. This should convert our program into machine code for our architecture. Incase your wondering,
-felf64 is the directive, which assembles our
x86_64 code into a 64-bit ELF, per this StackOverflow post.
However, were not done yet, as we have to use a linker, invoked like so,
ld ["nasm'd" file] -o [output filename], or in our case, as following.
ld app.o -o app, which passes in the pre-assembled app.o, which was the output of the assembler command, and names the final, linked executable,
The linker resolves external references and combines our program into a single executable, per ChatGPT’s response.
ChatGPT's Full Response
Q: Let’s say you assembled an ASM program using NASM. Why do you have to use a linker afterward?
A: When you assemble an ASM (Assembly) program using NASM (Netwide Assembler), the assembler converts the assembly code into machine code instructions specific to the target architecture. However, the assembly program may contain references to external symbols, such as functions or variables, that are defined in other source files or libraries.
The purpose of the linker is to resolve these external references by finding the corresponding symbol definitions and patching the appropriate memory addresses in the object code. The linker takes one or more object files, which are the output of the assembler, and combines them into a single executable file or a library.
Here are a few reasons why we need to use a linker after assembling an ASM program:
- Symbol resolution: The linker resolves references to symbols defined in other source files or libraries. It ensures that each symbol is correctly linked to its corresponding memory location, allowing the program to access functions and variables defined in different modules.
- Address relocation: The linker performs address relocation, adjusting memory addresses in the object code to match the final memory layout of the executable. This includes updating relative or absolute memory references and fixing up jump or call instructions.
- Library linking: If your ASM program uses functions or libraries provided by an external library, the linker incorporates the necessary object code from those libraries into the final executable. This allows your program to access the functionality provided by those libraries at runtime.
- Code and data organization: The linker organizes the different sections of the program, such as code segments, data segments, and other sections, into the appropriate memory locations. It ensures that the program’s memory layout is coherent and follows the rules of the target architecture.
- Optimization and code size reduction: The linker can perform various optimizations, such as dead code elimination, function inlining, and code size reduction techniques. These optimizations can improve the performance and reduce the size of the final executable.
Overall, the linker plays a crucial role in combining the object code generated by the assembler, resolving symbol references, organizing the code and data, and producing a complete executable file or library that can be executed or used by other programs.
Finally, you can execute the file by invoking
./app in our case. And there you go! If done correctly, you should see
Hello, World! on the screen.
Apologies for my lack of knowledge in this topic, I literally just learned my first ASM today I did learn a lot more about computers, and you should definitely run the boilerplate code through ChatGPT or watch a tutorial online to get a better understanding on what its doing, as I cannot explain it with my currently knowledge.
I am currently working on creating a template, and it should be out within minutes of the release of this post. All you have to do is click run, and done! Even though there are many high-level replacements to Assembly, its still extremely cool to interact with the Kernel directly.
I hope this post helped you, and maybe you learned something new?