对于那些喜欢将.S
格式用于GCC的人,我使用了:
ex3:
mov $0x0, %ecx
jmp lpe
lps:
movslq %ecx, %rax
lea (%rdi, %rax, 1), %r8
movzbl (%r8), %r9d
add %rsi, %rax
movzbl (%rax), %r10d
mov %r10b, (%r8)
mov %r9b, (%rax)
add $0x1, %ecx
lpe:
cmp %edx, %ecx
jl lps
repz retq
.data
.text
.global _main
_main:
mov $0x111111111111, %rdi
mov $0x222222222222, %rsi
mov $0x5, %rdx
mov $0x333333333333, %r8
mov $0x444444444444, %r9
call ex3
xor %eax, %eax
ret
然后您可以用gcc main.S -o main
对其进行编译,然后运行objdump -x86-asm-syntax=intel -d main
以intel格式查看它,或者在反编译器中运行生成的main
可执行文件。.但是,让我们进行一些手动工作。
首先,我将AT&T语法转换为更常见的Intel语法。.::
ex3:
mov ecx, 0
jmp lpe
lps:
movsxd rax, ecx
lea r8, [rdi + rax]
movzx r9d, byte ptr [r8]
add rax, rsi
movzx r10d, byte ptr [rax]
mov byte ptr [r8], r10b
mov byte ptr [rax], r9b
add ecx, 0x1
lpe:
cmp ecx, edx
jl lps
rep ret
现在我可以清楚地看到,从lps
(循环开始)到lpe
(循环结束)是for循环。
如何?因为首先将计数器寄存器(ecx
)设置为0,然后通过先执行ecx < edx
再执行cmp ecx, edx
(如果小于则跳转)检查jl
。如果是,则运行代码。并将ecx
加1(add ecx, 1
)..如果不存在,则该块存在。
因此,它看起来像:for (int32_t ecx = 0; ecx < edx; ++ecx)
..(请注意edx是rdx的低32位)。
所以现在我们用以下知识翻译其余内容:
r10
是64位寄存器。 r10d
是高32位,r10b
是低8位。r9
是一个64位寄存器。适用与r10
相同的逻辑。
所以我们可以代表一个寄存器,如下所示:
typedef union Register
{
uint64_t reg;
struct
{
uint32_t upper32;
uint32_t lower32;
};
struct
{
uint16_t uupper16;
uint16_t ulower16;
uint16_t lupper16;
uint16_t llower16;
};
struct
{
uint8_t uuupper8;
uint8_t uulower8;
uint8_t ulupper8;
uint8_t ullower8;
uint8_t luupper8;
uint8_t lulower8;
uint8_t llupper8;
uint8_t lllower8;
};
} Register;
哪个更好。您可以自己选择。现在我们可以开始查看说明了。movsxd
或movslq
将32位寄存器移动到带符号扩展名的64位寄存器中。
现在我们可以编写代码:
uint8_t* ex3(uint8_t* rdi, uint64_t rsi, int64_t rdx)
{
uintptr_t rax = 0;
for (int32_t ecx = 0; ecx < (rdx & 0xFFFFFFFF); ++ecx)
{
rax = ecx;
uint8_t* r8 = rdi + rax;
Register r9 = { .reg = *r8 }; //zero extend into the upper half of the register
rax += rsi;
Register r10 = { .reg = *(uint32_t*)rax }; //zero extend into the upper half of the register
*r8 = r10.lllower8;
*(uint8_t*)rax = r9.lllower8;
}
return rax;
}
希望我没有弄乱任何东西。。
我很确定是这样:交换两个内存区域:
void memswap(unsigned char *rdi, unsigned char *rsi, int edx) {
int ecx;
for (ecx = 0; ecx < edx; ecx++) {
unsigned char r9 = rdi[ecx];
unsigned char r10 = rsi[ecx];
rdi[ecx] = r10;
rsi[ecx] = r9;
}
}