- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
在他关于理解 Linux Kernel Initcall Mechanism 的文章中, Trevor 创建了一个用户空间程序来模拟调用 linux 驱动程序的 init_module() 的机制。
#include <stdio.h>
typedef int (*initcall_t)(void);
extern initcall_t __initcall_start, __initcall_end;
#define __initcall(fn) \
static initcall_t __initcall_##fn __init_call = fn
#define __init_call __attribute__ ((unused,__section__ ("function_ptrs")))
#define module_init(x) __initcall(x);
#define __init __attribute__ ((__section__ ("code_segment")))
static int __init
my_init1 (void)
{
printf ("my_init () #1\n");
return 0;
}
static int __init
my_init2 (void)
{
printf ("my_init () #2\n");
return 0;
}
module_init (my_init1);
module_init (my_init2);
void
do_initcalls (void)
{
initcall_t *call_p;
call_p = &__initcall_start;
do {
fprintf (stderr, "call_p: %p\n", call_p);
(*call_p)();
++call_p;
} while (call_p < &__initcall_end);
}
int
main (void)
{
fprintf (stderr, "in main()\n");
do_initcalls ();
return 0;
}
如您所见,未定义 __initcall_start 和 __initcall_end,因此链接器会报错并且不会生成可执行文件。解决方案是通过在文本部分之前添加以下行来自定义默认链接描述文件(由 ld --verbose 生成):
__initcall_start = .;
function_ptrs : { *(function_ptrs) }
__initcall_end = .;
code_segment : { *(code_segment) }
这是 objdump -t 输出的一个片段:
0000000000000618 g function_ptrs 0000000000000000 __initcall_end<br>
0000000000000608 g .plt.got 0000000000000000 __initcall_start<br>
0000000000000608 l O function_ptrs 0000000000000008 __initcall_my_init1<br>
0000000000000610 O function_ptrs 0000000000000008 __initcall_my_init2<br>
0000000000000618 l F code_segment 0000000000000017 my_init1<br>
我了解该机制,只是不明白链接器如何理解 __initcall_start 应指向 function_ptrs 部分或 __initcall_end 如何指向 code_segment 部分。
在我看来,__initcall_start 被分配了当前输出位置的值,然后定义了一个 function_ptrs 部分,它将指向输入文件中的 function_ptrs 部分,但我看不到 __initcall_start 和 funtction_ptrs 部分之间的链接。
我的问题是:链接器如何理解 __initcall_start 应该指向 funtion_ptrs ??
最佳答案
__initcall_start = .;
function_ptrs : { *(function_ptrs) }
__initcall_end = .;
code_segment : { *(code_segment) }
这段链接描述文件指示链接器如何编写一个输出文件的某些部分。这意味着:-
__initcall_start
寻址位置计数器(即 .
)function_ptrs
的部分,由所有名为 function_ptrs
的输入部分(即 function_ptrs
来自所有输入文件的片段)。__initcall_end
再次寻址位置计数器。code_segment
的部分,由所有名为 code_seqment
) 的输入部分function_ptrs
部分是放置在该位置的第一个存储由 __initcall_start
寻址。所以 __initcall_start
是链接器所在的地址启动 function_ptrs
段。 __initcall_end
寻址位置在 function_ptrs
段之后。出于同样的原因,它是地址链接器启动 code_segment
段。
The way I see it, __initcall_start is assigned the value of the current output location,...
你在想:
__initcall_start = .;
使链接器创建一个在某种意义上是指针的符号并将当前位置指定为该指针的值。有一点像这个 C 代码:
void * ptr = &ptr;
这里也有同样的想法(强调我的):
I just don't see how the the linker understood that __initcall_start should point to function_ptrs section or how the __initcall_end will point to the code_segment section either.
链接器没有指针的概念。它处理符号化地址的符号。
在链接器手册中,Assignment: Defining Symbols你看:
You may create global symbols, and assign values (addresses) to global symbols, using any of the C assignment operators:
symbol = expression ;
...
这意味着 symbol
被定义为由 expression
计算的地址 的符号。同样:
__initcall_start = .;
表示 __initcall_start
被定义为一个符号 for the address 在当前位置计数器。它意味着没有 type 该符号的任何内容 - 甚至没有它是一个数据 符号或一个函数 符号。符号S
的类型 是一个编程-表达该语言的程序如何使用字节序列的语言概念地址由 符号化 S
。
C 程序可以自由地声明它喜欢的任何类型它使用的外部符号 S
,只要链接提供该符号即可。无论是什么类型,程序都将获得 由 符号化的地址S
与表达式 &S
。
您的 C 程序选择同时声明 __initcall_start
和 __initcall_end
作为类型:
int (*initcall_t)(void);
这在程序告诉链接器做什么的上下文中很有意义。它告诉链接器在地址之间布置 function_ptrs
部分由 __initcall_start
和__initcall_end
符号化。本节包括int ()(void)
类型的函数数组。所以键入 int (*initcall_t)(void)
完全适合遍历该数组,如:
call_p = &__initcall_start;
do {
fprintf (stderr, "call_p: %p\n", call_p);
(*call_p)();
++call_p;
} while (call_p < &__initcall_end)
关于linux - ld:这个 ld 脚本是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49085273/
我有 powershell 脚本。通过调度程序,我运行 bat 文件,该文件运行 PS1 文件。 BAT文件 Powershell.exe -executionpolicy remotesigned
什么更快? 或者 $.getScript('../js/SOME.js', function (){ ... // with $.ajaxSetup({ cache: true });
需要bash脚本来显示文件 #!/bin/bash my_ls() { # save current directory then cd to "$1" pushd "$1" >/dev/nu
我有一个输入 csv 文件,实际上我需要在输入文件中选择第 2 列和第 3 列值,并且需要转换两个值的时区(从 PT 到 CT),转换后我需要替换转换后的时区值到文件。 注意: 所有输入日期值都在太平
我正在使用/etc/init.d/httpd 作为 init.d 脚本的模板。我了解文件中发生的所有内容,但以下行除外: LANG=$HTTPD_LANG daemon --pidfile=${pid
我有以下选择: python runscript.py -O start -a "-a "\"-o \\\"-f/dev/sda1 -b256k -Q8\\\" -l test -p maim\""
我对 shell 脚本完全陌生,但我需要编写一个 shell 脚本来检查文件是否存在,然后移动到另一个位置 这是我写的: 一旦设备崩溃,我就会在/storage/sdcard1/1 中收集日志 #!/
我正在使用 bash 脚本从文本文件中读取数据。 数据: 04:31 Alex M.O.R.P.H. & Natalie Gioia - My Heaven http://goo.gl/rMOa2q
这是单击按钮时运行的 javascript 的结尾 xmlObj.open ('GET', /ajax.php, true); xmlObj.send (''); } 所以这会执行根目录中的php脚本
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
我需要将文件转换为可读流以通过 api 上传,有一个使用 fs.createReadStream 的 Node js 示例。任何人都可以告诉我上述声明的 python 等价物是什么? 例子 const
我有一个 shell 脚本 cron,它从同一目录调用 python 脚本,但是当这个 cron 执行时,我没有从我的 python 脚本中获得预期的输出,当我手动执行它时,我的 python 脚本的
如何使 XMLHttpRequest (ajax) 调用的 php 脚本安全。 我的意思是,不让 PHP 文件通过直接 url 运行,只能通过脚本从我的页面调用(我不想向未登录的用户显示数据库结果,并
我正在尝试添加以下内容 我正在使用经典的 asp。但我不断收到的错误是“一个脚本 block 不能放在另一个脚本 block 内。”我尝试了此处的 document.write 技术:Javasc
如何从另一个 PHP 脚本(如批处理文件)中运行多个 PHP 脚本?如果我了解 include 在做什么,我认为 include 不会起作用;因为我正在运行的每个文件都会重新声明一些相同的函数等。我想
我想创建具有动态内容的网页。我有一个 HTML 页面,我想从中调用一个 lua 脚本 如何调用 lua 脚本? ? ? 从中检索数据?我可以做类似的事情吗: int xx = 0; xx
我删除了我的第一个问题,并重新编写了更多细节和附加 jSfiddle domos。 我有一个脚本,它运行查询并返回数据,然后填充表。表中的行自动循环滚动。所有这些工作正常,并通过使用以下代码完成。然而
我尝试使用 amp 脚本,但收到此错误: “[amp-script] 脚本哈希未找到。amp-script[script="hello-world"].js 必须在元[name="amp-script
我有一个读取输入的 Shell 脚本 #!/bin/bash echo "Type the year that you want to check (4 digits), followed by [E
我正在从 nodejs 调用 Lua 脚本。我想传递一个数组作为参数。我在 Lua 中解析该数组时遇到问题。 下面是一个例子: var script = 'local actorlist = ARGV
我是一名优秀的程序员,十分优秀!