我试图创建一个Promises数组,然后使用Promise.all()解决它们.我正在使用got,它返回了一个承诺.
我的代码有效,但我不完全理解.这里是:
const got = require('got');
const url = 'myUrl';
const params = ['param1', 'param2', 'param3'];
let promiseArray = [];
for (param of params) {
promiseArray.push(got(url + param));
}
// Inspect the promises
for (promise of promiseArray) {
console.log(JSON.stringify(promise));
// Output: promise: {"_pending":true,"_canceled":false,"_promise":{}}
}
Promise.all(promiseArray).then((results) => {
// Operate on results - works just fine
}).catch((e) => {
// Error handling logic
});
Run Code Online (Sandbox Code Playgroud)
让我失望的是,当我将Promises添加到数组中时Promise被标记为"pending",这意味着它们已经启动了.
我认为他们应该处于不活跃状态promiseArray
,并且Promise.all(promiseArray)
会启动它们并解决它们.
这是否意味着我两次开始他们?
为x86_64-unknown-linux-musl
目标编译时,此代码将产生一个.got
部分:
fn main() {
println!("Hello, world!");
}
Run Code Online (Sandbox Code Playgroud)
fn main() {
println!("Hello, world!");
}
Run Code Online (Sandbox Code Playgroud)
根据针对类似C代码的答案,该.got
部分是可以安全删除的工件。但是,它对我来说是段错误:
$ cargo build --release --target x86_64-unknown-linux-musl
$ readelf -S hello
There are 30 section headers, starting at offset 0x26dc08:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
...
[12] .got PROGBITS 0000000000637b58 00037b58
00000000000004a8 0000000000000008 WA 0 0 8
...
Run Code Online (Sandbox Code Playgroud)
看一下反汇编,我发现GOT基本上拥有静态函数地址:
$ objcopy -R.got hello hello_no_got
$ ./hello_no_got
[1] 3131 segmentation fault (core …
Run Code Online (Sandbox Code Playgroud) 这是什么<some symbol>@GOTPCREL(%rip)
意思?
我遇到过这一行mov var@GOTPCREL(%rip), %rax
,并对奇怪的语法感到有点困惑。
有人可以推荐我应该阅读以理解这一点的相关文档吗?谢谢!
我正在 Linux X86_64 上工作。
我需要根据条目所代表的动态函数的名称来确定 ELF 文件中特定 PLT 条目的地址。我可以算出文件相对于地址的偏移量,但我需要能够确定地址。
如果我使用反汇编 ELF 文件,objdump -D -z elffile
我会发现 objdump 对 PLT 中的每个条目使用符号名称。(objdump从哪里获取这些地址和符号名的关系?)
例子:
0000000000000041a2b0 fileno@plt:
Run Code Online (Sandbox Code Playgroud)
如果我使用objdump -T elffile | grep fileno
我会得到这样的东西:
0000000000000 DF *UND* 00000000000000000 GLIBC_2.2.5 fileno
Run Code Online (Sandbox Code Playgroud)
我需要从“C”做的是在 ELF 文件中找到特定动态函数的 PLT 条目并获取地址。
背景是我正在修补现有的 ELF 文件,并且需要将函数调用重定向到不同的动态函数。我已经使用从 objdump 反汇编中收集的地址手动修补了 ELF 文件,并证明这适用于我的特定应用程序,我只需要能够从程序中执行此操作。我希望不必通过 objdump 反汇编程序代码来找出它如何获取 PLT 条目符号和地址。
我一直在努力更好地了解共享库的工作原理,但我无法围绕两件事进行思考。
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
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) 考虑以下简单的共享库源代码:
library.cpp:
static int global = 10;
int foo()
{
return global;
}
Run Code Online (Sandbox Code Playgroud)
用-fPIC
clang中的option 编译,它会导致以下对象汇编(x86-64):
foo(): # @foo()
push rbp
mov rbp, rsp
mov eax, dword ptr [rip + global]
pop rbp
ret
global:
.long 10 # 0xa
Run Code Online (Sandbox Code Playgroud)
由于符号是在库中定义的,因此编译器按预期使用PC相对地址: mov eax, dword ptr [rip + global]
但是,如果我们更改static int global = 10;
为int global = 10;
具有外部链接的符号,则结果汇编为:
foo(): # @foo()
push rbp
mov rbp, rsp
mov rax, qword ptr [rip + global@GOTPCREL]
mov eax, dword ptr [rax] …
Run Code Online (Sandbox Code Playgroud) 据我所知,PLT
并且GOT
是处理动态链接功能的部分。
如果代码调用printf
libc 的函数,
1. 首先它调用PLT
getprintf
的地址。
2. 并将此地址写入GOT
部分。
3. 从第二次调用开始,代码使用编写的函数GOT
。
当我仔细查看 ELF 二进制文件时,
- 我发现PLT
ELF 中的section名称是<.plt>
.
-GOT
在 ELF 中部分的名称是<.got.plt>
.
但是...... <.got>
ELF中也有部分。
我无法理解如何使用此部分。
Q.<.got>
节的用法是什么?和部分有
什么区别?<.got>
<.got.plt>
PS 1. 这个<.got>
部分非常小,(在我的示例二进制文件中它只包含 4byte。)
在这里我附上<.got>
部分的IDA 视图:
.got:08049FFC ; ===========================================================================
.got:08049FFC
.got:08049FFC ; Segment type: Pure data
.got:08049FFC ; Segment permissions: Read/Write
.got:08049FFC _got segment …
Run Code Online (Sandbox Code Playgroud) 我试图弄清楚这两个部分之间的区别,这似乎是这个问题的重复,但那里给出的答案没有解释太多,所以我想要更详细和简洁的解释。
在写这个问题之前,我想强调一下,我自己做了几周的研究,阅读了数十篇文章,但这个问题仍然没有解决,而且我得到的解释根本没有意义(也许是因为我是链接世界的新手) )。所以我希望有人能提供简单但非常详细的答案。
我知道 GOT(全局偏移表)可以帮助我们解析动态链接中从另一个引用的全局符号。另外我读到:“每个共享库都有自己的 GOT”
但这是有问题的,如果两个程序使用同一个共享库怎么办?两者对于全局变量都有相同的值,但事实不应该如此。
至于我的主要问题:如果我不想使用惰性绑定,那么为什么我们需要 PLT,为什么不直接使用普通的 GOT 来处理变量呢?
这个简单的 c:
#include <stdio.h>
#include <string.h>
int *add(int a, int b){
int ar[1];
int result = a+b;
memcpy(ar, &result, sizeof(int));
return ar;
}
int main(){
int a = add(1,2)[0];
printf("%i\n",a);
}
Run Code Online (Sandbox Code Playgroud)
编译成这样:
.text
.globl add
.type add, @function
add:
pushq %rbp #
movq %rsp, %rbp #,
movl %edi, -20(%rbp) # a, a
movl %esi, -24(%rbp) # b, b
# a.c:5: int result = a+b;
movl -20(%rbp), %edx # a, tmp91
movl -24(%rbp), %eax # b, tmp92
addl %edx, %eax # …
Run Code Online (Sandbox Code Playgroud)