• ss and lea on 8086

    From Paul Edwards@21:1/5 to All on Sat Jun 24 00:35:07 2023
    I have the following code:

    void dumplong(unsigned long x)
    {
    static int y;
    char *z = "0123456789abcdef";
    char buf[9];

    y = 0;
    buf[0] = 'P';
    buf[1] = 'P';
    buf[2] = 'P';
    buf[3] = 'P';
    buf[3-y] = 'R';
    buf[4] = 'P';
    buf[4+y] = 'S';
    buf[5] = 'P';
    buf[6] = 'P';
    buf[7] = 'P';

    And Visual C++ 1.52 is generating this assembler:

    ; x = 0006
    ; buf = fff4
    ; z = fff0
    ; Line 5836
    _dumplong:
    push bp
    mov bp,sp
    sub sp,OFFSET L04604
    ; Line 5837
    ; Line 5838
    mov ax,OFFSET L03767
    mov dx,ds
    mov WORD PTR -16[bp],ax
    mov WORD PTR -14[bp],dx
    ; Line 5839
    ; Line 5841
    mov WORD PTR ?y@?1??dumplong@@9@9,OFFSET 0
    ; Line 5842
    mov BYTE PTR -12[bp],OFFSET 80
    ; Line 5843
    mov BYTE PTR -11[bp],OFFSET 80
    ; Line 5844
    mov BYTE PTR -10[bp],OFFSET 80
    ; Line 5845
    mov BYTE PTR -9[bp],OFFSET 80
    ; Line 5846
    mov ax,OFFSET 3
    sub ax,WORD PTR ?y@?1??dumplong@@9@9
    lea bx,WORD PTR -12[bp]
    add bx,ax
    mov BYTE PTR ss:[bx],OFFSET 82
    ; Line 5847
    mov BYTE PTR -8[bp],OFFSET 80
    ; Line 5848
    mov ax,WORD PTR ?y@?1??dumplong@@9@9
    add ax,OFFSET 4
    lea bx,WORD PTR -12[bp]
    add bx,ax
    mov BYTE PTR ss:[bx],OFFSET 83
    ; Line 5849
    mov BYTE PTR -7[bp],OFFSET 80
    ; Line 5850
    mov BYTE PTR -6[bp],OFFSET 80
    ; Line 5851
    mov BYTE PTR -5[bp],OFFSET 80


    I've been looking at this for hours.

    Unless I've somehow stuffed up the test, this data is
    all being set to 'P'.

    Regardless of whether I do a subtraction or an addition
    (of 0), the data is not changed.

    I do have one unusual thing happening - my "ss" is set
    to something a long way away from "ds" because this
    is the PDOS/86 kernel and I didn't create a separate
    stack for the kernel, I just reused the one from the
    bootloader.

    But I don't see any reason for that effect. The lea shouldn't
    care, and the ss is explicitly used.

    It is not easy to debug this because this IS what I use
    to debug!

    Original code, before I started debugging, is here:

    https://sourceforge.net/p/pdos/gitcode/ci/master/tree/src/pdos.c


    Any ideas?

    Thanks. Paul.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tavis Ormandy@21:1/5 to Paul Edwards on Sat Jun 24 14:52:17 2023
    [I've rearranged your code to intermix code with assembly]

    On 2023-06-24, Paul Edwards wrote:
    void dumplong(unsigned long x)
    _dumplong:
    push bp
    mov bp,sp

    Note: Making space for locals, not an offset.

    char buf[9];
    sub sp,OFFSET L04604

    Note: Loading far pointer to "0123..." into z

    char *z = "0123456789abcdef";
    mov ax,OFFSET L03767
    mov dx,ds
    mov WORD PTR -16[bp],ax
    mov WORD PTR -14[bp],dx

    y = 0;
    mov WORD PTR ?y@?1??dumplong@@9@9,OFFSET 0

    buf[0] = 'P';
    buf[1] = 'P';
    buf[2] = 'P';
    buf[3] = 'P';
    mov BYTE PTR -12[bp],OFFSET 80
    mov BYTE PTR -11[bp],OFFSET 80
    mov BYTE PTR -10[bp],OFFSET 80
    mov BYTE PTR -9[bp],OFFSET 80

    buf[3-y] = 'R';
    mov ax,OFFSET 3
    sub ax,WORD PTR ?y@?1??dumplong@@9@9
    lea bx,WORD PTR -12[bp]
    add bx,ax
    mov BYTE PTR ss:[bx],OFFSET 82

    buf[4] = 'P';
    mov BYTE PTR -8[bp],OFFSET 80

    buf[4+y] = 'S';
    mov ax,WORD PTR ?y@?1??dumplong@@9@9
    add ax,OFFSET 4
    lea bx,WORD PTR -12[bp]
    add bx,ax
    mov BYTE PTR ss:[bx],OFFSET 83

    buf[5] = 'P';
    buf[6] = 'P';
    buf[7] = 'P';
    mov BYTE PTR -7[bp],OFFSET 80
    mov BYTE PTR -6[bp],OFFSET 80
    mov BYTE PTR -5[bp],OFFSET 80


    I've been looking at this for hours.

    Unless I've somehow stuffed up the test, this data is
    all being set to 'P'.

    I don't follow, you set buf[3] to 'R' (shows as OFFSET 82 in the
    disassembly) and buf[4] to 'S'.


    Regardless of whether I do a subtraction or an addition
    (of 0), the data is not changed.

    You don't really explain what problem you're seeing, here is a
    line-by-line:

    buf[3-y] = 'R';

    mov ax,OFFSET 3 ; ax = 3
    sub ax,WORD PTR ?y@?1??dumplong@@9@9 ; ax -= y

    So now ax is 3-y

    lea bx,WORD PTR -12[bp] ; bx = &buf[0]
    add bx,ax ; bx += ax

    So now bx is &buf[3-y]

    mov BYTE PTR ss:[bx],OFFSET 82 ; *bx = 'R'

    Set *bx = 'R', isn't that correct?

    Tavis.

    --
    _o) $ lynx lock.cmpxchg8b.com
    /\\ _o) _o) $ finger taviso@sdf.org
    _\_V _( ) _( ) @taviso

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tavis Ormandy@21:1/5 to Tavis Ormandy on Sat Jun 24 15:39:49 2023
    On 2023-06-24, Tavis Ormandy wrote:
    I've been looking at this for hours.

    Unless I've somehow stuffed up the test, this data is
    all being set to 'P'.

    I don't follow, you set buf[3] to 'R' (shows as OFFSET 82 in the
    disassembly) and buf[4] to 'S'.

    Ah, as soon as I hit send I realized what you were saying - you don't
    think there's a miscompilation. You're saying the write to ss:[bx] isn't working, and you suspect the lea is to blame?

    It seems correct to me, the base should be irrelevant and the actual
    write has the correct override. I don't know what could be causing
    that!

    Tavis.


    --
    _o) $ lynx lock.cmpxchg8b.com
    /\\ _o) _o) $ finger taviso@sdf.org
    _\_V _( ) _( ) @taviso

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to Tavis Ormandy on Sat Jun 24 17:44:20 2023
    On Saturday, June 24, 2023 at 11:55:00 PM UTC+8, Tavis Ormandy wrote:

    Hi Tavis. Thanks for your reply.

    Ah, as soon as I hit send I realized what you were saying - you don't
    think there's a miscompilation. You're saying the write to ss:[bx] isn't working, and you suspect the lea is to blame?

    Correct.

    It seems correct to me, the base should be irrelevant and the actual
    write has the correct override. I don't know what could be causing
    that!

    Ok, thanks for the analysis. I thought I might have been doing
    something that was fundamentally and obviously wrong by
    having ss != ds, and the lea showed that up.

    A piece of information I forgot to give was that making the
    buffer static (so referenced by ds instead of ss), made the
    problem go away.

    So now that no-one is aware of anything that is obviously
    wrong, I thought of a way of getting more information by
    creating a second set of dump functions, one of them using
    "static".

    Here is what I see when I use the static version, and the
    new debug shown below, and Bochs instead of qemu
    so that I can capture a screen:

    Booting from Floppy...
    5bb3351253525050PPRSPPPP

    which is:

    5bb3:3512 (data section of PDOS)

    53525050 (SRPP - first 4 bytes treated as a 32-bit long)

    PPRSPPPP (the expected buffer printing correctly)


    And here is what I see when the buffer is on the stack:


    Booting from Floppy...
    0a6bfed850505050PPPPPPPP

    which is:

    0a6b:fed8

    the stack area from the loader:

    0A6B:0 DGROUP (from pload.map)

    50505050 (no sign of my 52 and 53)

    PPPPPPPP (and this is not what I want)


    Any ideas? Current debug code below.

    I really am expecting that the "lea" gives an address
    relative to ds rather than ss. Although I read that
    lea is a simple arithmetic operation, which would
    mean it is unrelated to either the ds or ss value.
    But that doesn't sound right to me. I think it needs
    to be relative to something by definition, and I
    would hope that a bp reference is relative to ss.

    Also note that I changed this so that it is within
    the first 4 bytes so that a "long" can see both
    bytes.

    + buf[2-y] = 'R';
    + buf[3] = 'P';
    + buf[3+y] = 'S';

    Thanks. Paul.



    diff --git a/src/pdos.c b/src/pdos.c
    index 0459c3ab..c35bc927 100644
    --- a/src/pdos.c
    +++ b/src/pdos.c
    @@ -885,6 +885,10 @@ void pdosRun(void)
    #ifdef __32BIT__
    printf("Welcome to PDOS/386 (aka PD-Windows)\n");
    #else
    +/*dumpbuf("XY", 2);*/
    +dumplong((long)5);
    +for (;;) ;
    +printf("Z");
    printf("Welcome to PDOS/86\n");
    #endif
    PosSetVideoAttribute(0x7);
    @@ -5828,17 +5832,71 @@ static void accessDisk(int drive)
    return;
    }

    -void dumplong(unsigned long x)
    +void dumpbuf2(unsigned char *buf, int len);
    +
    +void dumplong2(unsigned long x)
    {
    - int y;
    + static int y;
    char *z = "0123456789abcdef";
    - char buf[9];
    + static char buf[9];
    +
    + for (y = 0; y < 8; y++)
    + {
    + buf[7 - y] = z[x & 0x0f];
    + x /= 16;
    + }
    + buf[8] = '\0';
    + dumpbuf2(buf, 8);
    + return;
    +}
    +
    +void dumpbuf2(unsigned char *buf, int len)
    +{
    + int x;
    +
    + for (x = 0; x < len; x++)
    + {
    + pdosWriteText(buf[x]);
    + }
    + return;
    +}

    +void dumplong(unsigned long x)
    +{
    + static int y;
    +
  • From Paul Edwards@21:1/5 to All on Sat Jun 24 20:26:19 2023
    Next thing I tried was putting the generated assembler
    into one of my own assembler files. It didn't directly
    assemble, so I modified it like this:

    public dumplong3
    ; x = 0006
    ; buf = fffa
    ; Line 5910
    dumplong3:
    push bp
    mov bp,sp
    ; sub sp,OFFSET L04632
    sub sp,06H
    ; Line 5911
    ; Line 5912
    ; Line 5914
    mov BYTE PTR [bp-6],80
    ; Line 5915
    mov BYTE PTR [bp-5],OFFSET 80
    ; Line 5916
    mov BYTE PTR [bp-4],OFFSET 80
    ; Line 5917
    mov ax,OFFSET 2
    sub ax,WORD PTR y
    lea bx,WORD PTR [bp-6]
    add bx,ax
    mov BYTE PTR ss:[bx],OFFSET 82
    ; Line 5918
    mov BYTE PTR [bp-3],OFFSET 80
    ; Line 5919
    mov ax,WORD PTR y
    add ax,OFFSET 3
    lea bx,WORD PTR [bp-6]
    add bx,ax
    mov BYTE PTR ss:[bx],OFFSET 83
    ; Line 5920
    mov ax,OFFSET 4
    push ax
    lea ax,WORD PTR [bp-6]
    mov dx,ss
    push dx
    push ax
    call FAR PTR dumpbuf
    add sp,OFFSET 6
    ; Line 5921
    ; Line 5922
    ; Line 5922
    L03803:
    mov sp,bp
    pop bp
    retf
    int 3
    int 3
    int 3
    int 3
    int 3
    int 3
    int 3

    .data
    y dw 0


    The int 3 is an eyecatcher.

    The most suspicious change I made was this:

    ; sub sp,OFFSET L04632
    sub sp,06H

    That label doesn't actually appear in the generated assembler.

    Anyway, the handwritten assembler works!

    So lea is fundamentally fine.

    I then went looking to match the machine code. Here is
    the handwritten assembler:

    558B EC83EC06 ....XX.L.!U....
    000150 C646FA50 C646FB50 C646FC50 B802002B .F.P.F.P.F.P...+
    000160 0600008D 5EFA03D8 36C60752 C646FD50 ....^...6..R.F.P
    000170 A1000083 C0038D5E FA03D836 C60753B8 .......^...6..S.
    000180 0400508D 46FA8CD2 52509A00 00000083 ..P.F...RP......
    000190 C4068BE5 5DCB

    And here is the C code:

    55 8BEC81EC 0600C646 .......U.......F
    013310 FA50C646 FB50C646 FC50B802 002B0600 .P.F.P.F.P...+..
    013320 008D5EFA 03D8C607 52C646FD 50A10000 ..^.....R.F.P...
    013330 0503008D 5EFA03D8 C60753B8 0400508D ....^.....S...P.
    013340 46FA8CD2 52509A00 00000083 C4068BE5 F...RP..........
    013350 5DCB

    The first thing I noticed was that the x'83' (subtract):

    http://sparksandflames.com/files/x86InstructionChart.html

    is strangely an "add" ('x81') in C, which isn't going to work.

    I tried zapping the add into a subtract, on the assumption
    that it was a compiler bug, since I think I am using 1.52
    but I think there is a 1.52C available via patch.

    But the C code still didn't work.

    I suspect that the add is correct, and that label has a
    value of -6 in it, and so it is meant to work, and may
    explain why the number of bytes of code is different
    between the two, as it is perhaps a reference rather
    than an immediate.

    Still investigating.

    BFN. Paul.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to Paul Edwards on Sat Jun 24 22:24:34 2023
    On Sunday, June 25, 2023 at 11:40:47 AM UTC+8, Paul Edwards wrote:

    I tried zapping the add into a subtract, on the assumption
    that it was a compiler bug, since I think I am using 1.52
    but I think there is a 1.52C available via patch.

    I appear to have 1.52C as per the name of the CD,
    even though the label says 1.52.

    Anyway, I believe I have found a compiler bug:

    /*

    This program demonstrates a presumed bug in Visual C++ 1.52C

    When compiled with:

    cl -Fa -c -AH -Ox -f foo.c

    it says it generated:

    add bx,ax
    mov BYTE PTR ss:[bx],OFFSET 88

    but looking at the object code shows:

    03D8 C60758

    Manually assembling with masm shows:

    03 D8 add bx,ax
    36: C6 07 58 mov BYTE PTR ss:[bx],OFFSET 88

    the '36' is the SS override. That is missing from the object code.
    This only becomes a problem if ds and ss are not the same. Normally
    they are the same.

    */
    void foo(int y)
    {
    char buf[4];

    buf[3-y] = 'X';
    bar(buf);
    return;
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)