扩展内联汇编中的约束“Rah”和“Ral”意味着什么?

2024-03-17

这个问题的灵感来自于另一个论坛上有人提出的问题。在下面的代码中,扩展内联汇编约束是什么Rah and Ral意思是。我以前没见过这些:

#include<stdint.h>

void tty_write_char(uint8_t inchar, uint8_t page_num, uint8_t fg_color)
{
    asm (
        "int $0x10"
        :
        : "b" ((uint16_t)page_num<<8 | fg_color),
          "Rah"((uint8_t)0x0e), "Ral"(inchar));
}

void tty_write_string(const char *string, uint8_t page_num, uint8_t fg_color)
{
    while (*string)
        tty_write_char(*string++, page_num, fg_color);
}

/* Use the BIOS to print the first command line argument to the console */
int main(int argc, char *argv[])
{
    if (argc > 1)
        tty_write_string(argv[1], 0, 0);

    return 0;
}

特别是使用Rah and Ral作为此代码中的约束:

asm (
    "int $0x10"
    :
    : "b" ((uint16_t)page_num<<8 | fg_color),
      "Rah"((uint8_t)0x0e), "Ral"(inchar));

The 海湾合作委员会文档 https://gcc.gnu.org/onlinedocs/gcc/Constraints.html#Constraints没有l or h任何一个的约束简单的约束 https://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html#Simple-Constraints或 x86/x86机器限制 https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints. R是任何遗留寄存器并且a is the AX/EAX/RAX登记。

我不明白什么?


您所看到的代码旨在在具有 BIOS 的基于 x86 的 PC 上以实模式运行。Int 0x10 http://www.ctyme.com/intr/int-10.htm是一个 BIOS 服务,能够写入控制台。尤其Int 0x10/AH=0x0e http://www.ctyme.com/intr/rb-0106.htm是将单个字符写入 TTY(终端)。

这本身并不能解释约束的含义。了解限制条件Rah and Ral您必须了解此代码不是由标准版本的 GCC/CLANG 编译的。它正在由一个名为的 GCC 端口编译ia16-gcc https://github.com/tkchia/gcc-ia16。它是一个针对 8086/80186 和 80286 及兼容处理器的特殊端口。它不会生成 386 条指令,也不会在代码生成中使用 32 位寄存器。这实验性的GCC 版本的目标是 16 位环境,例如 DOS(FreeDOS、MSDOS),以及ELKS http://elks.sourceforge.net/.

的文档ia16-gcc很难在网上找到 HTML 格式的,但我为最近制作了一份副本GitHub 上的 GCC 6.3.0 版本文档 https://mpetch.github.io/ia16-gcc-6.3.0/gcc/index.html。该文档是通过从源代码构建 ia16-gcc 并使用make生成 HTML。如果您查看 Intel 的机器限制IA-16—配置/ia16您现在应该能够看到发生了什么:

Ralal 寄存器。

Rah啊寄存器。

这个版本的 GCC 不理解R不再受到自身的约束。您正在查看的内联程序集与参数相匹配整数 0x10/Ah=0xe http://www.ctyme.com/intr/rb-0106.htm:

VIDEO - TELETYPE OUTPUT
AH = 0Eh
AL = character to write
BH = page number
BL = foreground color (graphics modes only)

Return:
Nothing

Desc: Display a character on the screen, advancing the cursor
      and scrolling the screen as necessary

其他信息

该文档确实列出了 IA16 目标可用的所有约束:

Intel IA-16—config/ia16/constraints.md
a
The ax register. Note that for a byte operand, 
this constraint means that the operand can go into either al or ah.
     
b
The bx register.

c
The cx register.

d
The dx register.

S
The si register.

D
The di register.

Ral
The al register.

Rah
The ah register.

Rcl
The cl register.

Rbp
The bp register.

Rds
The ds register.

q
Any 8-bit register.

T
Any general or segment register.

A
The dx:ax register pair.

j
The bx:dx register pair.

l
The lower half of pairs of 8-bit registers.

u
The upper half of pairs of 8-bit registers.

k
Any 32-bit register group with access to the two lower bytes.

x
The si and di registers.

w
The bx and bp registers.

B
The bx, si, di and bp registers.

e
The es register.

Q
Any available segment register—either ds or es (unless one or both have been fixed).

Z
The constant 0.

P1
The constant 1.

M1
The constant -1.

Um
The constant -256.

Lbm
The constant 255.

Lor
Constants 128 … 254.

Lom
Constants 1 … 254.

Lar
Constants -255 … -129.

Lam
Constants -255 … -2.

Uo
Constants 0xXX00 except -256.

Ua
Constants 0xXXFF.

Ish
A constant usable as a shift count.

Iaa
A constant multiplier for the aad instruction.

Ipu
A constant usable with the push instruction.

Imu
A constant usable with the imul instruction except 257.

I11
The constant 257.

N
Unsigned 8-bit integer constant (for in and out instructions).

有许多新的限制和一些重新调整用途的限制。

特别是aAX 寄存器的约束不像其他针对 32 位和 64 位代码的 GCC 版本那样工作。编译器可以自由选择AH or ALa约束if传递的值是 8 位值。这意味着有可能a约束在扩展内联汇编语句中出现两次。

您可以使用以下命令将代码编译为 DOS EXE:

ia16-elf-gcc -mcmodel=small -mregparmcall -march=i186 \
             -Wall -Wextra -std=gnu99 -O3 int10h.c -o int10h.exe

它针对的是 80186。您可以通过省略来生成 8086 兼容代码-march=i186生成的代码为main看起来像:

00000000 <main>:
   0:   83 f8 01                cmp    ax,0x1
   3:   7e 1d                   jle    22 <tty_write_string+0xa>
   5:   56                      push   si
   6:   89 d3                   mov    bx,dx
   8:   8b 77 02                mov    si,WORD PTR [bx+0x2]
   b:   8a 04                   mov    al,BYTE PTR [si]
   d:   20 c0                   and    al,al
   f:   74 0d                   je     1e <tty_write_string+0x6>
  11:   31 db                   xor    bx,bx
  13:   b4 0e                   mov    ah,0xe
  15:   46                      inc    si
  16:   cd 10                   int    0x10
  18:   8a 04                   mov    al,BYTE PTR [si]
  1a:   20 c0                   and    al,al
  1c:   75 f7                   jne    15 <main+0x15>
  1e:   31 c0                   xor    ax,ax
  20:   5e                      pop    si
  21:   c3                      ret
  22:   31 c0                   xor    ax,ax
  24:   c3                      ret

当使用命令行运行时int10h.exe "Hello, world!"应该打印:

你好世界!


特别提示:GCC 的 IA16 端口是非常实验性的,并且确实存在一些代码生成错误,特别是在使用更高的优化级别时。目前我不会将它用于关键任务应用程序。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

扩展内联汇编中的约束“Rah”和“Ral”意味着什么? 的相关文章

随机推荐