1

I am trying to get the current time using syscalls and inline assembly in FreeBSD 5.2.1 32-bit.

My problem is that I struggle to pass needed structs as arguments to the function resulting in error:

error: impossible register constraint in `asm'

My current code which I am actually running looks like this:

#include <sys/syscall.h>
#include <sys/time.h>

struct timeval val;
struct timezone zone;

zone.tz_minuteswest = 0;
zone.tz_dsttime = 0;

long ret;

asm("int $0x80"
    : "=a"(ret)
    : "0"(SYS_gettimeofday), "D"(val), "S"(zone)
    : "memory");

I was trying to get inspired be these 2 examples, but I couldn't make it work link1, link2.

Only other thing that I managed was, calling syscalls such as getuid, because it requires no arguments and directly returns value.

I am open to using clock_gettime syscall, but other than that I really want to get it using inline assembly syscalls.

mikro45
  • 63
  • 1
  • 1
  • 9
  • 2
    32-bit mode with `int $0x80`? Doesn't FreeBSD pass syscall args on the stack in 32-bit mode? – Peter Cordes May 12 '20 at 21:23
  • Forgot to specify, but my FreeBSD is 32-bit (i386). – mikro45 May 12 '20 at 21:30
  • 1
    The reason you're getting the particular error you are is that `struct timezone` contains two `int`s, which means `zone` is too big to fit in `esi`. I assume that `time_t` and `suseconds_t` are also `int`s or bigger, which would mean that `val` is similarly too big to fit in `edi`. The underlying problem is that that's not how you pass parameters to syscalls in the x86 FreeBSD calling convention. – Joseph Sible-Reinstate Monica May 12 '20 at 21:35
  • @MichaelPetch: Are you implying that `int $0x80` from 64-bit user-space under FreeBSD uses register args like the normal `syscall` ABI? – Peter Cordes May 12 '20 at 21:35
  • Does this answer your question? [What are the calling conventions for UNIX & Linux system calls on i386 and x86-64](https://stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-i386-and-x86-6) – Joseph Sible-Reinstate Monica May 12 '20 at 21:35
  • 1
    @PeterCordes I was saying yes it uses the stack for arguments in 32-bit code, and that it requires an additional dummy parameter. It does not take values in registers in 32-bit code. – Michael Petch May 12 '20 at 21:36
  • @MichaelPetch: Ok, so when you wrote *Question here is if this is 32-bit or 64-bit code* you just meant whether the right fix was sort of like this with `"D"(&val)` and `syscall`, or something totally different with stack stuff. Not that `int $0x80` could almost work in 64-bit mode if you gave it pointer args instead of values. – Peter Cordes May 12 '20 at 21:37
  • @JosephSible-ReinstateMonica: This is FreeBSD and 32-bit code has some differences over Linux, answers related to 32-bit system calls for FreeBSD would be similar to similar 32-bit MacOS related question – Michael Petch May 12 '20 at 21:38
  • @MichaelPetch The dupe target I linked has a "x86-32 [Free|Open|Net|DragonFly]BSD UNIX System Call convention" section. – Joseph Sible-Reinstate Monica May 12 '20 at 21:39
  • @MichaelPetch: [What are the calling conventions for UNIX & Linux system calls on i386 and x86-64](https://stackoverflow.com/q/2535989) does have a section on 32-bit *BSD, although it's not a very *good* duplicate because that's kinda buried and it doesn't show how to use it from inline asm, or address the bug in the OP's code (value vs. pointer). It's missing anything about x86-64 *BSD / MacOS, unfortunately. – Peter Cordes May 12 '20 at 21:40
  • My gcc version is 3.3.3. I will try to follow up to other comments as I read them thoroughly. – mikro45 May 12 '20 at 21:50
  • 3
    I suppose there's a good reason why you're using versions that are nearly old enough to vote...? – Nate Eldredge May 12 '20 at 21:56

1 Answers1

1

Thanks for all the help in the comments.

Problems resolved were:

  • pass pointers instead of values
  • use correct convention for passing arguments (x86-32 FreeBSD)

Code:

#include <sys/syscall.h>
#include <sys/time.h>

struct timeval val;
struct timezone zone;

zone.tz_minuteswest = 0;
zone.tz_dsttime = 0;

unsigned int ret;

asm volatile(
  "push %3;"
  "push %2;"
  "push $0;"
  "int $0x80"
  "add $12, %%esp"
  : "=a"(ret)
  : "a"(SYS_gettimeofday), "r"(&val), "r"(&zone)
  : "memory");

E: Optimized code based on the comment suggestions.

mikro45
  • 63
  • 1
  • 1
  • 9
  • You're missing a memory clobber ([How can I indicate that the memory \*pointed\* to by an inline ASM argument may be used?](https://stackoverflow.com/q/56432259)). Also, you forgot to `add $12, %esp` to clean up the stack. An inline asm statement must leave ESP unmodified. Plus you can ask for the call number in `"a"` in the first place, no need to `mov` it. – Peter Cordes May 12 '20 at 22:27