1

In my Assembly Language book, the Virtual Machine Levels are listed as follows:

  • Level 4: High-Level Language
  • Level 3: Assembly Language
  • Level 2: Instruction Set Architecture (ISA)
  • Level 1: Digital Logic

According to the book, Level 2 (ISA) are instructions for the processor; the ISA is also referred to as machine language. Each instruction in this level gets executed either directly by the computer's hardware or by a program embedded in the microprocessor chip called a microprogram.

Above Level 2, is the Assembly Language level 3, programming languages that provide translation layers to make large-scale software development practical. This level uses short mnemonics like ADD, SUB, and MOV that can be easily translated to the ISA on level 2. These type of programs must be translated, or assembled, entirely into machine language at the ISA level before they can be executed.

Top tier is Level 4, high-level programming languages such as C, C++, and Java. These are stated as languages containing powerful statements that translate into multiple assembly language instructions.

That being said, I'm not quite following what the relationship is between a high-level language, say Java in this case, and Assembly Language. In my view high-level languages are simplified to where a single programmed statement may inherently perform many code lines worth of functionality, unlike assembly which needs an explicit statement for each action.

Can anyone provide some input to clear it up for me? This is my first time looking into Assembly, and it thus far is a very different world than my experience in C#.

Analytic Lunatic
  • 3,853
  • 22
  • 78
  • 120
  • 2
    What you say sounds correct. I can't follow where you are not following – zapl Jan 15 '14 at 23:43
  • 3
    Your book misses one level - the IL produced by Java (and C# and VB), which is what the compiler produces, which is somewhere between level 3 and 4. When the application runs, the IL is translated to assembly. – Dave Doknjas Jan 15 '14 at 23:47
  • 2
    Below level 1 should be a level 0: transistors. We can argue whether level -1 consists of geometric structures made of various kinds of doped silicon, germanium, or other mediums which carry electrons to some extent ("semiconductors"). What the levels basically mean is that you can construct level N using level N-1 devices relatively easily, without using level >N abstractions. – Ira Baxter Jan 15 '14 at 23:50
  • Also, in assembly, the instructions are closely linked to the CPU. An instruction that works on one type of CPU will most likely not be understood by a different type of CPU. – agbinfo Jan 15 '14 at 23:56
  • There are more levels than that. What they call "High level language" is really what most people would call a low level language that compiles directly to assembly code (e.g. C, C++, some dialects of Lisp, D, Obj-C). There is another level of languages that are considered high level that run on VM's running at the low level language level. These are languages like Java (the JVM), C# (the CLR), Ruby (YARV, sometimes the JVM), Python (the python interpreter), and so on. – Linuxios Jan 16 '14 at 01:51
  • There is also Level 5: Very High-Level Languages, such as Lisp, Prolog, Haskell, SQL etc. – Erik Kaplun Feb 01 '22 at 10:43
  • You can think of it as graphs of various density: higher levels correspond to graphs with fewer nodes and higher expressive content per node, lower levels correspond to graphs with many primitive nodes. Translations or isomorphisms between these levels (or expressive levels of these graphs) are perhaps the relationship you are looking for. – Erik Kaplun Feb 01 '22 at 10:46

5 Answers5

2

The number of high-level statements per assembly statement varies enough that it's a poor measure of the difference between the two. People are often somewhat surprised by how few assembly language statements it can take to implement something that seems like it would be much more complex. In some cases, something even turns out much simpler in assembly language than a higher level language.

The primary difference of note is that in assembly language you have direct access to the CPU's registers, which is not available in most higher level languages. You also have responsibility for managing registers--deciding which variable to put into which register, how long to keep it there, when to write it back to memory, and so on.

Likewise, you generally have more control over (and responsibility for) how you arrange your data in memory. In a higher level language, the compiler decides what variables to create on the stack, what to create in static memory, what to allocate on the heap, and so on. In some cases (e.g., C or C++) you have some degree of indirect control over these decisions, such as local variables typically being allocated on the stack and globals being allocated statically. In assembly language, this control is direct and explicit. For example, you don't necessarily get to refer to a local variable by name--you'll typically explicitly refer to an offset from the stack pointer.

One other (mostly fairly minor) point: not all CPUs use microprogramming. In some cases, all instructions are implemented directly in hardware. There can also be differences between different models of CPUs that implement the same instruction set--for example, in the Intel x86 line, early models (e.g., 8088, 80286) used microcode for a lot of instructions. More recent models use microcoding a lot less, primarily to increase execution speed. To the programmer, this change is largely irrelevant, except that microcoded instructions tend to execute relatively slowly on current processors, so you're more likely to avoid them in most new code.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
2

There is no direct relationship between higher-level languages and assembly languages.

It might be that a C compiler or Java JIT generates assembly language and then runs an assembler to convert this to machine instructions.

Then again, it might be that it doesn't, since a compiler or JIT is just as capable of outputting machine instructions as an assembler is.

This is entirely a design/implementation decision when you write your C compiler or your Java JIT. So if you were drawing a diagram of the technologies used to compile and execute code in the higher-level language, you might be able to leave out level 3 entirely, depending on exactly how the compiler was written. Assembly language is mostly (not entirely) a long-winded way of writing out machine instructions as human-readable text, but it's not the only way to generate machine instructions (as machine instructions are the only way to get the CPU to do anything involving "digital logic").

I'm not entirely sure why assembly is listed as a separate "virtual machine level". Unlike a high-level language it doesn't relate to a significantly different execution model from the model the machine instructions do. That said, it does abstract a few things that the machine instructions do not necessarily abstract. For example it contains labels and fixups and so on that are replaced by addresses and values by the time the machine code is loaded into memory and ready to run. But then again, machine code stored in an executable file does abstract those things too, so what level is that? Perhaps by reading further into your book you'll find examples of what this classification into levels is intended to achieve.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
1

In days of old, and sometimes today, compilers and interpreters translated a high level language into Assembly language. The Assembler would convert the assembly language into machine language.

The conceptual layers have to do with abstraction concepts, productivity, and portability. The high level languages allow programs to implement more concepts rather than worrying about registers and hardware. Thus allowing for programmers to be more productive.

The concepts of high level languages allow easier portability between platforms. For example, a stack data structure implemented in 80386 assembly does not run on an ARM7. The module would need to be rewritten for the ARM7 in order for anything using it to be ported to the ARM7.

Development time slows to a crawl when developers are coding in assembly. Productivity needed to be increased in order to produce products and projects at a faster rate. The productivity also including time to resolve errors.

For example let us take the statement a = b + c; which is the assignment of the sum of b and c to the variable a. This involves the following (generic) low level operations:

  1. copy value of variable b from memory to register 0
  2. copy value of variable c from memory to register 1
  3. add register 0 to register 1 and place sum in register 2
  4. store value in register 2 to variable a in memory.

So here the ratio is one line of a high level language to 4 lines of assembly language. To see for yourself, take the hello world program and print out the assembly language listing.

If a developer has an error injection rate of 1 error per line of code, then the assembly language example above would be prone to 4 errors and the high level language to 1. Higher level languages were also designed to reduce the errors generated by programmers as the application kept increasing in size.

One drawback of high level languages is their ability to access hardware or optimize for a specific processor. Fundamental FORTRAN and LISP, and somewhat Java and C#, do not allow easy access to hardware.

There are higher level languages than C, C++ and Java. These languages concern themselves with abstract concepts and implementations, allow the programmers to focus more on concepts than languages.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
1

Firstly, each high-level language has its own way of executing the programs(some are similar).

A Java program compiles into a Java bytecode then it is executed in an emulator(its own virtual computer). During the execution, that emulator communicates with the operating system (from outside) and uses its operating system calls. For example: You have a file explorer implemented in Java. When the part of the code that deletes a file is being executed, a message is sent to the operating system for deletion.

Nevertheless, the main idea in high-level languages is the abstraction that you can use(if you want to implement queries for a databases you don't really care about the optimizations at the assembly level).

History: The first computers (electrical powered ones of course) were programmed only in assembly language. Why did this happen and why weren't programmed directly in Java? Because it needed a translator from Java language to the language that hardware knows and that translator(which, in fact, is the compiler more or less) takes incredible amount of memory and probably it was impossible to execute at that time for each program.

It was easy to think of a "for" loop statement but impossible to implement a translator that was executed each time when the loop was used.

After hardware evolved, compilers were implemented and high-level languages were created.

So, this relationship that you are looking to grasp is in fact just the continuous development of programming languages during the history of computers.

speedyxvs
  • 111
  • 1
  • 2
  • 9
0

I think the answer is: only if you consider that machine code = assembly code. High-level languages are basically compiled or interpreted. In the first case, the high-level language is translated into a set of machine code instructions, which depends on the type of the architecture. However, in most cases, there is a 1:1 correspondence between the assembly code and the machine code, but this is not always true (I suggest you to read this discussion Assembly code vs Machine code vs Object code?).

In the second case, interpreted languages are translated into a intermediate language which is then executed directly by the interpreter, skipping the machine code translation. So in this case, no assembly code is produced.

Community
  • 1
  • 1
Pablo R. Mier
  • 719
  • 1
  • 7
  • 13