对于C中的全局变量
int aglobal = 5;
什么时候5被加载器转移到aglobal,它如何知道将5放入全局.
与函数中的静态声明相同的情况.喜欢
int afunc(){static int astatic = 8; 回归; }
我一直在阅读ELF规范,无法确定程序入口点和_start地址从何而来。
似乎它们应该在一个相当一致的位置,但是我编写了一些琐碎的程序,而_start始终在另一个位置。
谁能澄清?
我正在尝试处理.rel.plt某些Android系统库的部分,我可以很容易地找到函数的地址.
但是,我不确定该.rel.dyn部分的条目是做什么的.此部分是否也包含功能?.got.pltARM安卓库中缺少X86库中的表.不确定是否也需要这些.
android链接器代码提到系统库是预先链接并在固定地址加载的.如何处理.rel.plt和.rel.dyn部分.
更广泛的问题是各地了解Android的基于ARM的系统库和.rel.dyn,rel.plt以及.got.plt部分用在预链接抛出的附加问题.
我有一个ELF文件,我想将其反编译为C代码,并对生成的C代码进行简单的更改,然后将其重建为ELF。
反编译的C代码不需要完全可读。例如,如果混淆了变量和函数名称,那就可以了。
我可以使用哪些工具在Linux上完成此任务?
PS:如果C无法进行编译或不容易进行编译,尽管对汇编源进行调整对我来说非常困难,但我愿意考虑对汇编语言进行反编译。
更新:您可能会假设我正在使用以下C程序来获取我的a.outELF。现在,进一步假设我已经失去了这个原始C资料。所以,我现在想将其编译到(一个可能混淆),C其中我至少能够改变像琴弦的小东西源"world","Hello"和"Bye",或能扭转感if等语句
#include <stdio.h>
#include <string.h>
char buf[256];
const char *Hello = "Hello";
const char *Bye = "Bye";
const char *Who = "world";
char * greet(const char *greeting, const char *str) {
strcpy(buf, greeting);
strcat(buf, ", ");
strcat(buf, str);
strcat(buf, "!");
return buf;
}
int main(int argc, char *argv[]) {
int sayHello …Run Code Online (Sandbox Code Playgroud) 使用时组装对象时nasm,我发现所有标签都包含在结果.o文件中的符号中,以及最终的二进制文件中.
这对于我已经声明的函数入口点GLOBAL和段开始部分(例如,对于该.text部分)是有意义的,但是标签简单地用作循环入口点并且所有这些都接近出现在输出文件中似乎很奇怪.除了泄漏内部实现细节之外,它还浪费了符号表中的空间.
例如,鉴于这个简短的装配程序:
GLOBAL _start
_start:
xor eax, eax
normal_label:
xor eax, eax
.local_label:
xor eax, eax
xor edi, edi
mov eax, 231 ; exit(0)
syscall
Run Code Online (Sandbox Code Playgroud)
...建造使用:
nasm -f elf64 label-test.s
ld label-test.o -o label-test
Run Code Online (Sandbox Code Playgroud)
在l对象文件和链接的可执行文件中生成(即本地)符号:
objdump --syms label-test.o
label-test.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 label-test.s
0000000000000000 l d .text 0000000000000000 .text
0000000000000002 l .text 0000000000000000 normal_label
0000000000000004 l .text 0000000000000000 normal_label.local_label
0000000000000000 g .text …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用gcc和clang来查看它们是否可以优化
#define SCOPE static
SCOPE const struct wrap_ { const int x; } ptr = { 42 /*==0x2a*/ };
SCOPE struct wrap { const struct wrap_ *ptr; } const w = { &ptr };
int ret_global(void) { return w.ptr->x; }
Run Code Online (Sandbox Code Playgroud)
返回一个中间常量.
事实证明他们可以:
0000000000000010 <ret_global>:
10: b8 2a 00 00 00 mov $0x2a,%eax
15: c3 retq
Run Code Online (Sandbox Code Playgroud)
但令人惊讶的是,移除静态会产生相同的装配输出.这让我很好奇,因为如果全局不是static它应该是可插入的并且用中间体替换引用应该防止全局变量上的位置.
确实如此:
#!/bin/sh -eu
: ${CC:=gcc}
cat > lib.c <<EOF
int ret_42(void) { return 42; }
#define SCOPE
SCOPE const struct wrap_ { …Run Code Online (Sandbox Code Playgroud) 因此,我有两个文件,一个是我的库,另一个是主要的prog可执行文件。图书馆:
static int internal1(int a, int b){
return a + b;
}
namespace {
int internal2(int a, int b){
return a + b;
}
}
void external2(int qq, int zz){
}
void external(int a, int b){
external2(a, b);
internal1(a, b);
internal2(a, b);
}
Run Code Online (Sandbox Code Playgroud)
用g++ -c -O0 -fPIC -o libtest.o libtest.cpp和
编译
g++ -shared -o libtest.so libtest.o
主要编:
extern void external(int a, int b);
int main(){
external(1, 2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译与 g++ -O0 -L. -ltest -o tester tester.cpp …
我有一个源文件,它为一个非常大的类定义了移动构造函数。我在 Linux 系统上用 g++ 4.9.2 编译它。当我转储生成的 ELF 对象文件的符号表时,我看到 2 个移动构造函数的列表。两个列表具有相同的地址、相同的大小、相同的类型,并且链接器链接得很好,没有 ODR 违规。当我反汇编目标文件时,我只看到一个移动构造函数。我的结论是符号表有两个指向同一位置的条目。
同样的行为也会发生在这个特定类的构造函数中,该类是在同一个源文件中定义的。
我看到的唯一一个我不完全理解的编译标志是“-m64”,但我不知道这将如何影响符号表。
我也用 g++ 9.2.0 尝试过,现在符号表中有 3 个条目!其中两个指向同一个地址,第三个指向地址0x0,位于.text.unlikely部分,并被标记为[clone .cold]。
为什么是这样?
编辑:实际上,我可以在家里用一个很小的班级重现这个。
// class.h
class VeryLargeClass
{
int data;
public:
VeryLargeClass(VeryLargeClass&&);
};
// class.cpp
#include "class.h"
VeryLargeClass::VeryLargeClass(VeryLargeClass&& other)
{
data = other.data;
other.data = 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我用 编译它g++ -c -O3 class.cpp -o class.o,然后用 转储符号表,objdump -t class.o | c++filt我会得到以下内容: class.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 main.cc
0000000000000000 l d .text …Run Code Online (Sandbox Code Playgroud) PLT 使用方式在 SystemV ABI 中指定(并在实践中实现),示意性如下:
# A call from somewhere in code is into a PLT slot
# (In reality not a direct call, in x64 typically an rip-relative one)
0x500:
call 0x1000
...
0x1000:
.PLT1: jmp [0x2000] # the slot for f in the binary's GOT
pushq $index_f
jmp .PLT0
...
0x2000:
# initially jumps back to .PLT to call the lazy-binding routine:
.GOT1: 0x1005
# but after that is called:
0x3000 # the address of the real implementation …Run Code Online (Sandbox Code Playgroud)