-1

I am trying to figure out how to use the variable ret within the inline assembly code below, but I keep getting this error: undefined reference to 'ret.

char getkey(void){
int ret;
asm(
"movq $0, %RAX\n\t"
"INT $0X16\n\t"
"movq %RAX, ret"
);
return ret;
}
Mat
  • 202,337
  • 40
  • 393
  • 406
  • I am using gcc. I am using ubuntu OS. – stingraing Dec 29 '15 at 21:43
  • 1
    You should look at assembler templates and passing the variables as input (and output parameters) https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html – Michael Petch Dec 29 '15 at 21:44
  • I've added a link to the docs in my first comment. – Michael Petch Dec 29 '15 at 21:46
  • `ret` is the name of an instruction; this may be what is causing it to fail – user1354557 Dec 29 '15 at 21:48
  • I changed the name of ret and it still does not work. – stingraing Dec 29 '15 at 21:51
  • 1
    Aside from the fact you're not using GCC's inline assembly correctly, this code can never work. The INT 0x16 keyboard BIOS interface only works in real mode and you can't access the 64-bit registers (eg. RAX) from real mode. (Theoretically it could work under a 64-bit DOS extender, but as far I know no such thing exists.) – Ross Ridge Dec 29 '15 at 21:58

1 Answers1

4

What you're trying to do won't work. PC BIOS interrupts, like int 16h, are only available when the system is running in real mode (i.e, at startup before the MMU is enabled); they cannot be used in Linux executables.

That being said, in general, you can specify an output register using gcc assembler constraints. For example:

asm(
    "movq $0, %RAX\n"
    "int $0x16\n"
    : "=a" (ret)
);

Note that there's no mov instruction at the end of this code! The "=A" constraint tells the compiler that the result will be left in the A register; it'll figure out what to do from there. (There are ways to eliminate the first mov as well, if you're clever about it.)

  • So you are saying my code and even the code you provided will not work because I cannot use the interrupts? – stingraing Dec 29 '15 at 22:19
  • @stingraing Correct. You can't use BIOS interrupts in any operating system newer than MS-DOS. –  Dec 29 '15 at 22:20
  • So how can I access the bios. How do the OS do it? If I created an OS, wouldn't the OS be able to? Is this not how they create libraries for programming languages? – stingraing Dec 29 '15 at 22:25
  • @stingraing You can't, and it doesn't. Modern operating systems basically ignore the BIOS beyond startup and interface with the hardware directly. –  Dec 29 '15 at 22:28
  • How can I interface with the hardware? – stingraing Dec 29 '15 at 22:30
  • On Linux you interface with the hardware mostly via kernel resident code, mostly in device drivers. Device drivers *can* present a usually restricted interface to the `userland` via device nodes in the filesystem, via `ioctl()`. Sometimes the address space for registers of a device can also be mapped directly to `userspace` to implement essentially `userspace` drivers. – Ziffusion Dec 29 '15 at 22:50
  • If you start the pc and you have not downloaded any drivers, how does the OS know how to use a device? – stingraing Dec 29 '15 at 22:59
  • Well, actually there *is* a mov in this code, just not after the interrupt call. So how about `asm("int $0x16" : "=A" (ret) : "0" (0));`? – David Wohlferd Dec 29 '15 at 23:14
  • 1
    @stingraing When you start an IBM-PC(assume a legacy BIOS), the BIOS contains interrupts that can handle the basic hardware. Many people start out by making calls to the BIOS for their first toy OS/bootloader. Unfortunately if you use protected mode most BIOSes don't support protected mode calls. Usually protected mode OSes implement drivers that communicate with the hardware that is discovered. This is usually done by communicating with IO ports (in/out family of instructions) or reading/writing directly to memory. Essentially rolling your own device drivers that a BIOS interrupt did for you – Michael Petch Dec 29 '15 at 23:28
  • The `"A"` constraint actually specifies the EDX:EAX register pair as a 64-bit value (only usable in 32 bit mode). You want the `"a"` constraint for rax/eax/ax by itself. – Chris Dodd Dec 29 '15 at 23:46
  • @ChrisDodd Good catch. I was cribbing from some code I'd written that called `rdtsc`. –  Dec 29 '15 at 23:55