I need to use a pointer to an array and put the third value in ax. My solution:
mov bx, [chrs_ptr]
add bx, 2
mov ax,[bx]
But I couldn't figure out why mov ax, [[chrs_ptr] + 2]
gives me the pointer value.
Because assembler is different to most of the other programming languages.
Most of the PLs are aiming for generalization and universal usage of their syntax, as building blocks, to compose expressions way beyond trivial syntax of particular single feature.
Assembler is "human readable" mnemonics for the machine code of the particular processor. I.e. the instructions available in particular assembler are not designed by the assembler creator (mostly), but they are defined by the HW engineers designing the CPU itself. So instructions of your assembler depends on the target processor, and they are like 1:1 mapped from the source form into actual CPU instruction (with few exceptions, some assemblers actually do have support for few pseudo-instructions, but generally it's 1:1).
And thus emu8086 emulating 8086 CPU (and also few following ones from that family, 80286 and maybe even 80386? I'm never sure what emu8086 supports, as I don't use it) has only the Intel instructions designed in those processors.
There is for example MOV r16,r/m16
instruction in 16 bit real mode, which you are using at line mov ax,[bx]
, but there is no instruction like MOV r16,memory-by-indirection-from-other-memory with +2 offset
, so when programming in assembly, you are expected to know the target instruction set, and write your solution with instructions which are available.
You may question why some instruction does only "that", but not also "this", which may seem to you like obvious thing to do, but most of the times the ISA (Instruction Set Architecture) tend to be very good compromise between what is enough to write practical code with, and what is practical to design in the circuit, with reasonable power consumption and timing features per single machine cycle, and also with early CPUs what was practical to design by hand, and validate its correctness in head.
Your proposal of mov ax,[[chrs_ptr]+2]
would require two reads of memory within single instruction execution, and reading of memory is far from trivial task (often stalls the CPU for multiple machine cycles, until the memory chip is ready to deliver the value from particular cell), so you would immediately raise the complexity of CPU circuitry design a lot. Like a lot.
Or maybe you may question why the assembler doesn't break it down into the three native instructions of processor for you.
But usually when you need assembler, you need actually that 1:1 mapping of assembler source instruction to native machine code instruction of the target CPU. Because if you don't need that, then why assembler at all, there are many higher level languages, which give you still enough low-level control over the machine, but lifts up this kind of micro management of everything, like C or C++. So there's very little incentive to enrich the assembler "language" itself, and usually when you see some effort like this, it ends up as just another programming language, too tainted to be used in place of actual assembler, when you really need to write those few CPU instructions by hand, and tune it down to every single byte.