我有内存布局(在增加内存地址中),例如:
代码部分(0-4k),数据部分(4k-8k),堆栈部分(8k-12k),自定义数据部分(12k-16k)。
我在自定义数据部分放置了一些特殊的数组、结构。
据我所知,数据段(DS)选择器将用于任何与数据相关的编译器代码。
因此数据部分(4k-8k)对于所有操作默认都会有 DS。 (除了一些可能使用 ES 的 str 操作)。
例如,除了 EBP 和 ESP 之外的基址寄存器,默认段基址是 DS:
mov $0xc00,%eax
addl $0xd, (%eax) # address is DS:EAX
但是,我想使用额外段(ES)选择器进行自定义数据访问。我将为具有不同 Base 和 Limit 的 ES 定义一个新的 GDT 条目。 所以我需要编译器像这样发出 asm:
mov $0x3400,%eax
addl $0xd, %es:(%eax)
GCC 是否有任何 x86 编译器标志,可用于告诉编译器使用
ES
段来访问特定部分中的变量,例如标有 __attribute__((section("CustomSection")))
? 的变量
虽然问题要求提供一个选项,使 gcc 的代码生成使用 es 前缀来访问自定义部分,但如果您想以手写代码执行此操作,AT&T 语法已经允许例如%es:(%eax).
注意,这可能会破坏 gcc 有时内联的代表字符串指令; fs 或 gs 将是唯一明智的选择,即使在 x86-64 中仍然可用。
(根据 Peter Cordes 的有用批评制作此评论社区 wiki。)
#define GS_RELATIVE __attribute__((address_space(256))) int foo(int GS_RELATIVE *P) { return *P; }
编译为(在 X86-32 上):
_foo: movl 4(%esp), %eax # load the arg movl %gs:(%eax), %eax # use it with its prefix ret
地址空间 256 是
gs
,257 是 fs
,258 是 ss
。
文档没有提到
es
;编译器通常假设 es
=ds
,因此如果他们根据调整选项选择这样做,他们可以自由地内联 memcpy / memset 的 rep movs
或 rep stos
。 memcpy
或memset
的库实现也可能在某些CPU上使用rep stos/movs。 相关:为什么 std::fill(0) 比 std::fill(1) 慢?
显然这确实是低级的东西,只有当您已经设置了 GS 或 FS 基地址时才有意义。 (
wrfsbase
)。 请注意,i386 Linux 使用 gs
作为用户空间中的线程本地存储,而 x86-64 Linux 使用 fs
。
我不知道 gcc、ICC 或 MSVC 是否有此类扩展。
嗯,GNU C 中有
__thread
,它将根据目标平台使用 %gs:
或 %fs:
前缀。 gcc `__thread` 是如何工作的?.