汇编函数地址table及函数下或数据段中的数据
Assembly function address table and data under the function or in data section
我有一个问题是将数据(地址table或其他数据)放在其功能下的.text
部分还是放在.data
部分?
例如,我有一个这样的函数:
extern int i0();
extern int i1();
extern int i2();
extern int i3();
extern int i4();
extern int i5();
void fff(int x) {
switch (x) {
case 0:
i0();
break;
case 1:
i1();
break;
case 2:
i2();
break;
case 3:
i3();
break;
case 4:
i4();
break;
case 5:
i5();
break;
}
}
在汇编中,这是我的代码:
fff:
cmp edi, 5
ja .L10
mov edi, edi
xor eax, eax
jmp [QWORD PTR .L4[0+rdi*8]]
.L4:
.quad .L9
.quad .L8
.quad .L7
.quad .L6
.quad .L5
.quad .L3
.L5:
jmp i4
.L3:
jmp i5
.L9:
jmp i0
.L8:
jmp i1
.L7:
jmp i2
.L6:
jmp i3
.L10:
ret
这里我有 .L4
保存跳转地址...我应该把这个 .L4
table 放在哪里?在 fff
函数下还是我必须将它放在 .data
部分?静态数据呢?例如,我有一个函数有 2 QWORD
,我必须把它放在那个函数中,或者我必须把那些 QWORDs
放在数据部分?为什么 ?我知道放在.data段或者function下不会有问题,但是我想知道哪种方式更好?
是的,你可以把指针(.L4:
)的table放在.text
部分(如果它在运行时不会被修改的话)但是我没有看到双重间接指向一组外部函数跳转的原因 i0
..i5
。您可以使用间接近跳转进行分支,它从指向这些外部函数的 table 指针中获取目标地址。链接器负责完成外部地址。 NASM/Intel 语法示例:
| | global fff
| | extern i0,i1,i2,i3,i4,i5
|00000000:4883FF05 |fff: cmp rdi, 5
|00000004:773A | ja .L10
|00000006:FF24FD[10000000] | jmp [.L4+8*rdi]
|0000000D:0F1F00 | align 8 ; For better performance.
|00000010:[0000000000000000] |.L4: dq i0
|00000018:[0000000000000000] | dq i1
|00000020:[0000000000000000] | dq i2
|00000028:[0000000000000000] | dq i3
|00000030:[0000000000000000] | dq i4
|00000038:[0000000000000000] | dq i5
|00000040:C3 |.L10:ret
.data
部分通常是 writable,您不希望您的跳转 table 被意外或恶意覆盖。所以 .data
不是最好的地方。
.text
就可以了;它通常是只读的。它是否靠近功能并不重要。许多系统有一个 .rodata
部分是只读的而不是 executable,这会更好;这将有助于捕获错误或攻击,这些错误或攻击意外或故意尝试执行跳转的字节 table.
我有一个问题是将数据(地址table或其他数据)放在其功能下的.text
部分还是放在.data
部分?
例如,我有一个这样的函数:
extern int i0();
extern int i1();
extern int i2();
extern int i3();
extern int i4();
extern int i5();
void fff(int x) {
switch (x) {
case 0:
i0();
break;
case 1:
i1();
break;
case 2:
i2();
break;
case 3:
i3();
break;
case 4:
i4();
break;
case 5:
i5();
break;
}
}
在汇编中,这是我的代码:
fff:
cmp edi, 5
ja .L10
mov edi, edi
xor eax, eax
jmp [QWORD PTR .L4[0+rdi*8]]
.L4:
.quad .L9
.quad .L8
.quad .L7
.quad .L6
.quad .L5
.quad .L3
.L5:
jmp i4
.L3:
jmp i5
.L9:
jmp i0
.L8:
jmp i1
.L7:
jmp i2
.L6:
jmp i3
.L10:
ret
这里我有 .L4
保存跳转地址...我应该把这个 .L4
table 放在哪里?在 fff
函数下还是我必须将它放在 .data
部分?静态数据呢?例如,我有一个函数有 2 QWORD
,我必须把它放在那个函数中,或者我必须把那些 QWORDs
放在数据部分?为什么 ?我知道放在.data段或者function下不会有问题,但是我想知道哪种方式更好?
是的,你可以把指针(.L4:
)的table放在.text
部分(如果它在运行时不会被修改的话)但是我没有看到双重间接指向一组外部函数跳转的原因 i0
..i5
。您可以使用间接近跳转进行分支,它从指向这些外部函数的 table 指针中获取目标地址。链接器负责完成外部地址。 NASM/Intel 语法示例:
| | global fff
| | extern i0,i1,i2,i3,i4,i5
|00000000:4883FF05 |fff: cmp rdi, 5
|00000004:773A | ja .L10
|00000006:FF24FD[10000000] | jmp [.L4+8*rdi]
|0000000D:0F1F00 | align 8 ; For better performance.
|00000010:[0000000000000000] |.L4: dq i0
|00000018:[0000000000000000] | dq i1
|00000020:[0000000000000000] | dq i2
|00000028:[0000000000000000] | dq i3
|00000030:[0000000000000000] | dq i4
|00000038:[0000000000000000] | dq i5
|00000040:C3 |.L10:ret
.data
部分通常是 writable,您不希望您的跳转 table 被意外或恶意覆盖。所以 .data
不是最好的地方。
.text
就可以了;它通常是只读的。它是否靠近功能并不重要。许多系统有一个 .rodata
部分是只读的而不是 executable,这会更好;这将有助于捕获错误或攻击,这些错误或攻击意外或故意尝试执行跳转的字节 table.