3
\$\begingroup\$

In X86 Legacy boot loader prologue the first seven instructions preserve the state of the 8 general purpose and 6 segment registers. This is where they are displayed, right justified without leading zeros. Most often you'll see this kind of thing formulated as an ASCII string, then displayed with printf or maybe if INT 80 or SYSCALL under Linux.

The addresses are absolute and for those that may be interested in executing the code, you can PM me and I'll send the current version that can be assembled with NASM. Then breakpoints can be set and in my case I use BOCH's.

Here is the result; enter image description here SI is already pointing to the beginning of this string

'AXCXDXBXSPBPSIDIESDSCSSSFSGS'

 700  83C61B            add     si, 27     Point to last character
 703  FD                std                Do things in reverse
 704  6800B8            push    VIDEO_SEG
 707  07                pop     es
 708  BF9C09            mov     di, 0x99c  Row 15 Column 30 (zero indexed)
 70B  B90E00            mov     cx, 14     Values to be displayed
 70E  B407              mov     ah, 0x7    in low intensity white

At this point SP is pointing to the values preserved in proglogue.

enter image description here

that is why this instruction without the corresponding push works. After all, is said and done, SS:SP will be pointing to the far pointer back into the BIOS.

 710  5A                pop     dx      Retrieve registers value

Retain pointer to end of hex value (DI) and in case we change attribute which is in AH, preserve it too.

 711  57                push    di
 712  50                push    ax            AH = White
 713  09D2              or      dx, dx        Is value zero
 715  7502              jnz     719
 717  FEC4              inc     ah            AH = Grey
 719  E8BFFF            call    6db

Now registers mnemonic can be displayed in bright yellow

 71C  B40E              mov     ah, 14        Attribute bright yellow
 71E  AC                lodsb
 71F  AB                stosw
 720  AC                lodsb
 721  AB                stosw

 722  58                pop     ax            AH = White again
 723  5F                pop     di
 724  81EFA000          sub     di, 160       Bump pointer up one line
 728  FEC9              dec     cl          
 72A  740A              jz      736           Bail if done ZF=1

As soon as CL = 8, that means all the segment registers have been displayed and we can move over to the next column

 72C  80F908            cmp     cl, 8
 72F  75DF              jnz     710
 731  BF200A            mov     di,0xa20      DI = 5DC 
 734  EBDA              jmp     710

One thing I had considered here is adding 444H to DI instead, which in effect does exactly the same and then the left column would stay relative if the word at 709H was changed.

Finally, restore DF

 736  FC                cld

This is where DX will be right justified without leading spaces

 6DB  51                push    cx
 6DC  B105              mov     cl, 0x5

 Converts low nibble in AL to corresponding 0-1 or A-F
 6DE  88D0              mov     al, dl
 6E0  240F              and     al, 0xf
 6E2  3C0A              cmp     al, 0xa
 6E4  7202              jc      6e8
 6E6  0407              add     al, 0x7
 6E8  0430              add     al, 0x30
 6EA  AB                stosw
 6EB  FEC9              dec     cl

 Asserting DX here assures only one zero will be displayed for zero
 values in DX
 6ED  C1EA04            shr     dx, 4
 6F0  75EC              jnz     6de
 6F2  D1E1              shl     cx, 1
 6F4  29CF              sub     di, cx
 6F6  B82D0F            mov     ax, 0xf2d
 6F9  66AB              stosd                  Write bright white hyphen
 6FB  59                pop     cx
 6FC  C3                ret
\$\endgroup\$
  • \$\begingroup\$ Retrive, hypen, charcter - If these comments are actually in your code, you might want to fix the spelling, otherwise future maintainers will laugh at you... \$\endgroup\$ – David Wohlferd Jun 28 '17 at 22:43
  • \$\begingroup\$ Actually, sources have no comments at all. I'm experimenting with a different sort of regime through pages done with LibreOffice Impress. That being said, there's still no excuse for errors as there is spellcheck wich I usually use. \$\endgroup\$ – Shift_Left Jun 28 '17 at 23:39
  • \$\begingroup\$ Wich - I see what you did there... I'm not sure what you are doing with LibreOffice, but code (especially assembler, but any code) without comments sounds like a support nightmare. \$\endgroup\$ – David Wohlferd Jun 29 '17 at 0:08
  • \$\begingroup\$ @DavidWohlferd Wich reminds me to get a new keyboard, this one can't spell very well. Once I get into the kernel part of my code, I'll probably change things up quite a bit, as it's very likely GRUB will replace this, then maintainability will be much more important. The way binaries are written to fixed, flexible and removable media at the point is monumentally unorthodox. \$\endgroup\$ – Shift_Left Jun 29 '17 at 3:05
1
\$\begingroup\$

This is a very nice routine that totally succeeds in using a direction flag set to 1. I've seen others fail at this.

Some observations:

731  BF200A            mov     di,0xa20      DI = 5DC 

It's not clear what you mean with "DI = 5DC"

One thing I had considered here is adding 444H to DI instead, which in effect does exactly the same and then the left column would stay relative if the word at 709H was changed.

I would definitely choose adding 444h to DI in such a specially crafted routine. Relative addressing is so much more flexible to work with.

6F6  B82D0F            mov     ax, 0xf2d
6F9  66AB              stosd                  Write bright white hyphen

This is the only place where your code conceivably could fail. You store the dword from EAX without making sure the high word has any meaningful content. If the high word is empty you're in the clear, if not the screen will get disrupted.
Since modern BIOSes do use 32-bit registers, you can't be sure...

The shortest way to 'correct' this is:

mov     ax, 0x0F2D
stosw
dec     di
dec     di
\$\endgroup\$
  • \$\begingroup\$ Yes, the comment at 731H could have been clearer, but at that point, the routine had just finished displaying contents of ES register and the value in DX = 5DC before mov instruction. So 5DC + 444H = A20H. \$\endgroup\$ – Shift_Left Jul 2 '17 at 21:24
  • \$\begingroup\$ Right. It's one of those things then that one can only understand through recalculating. \$\endgroup\$ – Sep Roland Jul 2 '17 at 21:28
  • 2
    \$\begingroup\$ At 6F9 EAX = 00000F2D. It should be 07200F2D, but zero to video works just as well and the premise to the instruction was to decrement DI byte 4, ...but... not a very good habit to get into cause this sort of thing is very innocuous on the surface, and monumentally hard to trace when there is a problem. Case in point, I just tried to trace back and couldn't find the place where high order bits of EAX were zeroed. Not a very good commentary, just having finished the app a couple of days ago. \$\endgroup\$ – Shift_Left Jul 2 '17 at 21:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.