• x64 address indexed by 32-bit address

    From Paul Edwards@21:1/5 to All on Fri Jan 19 21:42:14 2024
    Hi.

    I am using a slightly modified GCC 3.2.3
    to generate x64 code, and using PDPCLIB
    and running under Linux x64.

    I don't trust either (my) PDPCLIB or my
    modified GCC 3.2.3

    Assuming PDPCLIB is behaving correctly,
    it is showing that the stack is above
    4 GiB. It seems to be a 48-bit address.

    The executable appears to be loaded in
    low memory - way below 2 GiB.

    kerravon@kerravon-pc:~/scratch/eee/pdos/pdpclib$ ./pdptest ab def
    welcome to pdptest
    main function is at 00401334
    allocating 10 bytes
    m1 is 004087A8
    allocating 20 bytes
    m2 is 00408828
    stack is around 7FFC36A1053C
    printing arguments
    argc = 3
    arg 0 is <./pdptest>
    arg 1 is <ab>
    arg 2 is <def>
    kerravon@kerravon-pc:~/scratch/eee/pdos/pdpclib$


    Now I have this code:

    printf("argv[0] is %p %s\n", argv[0], argv[0]);
    printf("len is %d\n", (int)strlen(argv[0]));
    p = argv[0] + strlen (argv[0]);
    printf("p is %p\n", p);
    printf("p as string is %s\n", p);
    printf("p current is %x\n", p[0]);
    printf("as negative is %x\n", p[-1]);


    which is generating (for that last line):

    LM1873:
    movl $4294967295, %eax
    addq -64(%rbp), %rax
    movsbl (%rax),%esi
    movl $LC445, %edi
    movb $0, %al
    call _printf

    That first instruction - the movl - has
    negative 1 as an unsigned value. I tried
    manually changing the generated assembler
    to $-1 but the result appears to be the
    same (I may have stuffed up the test).

    And it crashes:

    kerravon@kerravon-pc:~/scratch/eee/gcc/gcc$ ./gcc-new.exe
    argv[0] is 7FFC8DC50294 ./gcc-new.exe
    len is 13
    p is 7FFC8DC502A1
    p as string is
    p current is 0
    Segmentation fault (core dumped)
    kerravon@kerravon-pc:~/scratch/eee/gcc/gcc$


    I suspect what is happening is that it is
    adding the entire value of eax as an unsigned
    32-bit value to the 64-bit address and so the
    address is being offset by nearly 4 GiB
    instead of being offset by 1 byte.

    GCC 3.2.3 was used to build systems I believe,
    so it "must" work in some circumstances.

    Any idea how this was meant to work?

    Thanks. Paul.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to Paul Edwards on Tue Feb 13 14:17:18 2024
    On 19/01/24 21:42, Paul Edwards wrote:

    LM1873:
    movl $4294967295, %eax
    addq -64(%rbp), %rax
    movsbl (%rax),%esi
    movl $LC445, %edi
    movb $0, %al
    call _printf

    This has now been resolved. I wasn't building my
    modified gcc 3.2.3 properly, so it thought that
    size_t was 32 bits instead of 64 and was making
    it unsigned.

    Now I am getting working code:

    D:\devel\gcc\gcc>type foo.s
    .file "foo.c"
    .text
    .p2align 2,,3
    .globl foo
    foo:
    .LFB1:
    movsbl -1(%rcx),%eax
    ret
    .LFE1:

    D:\devel\gcc\gcc>


    (rcx is because one of my modifications is to use
    Win64 function call convention)

    BFN. Paul.

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