Page 2 of 2

Re: GCC fails to reserve space for local variables

Posted: Tue Jan 01, 2013 2:25 pm
by Owen
rdos wrote:The problem with the above code, is that when SYSCALL5 is used multiple times in the same procedure, GCC will complain about already defined variables. That's one of the alternatives I tried and discarded. I was able to hide it as a "scope" variable by putting {} around the declaration, but that can also have unwanted side-effects. I was not able to place the whole inline within a private scope.
The do { } while(0) is a standard idiom to introduce a new scope without side effects. I find it hard to believe you've never encountered it.
rdos wrote:Additionally, it seems like GCC can remove these assignments in the optimization process, and it was not possible to use volatile with register to make GCC always keep these asignments.
The assignments have effect only when the variables are passed into an asm() statement with the "r" specifier, for the duration of that statement; but they do work, as is attested by the fact that Linux and glibc work reliably; they use these extensions extensively

Re: GCC fails to reserve space for local variables

Posted: Tue Jan 01, 2013 3:57 pm
by rdos
The problem is that the syntax is adapted for Linux usage, and poorly documented.

Resulting code (which seem to be correct):

Code: Select all

00000180e00000b0 <main>:
 180e00000b0:   41 56                   push   %r14
 180e00000b2:   48 8d 3d ff 01 00 00    lea    0x1ff(%rip),%rdi        # ffffffffe00002b8 <_end+0xfffffe7ebffff900>
 180e00000b9:   41 be 7b 00 00 00       mov    $0x7b,%r14d
 180e00000bf:   45 31 c0                xor    %r8d,%r8d
 180e00000c2:   41 54                   push   %r12
 180e00000c4:   41 bc 09 00 00 00       mov    $0x9,%r12d
 180e00000ca:   53                      push   %rbx
 180e00000cb:   0f 05                   syscall
 180e00000cd:   72 06                   jb     180e00000d5 <main+0x25>
 180e00000cf:   48 0f b7 c3             movzwq %bx,%rax
 180e00000d3:   eb 03                   jmp    180e00000d8 <main+0x28>
 180e00000d5:   48 31 c0                xor    %rax,%rax
 180e00000d8:   41 89 c2                mov    %eax,%r10d
 180e00000db:   85 c0                   test   %eax,%eax
 180e00000dd:   74 2a                   je     180e0000109 <main+0x59>
 180e00000df:   41 be 86 00 00 00       mov    $0x86,%r14d
 180e00000e5:   48 8b 3d 1c ff ff 3f    mov    0x3fffff1c(%rip),%rdi        # 20000008 <usergate_entries+0x1ffffeb4>
 180e00000ec:   41 b8 f4 01 00 00       mov    $0x1f4,%r8d
 180e00000f2:   66 41 bc f4 01          mov    $0x1f4,%r12w
 180e00000f7:   0f 05                   syscall
 180e00000f9:   73 03                   jae    180e00000fe <main+0x4e>
 180e00000fb:   48 31 c0                xor    %rax,%rax
 180e00000fe:   41 be 7d 00 00 00       mov    $0x7d,%r14d
 180e0000104:   44 89 d3                mov    %r10d,%ebx
 180e0000107:   0f 05                   syscall
 180e0000109:   5b                      pop    %rbx
 180e000010a:   41 5c                   pop    %r12
 180e000010c:   31 c0                   xor    %eax,%eax
 180e000010e:   41 5e                   pop    %r14
 180e0000110:   c3                      retq
Source:

Code: Select all

#define RdosClobberSyscall \
  asm volatile ( \
    "\n\t" \
     : : : "rcx", "r9", "r11", "r14" \
   );

#define RdosClobberSyscallRdi \
  asm volatile ( \
    "\n\t" \
     : : : "rcx", "rdi", "r9", "r11", "r14" \
   );

#define RdosUserGateEdiEcxPar0RetEbx(nr, rdi, rcx, size, res) do { \
  register int _id asm("r14") = nr; \
  register typeof(rdi) _rdi asm("rdi") = (rdi); \
  register typeof(rcx) _rcx asm("r8") = (rcx); \
  register typeof(size) _size asm("r12") = (size); \
  asm volatile ( \
    "syscall\n\t" \
    "jc 1f\n\t" \
    "movzx %%bx,%%rax\n\t" \
    "jmp 2f\n\t" \
    "1: \n\t" \
    "xorq %%rax,%%rax\n\t" \
    "2: \n\t" \
    : "=a" (res) : "r" (_id), "r" (_rdi), "r" (_rcx), "r" (_size) : "rbx", "rdx", "rsi" \
  ); \
  RdosClobberSyscallRdi; \
} while(0);

#define RdosUserGateEbxEdiEcxParRetEax(nr, rbx, rdi, rcx, res) do { \
  register int _id asm("r14") = nr; \
  register typeof(rdi) _rdi asm("rdi") = (rdi); \
  register typeof(rcx) _rcx asm("r8") = (rcx); \
  register typeof(rcx) _size asm("r12") = (rcx); \
  asm volatile ( \
    "syscall\n\t" \
    "jnc 1f\n\t" \
    "xorq %%rax,%%rax\n\t" \
    "1: \n\t" \
    : "=a" (res) :  "r" (_id), "r" (_rdi), "r" (_rcx), "r" (_size) : "rdx", "rsi" \
  ); \
  RdosClobberSyscallRdi; \
} while(0);

#define RdosUserGateEbx(nr, rbx) do { \
  register int _id asm("r14") = nr; \
  register typeof(rbx) _rbx asm("rbx") = (rbx); \
  asm volatile ( \
    "syscall\n\t" \
    : : "r" (_id), "r" (_rbx) : "rax", "rdx", "rsi", "rdi" \
  ); \
  RdosClobberSyscall; \
} while(0);

RDOSAPI int RdosOpenFile(const char *FileName, char Access)
{
    int res;
    int size = strlen(FileName) + 1;
    RdosUserGateEdiEcxPar0RetEbx(usergate_open_file, FileName, Access, size, res);
    return res;
}

RDOSAPI int RdosReadFile(int Handle, void *Buf, int Size)
{
    int res;
    RdosUserGateEbxEdiEcxParRetEax(usergate_read_file, Handle, Buf, Size, res);
    return res;
}

RDOSAPI RdosCloseFile(int Handle)
{
    RdosUserGateEbx(usergate_close_file, Handle);
}
I'm not sure about the typeof definitions. A better idea is probably to define these as "int" instead. The assembler code has one of the loads in a word format, which would be wrong by itself (but is correct since the higher half is cleared before in the code).

Re: GCC fails to reserve space for local variables

Posted: Tue Jan 01, 2013 9:24 pm
by bluemoon
I suggest to put the clobber list within the same assembly block:

Code: Select all

#define RdosSyscall_ClobberBasic "rcx", "r9", "r11", "r14"
#define RdosSyscall_ClobberRdi RdosSyscall_ClobberBasic, "rdi"

asm volatile ( \
    "syscall\n\t" \
    : : "r" (_id), "r" (_rbx) : "rax", "rdx", "rsi", "rdi" \
    : RdosSyscall_ClobberBasic ); \

Re: GCC fails to reserve space for local variables

Posted: Wed Jan 02, 2013 4:39 am
by rdos
bluemoon wrote:I suggest to put the clobber list within the same assembly block:

Code: Select all

#define RdosSyscall_ClobberBasic "rcx", "r9", "r11", "r14"
#define RdosSyscall_ClobberRdi RdosSyscall_ClobberBasic, "rdi"

asm volatile ( \
    "syscall\n\t" \
    : : "r" (_id), "r" (_rbx) : "rax", "rdx", "rsi", "rdi" \
    : RdosSyscall_ClobberBasic ); \
Probably a good idea, however it doesn't work for rdi as it is defined as an input parameter.

Re: GCC fails to reserve space for local variables

Posted: Wed Jan 02, 2013 12:37 pm
by Owen
Use the "+r" specifier in the output parameter block. This will cause GCC to treat it as an in/out parameter.

That portion of the inline assembly syntax which I do agree is truly annoying.