Why is the CALL instruction adding to the stack pointer?

86 Views Asked by At

For some reason when I run this code in bochs the value of BX at the start of the PRINTCHAR procedure resolves to 0x1002. How can this be? Doesn't the CALL procedure decrement SP and push the IP onto it, why has 2 been added to SP instead of subtracted? The register dump follows after the code listings. Thank you for reading.

[BITS 16]
[ORG 0x7c00]
START:
MOV     AX,     0x0FA0
MOV     SS,     AX  
MOV     AX,     0x1000
MOV     SP,     AX
MOV     BP,     AX
MOV     AX,     0x1F40
MOV     DS,     AX
MOV     AX,     0x2EE0
MOV     ES,     AX
STI
CALL PRINTCHAR
CLI
HLT
PRINTCHAR:
MOV     BX,     SP
HLT

Register Dump

00014725614i[CPU0  ] WARNING: HLT instruction with IF=0!
04272480000p[WINGUI] >>PANIC<< POWER button turned off.
04272480000i[CPU0  ] CPU is in real mode (halted)
04272480000i[CPU0  ] CS.mode = 16 bit
04272480000i[CPU0  ] SS.mode = 16 bit
04272480000i[CPU0  ] EFER   = 0x00000000
04272480000i[CPU0  ] | EAX=00000e00  EBX=00001002  ECX=00090000  EDX=00000000
04272480000i[CPU0  ] | ESP=00001000  EBP=00001000  ESI=000e0000  EDI=0000ffac
04272480000i[CPU0  ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
04272480000i[CPU0  ] | SEG sltr(index|ti|rpl)     base    limit G D
04272480000i[CPU0  ] |  CS:0000( 0004| 0|  0) 00000000 0000ffff 0 0
04272480000i[CPU0  ] |  DS:1f40( 0005| 0|  0) 0001f400 0000ffff 0 0
04272480000i[CPU0  ] |  SS:0fa0( 0005| 0|  0) 0000fa00 0000ffff 0 0
04272480000i[CPU0  ] |  ES:2ee0( 0005| 0|  0) 0002ee00 0000ffff 0 0
04272480000i[CPU0  ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
04272480000i[CPU0  ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
04272480000i[CPU0  ] | EIP=00007c1c (00007c1c)
04272480000i[CPU0  ] | CR0=0x60000010 CR2=0x00000000
04272480000i[CPU0  ] | CR3=0x00000000 CR4=0x00000000
04272480000i[CPU0  ] 0x0000000000007c1c>> mov bx, sp : 89E3
2

There are 2 best solutions below

0
Nassau On

Ms Debug shows good values ;) Maybe something is wrong with Bochs. enter image description here

0
Martin Rosenau On

Bytes in RAM are never "empty" (but they contain some value) and most values are interpreted by the CPU as instructions.

For this reason, the memory after the end of a program contains "random" instructions.

Example: If you write the following program:

mov ax, 1
mov bx, 2

... then the memory may contain the following instructions:

# Instructions of your program
mov ax, 1
mov bx, 2
# Random instructions after your program
xor dx, ax
mov di, si
add dx, [di]
...

And if your program does not "end" propperly (e.g. you don't have an instruction that stops your program when it reaches the end), the CPU will execute those "random" instructions.

In the output of Bochs you can also see that the ax register has been modified (from 0x2EE0 to 0xE00).

The most probable reason for this is that the random instructions after your code caused the register changes - maybe these instructions look like this:

# Last part of your program
PRINTCHAR:
MOV     BX,     SP
HLT

# Random instructions after your program
MOV     BX,     0x1002
MOV     AX,     0xE00
RET