0

I need to write inline assembly code in C in format like this:

asm(
    "mov %1, %%ax\n\t"
    "inc %%ax\n"
    "mov %%ax, %0"
    :"=r" (a)
    :"r" (a)
    );

This code in asm() need to do break and assign current time to variables declared in C outside of asm() func. I have tried to write my own code but I even struggle to do break instruction... I'm on intel and using codeblock. Any good sources of inline-assembly are welcome too. EDIT: I need something like this:

int 21h -> break
AH = 2Ah
CX -> year
DH -> month
DL -> day
AH = 2Ch
CH -> hour
CL -> min
DH -> sec
RET
  • 1
    So you're using GCC to compile for 16-bit DOS? `int 21h` doesn't work anywhere else. (Or some other compiler that supports GNU C extended asm). – Peter Cordes Jun 13 '21 at 18:38
  • This code is buggy: you forgot to tell the compiler that your asm clobbers `"ax"`. Of course, you could have just done a `mov %1, %0` directly, and `inc %0`. Both operands are registers. Or better, only take one `"+r"` operand that you run `inc %0` on, and let the compiler use `mov` instructions if it wants the results in different registers. – Peter Cordes Jun 13 '21 at 18:41

1 Answers1

3

In general, when using gcc inline asm on x86, you NEVER want to include mov instructions, or explicit registers in the asm code. Instead, you want to use the constraints to force inputs and output into specific registers. The constraints available are:

+---+--------------------+
| r |    Register(s)     |
+---+--------------------+
| a |   %eax, %ax, %al   |
| b |   %ebx, %bx, %bl   |
| c |   %ecx, %cx, %cl   |
| d |   %edx, %dx, %dl   |
| S |   %esi, %si        |
| D |   %edi, %di        |
+---+--------------------+

This means that your increment example (putting a value into ax and incrementing) can be much more effectively written as:

asm("inc %0" : "+a" (a))

This forces the variable a into the ax register (assuming it is a 16-bit value) and increments it there.

One tricky problem is there are no constraints for h registers (upper 8 bits of 16 bit registers). So if you want to do things with those, you need to use a 16 bit value and explicitly pack/unpack the pairs. So for your int 21h/2Ah call, you would use something like:

uint16_t year, month_day;
asm("int 0x21" : "=c" (year), "=d" (month_day) : "a" (0x2a00));
uint8_t month = month_day >> 8;
uint8_t day = month_day;
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226