We mostly write programme in high level language. So while studying I came across assembly language. So an assembler converts assembly language to machine language and a compiler does the same with high level language. I found assembly language has instructions like move r1 r3 , move a 5 etc. And it is rather hard to study. So why was assembly language created?or was it the one that came first even before high level language? Why am I studying about assemblers in my computer engineering class?
"So why was assembly language created?"
Assembly language was created as an exact shorthand for machine level coding, so that you wouldn't have to count 0s and 1s all day. It works the same as machine level code: with instructions and operands.
"Which one came first?"
Wikipedia has a good article about the History of Programming Languages
"Why am I studying about assemblers in my computer engineering class?"
Though it's true, you probably won't find yourself writing your next customer's app in assembly, there is still much to gain from learning assembly.
Today, assembly language is used primarily for direct hardware manipulation, access to specialized processor instructions, or to address critical performance issues. Typical uses are device drivers, low-level embedded systems, and real-time systems.
Assembly language is as close to the processor as you can get as a programmer so a well designed algorithm is blazing -- assembly is great for speed optimization. It's all about performance and efficiency. Assembly language gives you complete control over the system's resources. Much like an assembly line, you write code to push single values into registers, deal with memory addresses directly to retrieve values or pointers. (source: codeproject.com)
Why do we need assembly language?
Well, there's actually only one language we will ever need, which is called "machine language" or "machine code". It looks like this:
This is the only language your computer can speak directly. It is the language a CPU speaks (and technically, different types of CPUs speak different versions). It also sucks to look at and try to understand.
Fortunately, each section of binary corresponds to a particular meaning. It is divided into a number of sections:
0010|0001|0010|0011 operation type source register other source destination register 0010 0001 0010 0011
These values correspond to:
operation type 0010 = addition source register 0001 = register 1 other source 0010 = register 2 destination register 0011 = register 3
So this operation would add the numbers in registers 1 and 2 and put that value in register 3. If you literally put these values into a CPU and tell it "go", it will add two numbers for you. The operation "subtract" could be a 0011 or something, instead of 0010 here. Whatever value will make the CPU do a subtraction.
So a program could look like this (don't try to understand it, since I made up this particular version of machine code to explain things):
instruction 1: 0010000100100011 instruction 2: 0011000110100100 instruction 3: 0101001100010111 instruction 4: 0010001001100000
Does this suck to read? Definitely. But we need it for the CPU. Well, if every machine code corresponds to a particular action, lets just make a simple "English" shorthand, and then once we understand what the program is doing, convert it into real binary machine code and give it to the CPU to run.
So our original instruction from above could look like:
(meaning) operation type source register other source destination register (machine code) 0010 0001 0010 0011 ("English") add r1 r2 r3
Note that this English version has an exact mapping to machine code. So when we write a line of this "English", we're really just writting friendlier and more understandable machine code.
Well, this is assembly language. That's why it exists, and why it was originally created.
To understand why we need it now, read the above answers, but the key this to understand is this: High level languages do not have a single representation is machine code. E.g. in C, or Python, or whatever:
z = x + y
This sounds just like our addition from above, assuming
x is in register 1,
y is in register 2, and
z should end up in register 3. But what about this line?
z = x * 2 + (y / 6) * p + q - r
Try representing that line in 16 bits of binary and telling a CPU "go". You can't. Machine code has no single operation instruction to perform an addition, subtraction, and whatever else with 4 or 5 variables at once. So it has to be converted to a sequence of machine code first. This is what you do when you "compile" or "interpret" a high level language.
Well, we have programs to do that, so why do we need assembly now? Well say your program is running more slowly than you expect, and you want to know why. Looking at the machine language "output" of this line, it might look like:
1010010010001001 0010001000010000 0110010000100100 0010001011000010 0010100001000001 0100010100000001 0010010101000100 0010101010100000 0000100111000010
Just to get that one line of Python done. So you really want to debug that?!?!?! NO. Rather, you ask your compiler to kindly give you the output in the form you can actually understand easily, which is the assembly language version corresponding exactly to that machine code. Then you can figure out if your compiler is doing something dumb and try to fix it.
(Extra note on @Raphael's advice: You could actually construct CPU's that work with things other than binary codes, like ternary (base 3) or decimal codes, or even ASCII. For practical purposes though, we really have stuck to binary.)
So why was assembly language created? or was it the one that came first even before high level language?
Yes, assembly was one of the first programming languages which used text as input, as opposed to soldering wires, using plug boards, and/or flipping switches. Each assembly language was created for just one processor or family of processors as the instructions mapped directly to opcodes run by the processor.
Why am I studying about assemblers in my computer engineering class?
If you need to program device drivers or write compilers then understanding how a processor works is invaluable, if not required. The best way to understand this is to write some code in assembly.
If you take a look at how a compiler writes code it is common to see options for calling conventions which without knowing assembly probably can't be understood.
If you have to resolve a bug and the only input you have is a core dump, then you definitely need to know assembly to understand the output which is assembly code and if lucky augmented with higher level statements of a high level language.
Let me add one less practical aspect. This is (probably) not a historic reason but a reason for you, today.
Assembly (compared to high-level languages) is naked. It does not hide anything (that is done in software), and it is simple in the sense that it has a relatively small, fixed set of operations.
This can be helpful for exact algorithm analysis. Semantics and control flow are so simple that counting all operations (or the expected number) can be done by annotating the control flow graph with transition counts (probabilities). Knuth does this in his TAoCP books to great effect, demonstrating some of the most rigorous algorithm analyses there are.
Anecdote: my colleague has learned to read Java Bytecode for exactly this purpose.
There are answers here:
Why Study Assembly language? by Gary L. Burt
All these answers point to:
- Speed/Memory Optimization
- Understanding how the machine works
- So Noob Programmers become Experts
- If you know assembly, you know how to write compilers for your High Lvl language
Assembly = machine code
Some people keep harping on about how assembly language is different from the numeric codes that the CPU understands.
This (whilst true) completely misses the point.
As far as translation goes assembly language and the numeric (binary, hex whatever) are one and the same thing.
Grok it or drop it
If you grok assembly you know how an actual computer works.
grokking assembly involves:
- Learning the instructions and what they mean (duh).
- Understanding what the instruction do, what they don't do and all their side-effects.
- Learning how a CPU processes the instructions
- How the pipeline works.
- What a CPU core is.
- How the cache works.
- Understanding how to cycle count
- learning the teachings of Agner Fog
- Understanding how compilers generate code and how they fail at times.
- Optimizing well defined and very specific problems.
If you grok assembly you well have a nearly complete picture of how the CPU connected to your keyboard works.
You need to use this knowledge like a brain surgeon uses his scalpel.
Don't need no stinking abstractions
Unless you grok assembly (and thus the CPU on the operating table) you will never be free of the clutches of the abstractions of the RAM machine (or god forbid the Turing machine the horror).
It is not the knowledge of assembly that matters, but knowledge of the machine your working on that matters.
If you want to know the machine, you must understand it and that means speaking the language of the machine.
If you don't then you're stuck with the abstraction.
That's science and that's good, but that's never the complete picture.
Because it's fun.
To date myself, I first learned RPG II using an IBM System 32, and later learned APL on a 370. I was all about size and speed. My mantra was smaller and faster. Assembly is the most compact and fastest language out there. I would make test programs in both C and Assembly. Where C programs would require 100's of Kb, an equivalent Assembly program would often be less that 5 Kb. When studying the output of the C compiler I would find code that would check and recheck parameters make conditional checks for possible errors that were quite often rare and exotic and quite unnecessary, all of which took time, but the biggest memory bloat was passing absolutely everything to and from the stack.
In today's programming environment writing code provides an extra level of security and protection. Being able to read info directly from a piece of hardware that is not accessible to high level languages, allows you to encrypt with Assembly in a way that a program can only be used on that particular machine. For example encrypting a user key using the MAC address of the network interface, and then parking that key on a specific unregistered sector of the hard drive then marking the sector as bad so that other files can't overwrite it. Of course you lose the sector, but what is that? 2048 or 4096 bytes out of billions or trillions?