このマクロ自体には命令がないため、実際には「アセンブリ」ではありません。
これは、1 つの入力オペランド、1 つの即時 (定数) 入力オペランド、および出力オペランドinstr
を持つ挿入 (マクロに渡される命令) を行う単なるマクロです。from
type
to
この命令のアドレスを特定のバイナリ セクションに記録するpushsection
との間の部分もあります。これにより、カーネルは必要に応じてコード内のこれらの場所を見つけることができます。popsection
pv_table
最後の部分は asm 制約とオペランドです。コンパイラが%0
,%1
と%2
を置き換えるものをリストします。 %0
最初にリストされている ( "=r"(to)
) は、%0 が任意の汎用レジスタになることを意味します。これは、マクロ引数に格納される出力オペランドですto
。他の 2 つは、入力オペランドであることを除いて同様です。from
レジスタなので取得します"r"
がtype
、即値なので"i"
詳細については、http: //gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/Extended-Asm.html#Extended-Asmを参照してください。
したがって、カーネルからのこのコードを検討してください ( http://lxr.linux.no/linux+v3.9.4/arch/arm/include/asm/memory.h#L172 )
static inline unsigned long __virt_to_phys(unsigned long x)
{ unsigned long t;
__pv_stub(x, t, "add", __PV_BITS_31_24);
return t;
}
__pv_stub
t = x + __PV_BITS_31_24
( instr
== add
、from
== x
、to
== t
、type
== __PV_BITS_31_24
)と同等になります
t = x + __PV_BITS_31_24
したがって、コードを記述するだけでなく、なぜこのような複雑なことを行うのか疑問に思うかもしれません。
その理由は、上で述べた pv_table です。これらすべてのステートメントのアドレスは、特定の elf セクションに記録されています。状況によっては、カーネルが実行時にこれらの命令にパッチを適用する (そのため、すべての命令を簡単に見つけられるようにする必要がある) ため、テーブルが必要になります。
ARM ポートはまさにここでそれを行います: http://lxr.linux.no/linux+v3.9.4/arch/arm/kernel/head.S#L541
これは、CONFIG_ARM_PATCH_PHYS_VIRT を使用してカーネルをコンパイルする場合にのみ使用されます。
CONFIG_ARM_PATCH_PHYS_VIRT:
Patch phys-to-virt and virt-to-phys translation functions at
boot and module load time according to the position of the
kernel in system memory.
This can only be used with non-XIP MMU kernels where the base
of physical memory is at a 16MB boundary, or theoretically 64K
for the MSM machine class.