我需要一个在STM32F401上工作的位置无关代码(PIC).但是我对指向例如struct中使用的函数的指针有问题.
简短的例子:
struct process {
struct process *next;
const char *name;
PT_THREAD((* thread)(struct pt *, process_event_t, process_data_t));
struct pt pt;
unsigned char state, needspoll;
};
process etimer_process...
static void call_process(struct process *p, process_event_t ev, process_data_t data) {
int ret;
ret = p->thread(&p->pt, ev, data);
}
Run Code Online (Sandbox Code Playgroud)
反汇编后:
Disassembly of section .data:
...
20000768 <etimer_process>:
20000768: 00000000 andeq r0, r0, r0
2000076c: 0803b134 stmdaeq r3, {r2, r4, r5, r8, ip, sp, pc}
20000770: 08027435 stmdaeq r2, {r0, r2, r4, r5, sl, ip, …Run Code Online (Sandbox Code Playgroud) 在 RISC-V 非特权规范 V20191213 中,说明了以下内容(第 21 页)
无条件跳转指令均使用 PC 相对寻址来帮助支持位置无关代码。
查看JALR指令的定义,
间接跳转指令JALR(跳转链接寄存器)采用I型编码。通过将符号扩展的 12 位 I 立即数与寄存器 rs1 相加,然后将结果的最低有效位设置为零来获得目标地址。
这个地址计算显然与PC无关。那么,为什么规范声称所有跳转指令都使用 PC 相对寻址呢?
另外,PC 相对寻址如何支持位置无关代码?难道不应该是完全相反的吗?
assembly instruction-set cpu-architecture riscv position-independent-code
考虑以下功能:
extern void test1(void);
extern void test2(void) {
test1();
}
Run Code Online (Sandbox Code Playgroud)
这是gcc -fpic在amd64 Linux上生成的代码:
test2:
jmp test1
Run Code Online (Sandbox Code Playgroud)
当我编译时-fpic,gcc显式调用PLT来启用符号插入:
test2:
jmp test1@PLT
Run Code Online (Sandbox Code Playgroud)
然而,这对于与位置无关的代码并不是严格需要的,如果我不想支持,可能会被遗漏.如有必要,链接器仍然会将跳转目标重写为PLT符号.
如何在不更改源代码且不使编译代码不适合共享库的情况下,使函数调用直接转到其目标而不是通过PLT显式转换?
我想在Linux上编译以下程序:
.global _start
.text
_start:
mov $1, %rax
mov $1, %rdi
mov $msg, %rsi
mov $13, %rdx
syscall
mov $60, %rax
xor %rdi, %rdi
syscall
msg:
.ascii "Hello World!\n"
Run Code Online (Sandbox Code Playgroud)
但是,它给了我以下链接器错误:
$ gcc -nostdlib hello.s
/usr/bin/ld: /tmp/ccMNQrOF.o: relocation R_X86_64_32S against `.text' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
我认为它不起作用的原因是 gcc-pie默认使用生成共享对象。因此,使用-no-pie修复它:
$ gcc -no-pie -nostdlib hello.s
$ ./a.out …Run Code Online (Sandbox Code Playgroud) configuration gcc gnu-assembler ld position-independent-code
我一直在努力更好地了解共享库的工作原理,但我无法围绕两件事进行思考。
1- 每个进程都有自己的虚拟内存空间和页表,因此如果共享库被加载到一个进程虚拟内存空间中,那么第二个进程如何访问该共享库,因为它不在其内存空间中?
2- 我知道只有文本部分是共享的,而全局数据不是,这怎么可能?我的理解是,对全局变量的每次引用都是通过全局偏移表(简称 GOT)完成的。所以,如果我有这行代码,x = glob那么这将大致等于mov eax,DWORD PTR [ecx-0x10]汇编中的东西,其中ecx用作 GOT 的基值。但如果是这种情况,那么很明显,无论哪个进程调用该行,它将始终访问相同的全局变量,其地址位于 GOT 中的偏移量 0x10。那么,如果两个进程使用引用相同 GOT 条目的相同文本部分,那么它们如何拥有不同的全局变量副本呢?
unix shared-libraries dynamic-linking position-independent-code got
如果使用以下命令编译一个简单的程序:
arm-none-eabi-gcc -shared -fpic -pie --specs=nosys.specs simple.c -o simple.exe
Run Code Online (Sandbox Code Playgroud)
并使用以下命令打印重定位条目:
arm-none-eabi-readelf simple.exe -r
Run Code Online (Sandbox Code Playgroud)
有一堆重定位条目部分(见下文)。
由于 -fpic / -pie 标志会导致编译器生成位置无关的可执行文件,因此我天真的(并且显然不正确)假设不需要重定位表,因为加载程序可以将可执行映像放置在任何地方而不会出现问题。那么为什么那里有一个重定位表,这是否表明代码实际上不是位置无关的?
Relocation section '.rel.dyn' at offset 0x82d4 contains 37 entries:
Offset Info Type Sym.Value Sym. Name
000084a8 00000017 R_ARM_RELATIVE
000084d0 00000017 R_ARM_RELATIVE
00008508 00000017 R_ARM_RELATIVE
00008510 00000017 R_ARM_RELATIVE
0000855c 00000017 R_ARM_RELATIVE
00008560 00000017 R_ARM_RELATIVE
00008564 00000017 R_ARM_RELATIVE
00008678 00000017 R_ARM_RELATIVE
0000867c 00000017 R_ARM_RELATIVE
0000870c 00000017 R_ARM_RELATIVE
00008710 00000017 R_ARM_RELATIVE
00008714 00000017 R_ARM_RELATIVE
00008718 00000017 R_ARM_RELATIVE
00008978 00000017 R_ARM_RELATIVE
000089dc 00000017 R_ARM_RELATIVE
000089e0 …Run Code Online (Sandbox Code Playgroud) 我需要在运行的进程中获取堆栈的基地址。这将使我能够打印将由addr2line理解的原始堆栈跟踪(已剥离运行二进制文件,但addr2line可以访问符号)。我通过检查以下内容的elf标头成功做到了这一点argv[0]:我读取了入口点并将其从中减去&_start:
#include <stdio.h>
#include <execinfo.h>
#include <unistd.h>
#include <elf.h>
#include <stdio.h>
#include <string.h>
void* entry_point = NULL;
void* base_addr = NULL;
extern char _start;
/// given argv[0] will populate global entry_pont
void read_elf_header(const char* elfFile) {
// switch to Elf32_Ehdr for x86 architecture.
Elf64_Ehdr header;
FILE* file = fopen(elfFile, "rb");
if(file) {
fread(&header, 1, sizeof(header), file);
if (memcmp(header.e_ident, ELFMAG, SELFMAG) == 0) {
printf("Entry point from file: %p\n", (void *) header.e_entry);
entry_point = (void*)header.e_entry;
base_addr = …Run Code Online (Sandbox Code Playgroud) I have one interesting compilation problem. At first, please see code to be compiled.
$ ls
Makefile main.c sub.c sub.h
$ gcc -v
...
gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
Run Code Online (Sandbox Code Playgroud)
## Makefile
%.o: CFLAGS+=-fPIE #[2]
main.so: main.o sub.o
$(CC) -shared -fPIC -o $@ $^
Run Code Online (Sandbox Code Playgroud)
$ ls
Makefile main.c sub.c sub.h
$ gcc -v
...
gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
Run Code Online (Sandbox Code Playgroud)
## Makefile
%.o: CFLAGS+=-fPIE #[2]
main.so: main.o sub.o
$(CC) -shared -fPIC -o $@ $^
Run Code Online (Sandbox Code Playgroud)
//main.c
#include …Run Code Online (Sandbox Code Playgroud) 首先,我尝试对其进行一些逆向工程:
printf '
#include <stdio.h>
int main() {
puts("hello world");
}
' > main.c
gcc -std=c99 -pie -fpie -ggdb3 -o pie main.c
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
readelf -s ./pie | grep -E 'main$'
gdb -batch -nh \
-ex 'set disable-randomization off' \
-ex 'start' -ex 'info line' \
-ex 'start' -ex 'info line' \
-ex 'set disable-randomization on' \
-ex 'start' -ex 'info line' \
-ex 'start' -ex 'info line' \
./pie \
;
Run Code Online (Sandbox Code Playgroud)
输出:
64: 000000000000063a 23 …Run Code Online (Sandbox Code Playgroud) 我试图在 gcc 中编译带有标志 -fno-pie 和不带的虚拟函数。
void dummy_test_entrypoint() { }
Run Code Online (Sandbox Code Playgroud)
当我在没有标志的情况下编译时。
gcc -m32 -ffreestanding -c test.c -o test.o
Run Code Online (Sandbox Code Playgroud)
我得到以下反汇编代码。
00000000 <dummy_test_entrypoint>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: e8 fc ff ff ff call 4 <dummy_test_entrypoint+0x4>
8: 05 01 00 00 00 add eax,0x1
d: 90 nop
e: 5d pop ebp
f: c3 ret
Run Code Online (Sandbox Code Playgroud)
当我用标志编译时。
00000000 <dummy_test_entrypoint>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 90 nop
4: 5d pop ebp
5: c3 ret
Run Code Online (Sandbox Code Playgroud)
我的问题。
它是什么??? …