AIRobot

AIRobot quick note


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

本福特定律和齐夫定律

发表于 2019-11-28
本文字数: 706 阅读时长 ≈ 1 分钟

本福特定律

本福特定律,也称为本福德法则,说明一堆从实际生活得出的数据中,以1为首位数字的数的出现机率约为总数的三成,接近期望值1/9的3倍。推广来说,越大的数,以它为首几位的数出现的机率就越低。它可用于检查各种数据是否有造假。
本福特定律说明在b进位制中,以数n起头的数出现的概率为$P(n) = \log_{b}{(n+1)} - \log_{b}{(n)} = \log_{b}{(\frac{n+1}{n})}$。本福特定律不但适用于个位数字,连多位的数也可用。

齐夫定律

关于单词在文献中出现频次的齐夫定律(Zipf’s Law)。亦称省力法则。1948年由美国哈佛大学语言学教授G.K.齐夫(George K. Zipf )对英语文献中单词出现的频次进行大量统计以检验前人的定量化公式而提出的。该定律指出文章中单词的频次(f)与其排列的序号(r)之间存在着下述定量的关系,齐夫认为:如果有一个包含n 个词的文章,将这些词按其出现的频次递减地排序,那么序号r和其出现频次f之积fr,将近似地为一个常数,即$f*r=b$,(式中r=1,2,3.…),即词频分布定律最普通而又最典型的表达。 此后, 许多工具书大 都采用类似观点和说法 。如英国著名的语言学著作《语言与语言词典》 中的释义是:“(词频分布定律) 是指谈话者或写作者使用的词的分布和频次的总描述。$F * R=C$,方程式中F=频次,R=序号,即频率表上的位置;C=常数。方程式表示词使用的总次数和词频表上的位置之间有一个固定比率。”但是齐普夫的表达仅适宜于中频词的情况,高频与低频词与该表述偏差较大。于是对词频分布规律又有许多补充和深化的研究。

指定glibc编译

发表于 2019-11-20 更新于 2019-11-21
本文字数: 343 阅读时长 ≈ 1 分钟

编译时指定--rpath和--dynamic-linker,运行时指定LIB_LIBRARY_PATH。

gcc main.c -o main -Wl,--rpath=/path/to/new/glibc/lib -Wl,--dynamic-linker=/path/to/new/glibc/ld-linux-xxxx.so.2

ld-linux-xxxx.so.2的路径会硬编码到程序中。正是这个原因,导致很多已有程序不能使用新glibc的库。

另外,查看链接问题的两个常用工具是:

  • ldd: 查看可执行文件或动态库依赖的其它的库
  • strings: 查看库中的字符串,比如strings /lib64/libc.so.2 | grep GLIBC可以查看GLIBC支持的版本。

fPIC

发表于 2019-11-19
本文字数: 2.9k 阅读时长 ≈ 3 分钟

-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

gcc -shared -fPIC -o 1.so 1.c

这里有一个-fPIC参数

PIC就是position independent code
PIC 使.so文件的代码段变为真正意义上的共享如果不加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象需要重定位, 重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy.每个copy都不一样,取决于 这个.so文件代码段和数据段内存映射的位置.

不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位的.(因为它里面的代码并不是位置无关代码)如果被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了.(因为so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)我们总是用fPIC来生成so,也从来不用fPIC来生成a.fPIC与动态链接可以说基本没有关系,libc.so一样可以不用fPIC编译,只是这样的so必须要在加载到用户程序的地址空间时重定向所有表目.

因此,不用fPIC编译so并不总是不好.

如果你满足以下4个需求/条件:

  1. 该库可能需要经常更新
  2. 该库需要非常高的效率(尤其是有很多全局量的使用时)
  3. 该库并不很大.
  4. 该库基本不需要被多个应用程序共享

如果用没有加这个参数的编译后的共享库,也可以使用的话,可能是两个原因:

  1. gcc默认开启-fPIC选项
  2. loader使你的代码位置无关

从GCC来看,shared应该是包含fPIC选项的,但似乎不是所以系统都支持,所以最好显式加上fPIC选项。参见如下

-shared
Produce a shared object which can then be linked with other
objects to form an executable. Not all systems support this
option. For predictable results, you must also specify the same
set of options that were used to generate code (‘-fpic’, ‘-fPIC’,
or model suboptions) when you specify this option.(1)

-fPIC 的使用,会生成 PIC 代码,.so 要求为 PIC,以达到动态链接的目的,否则,无法实现动态链接。

non-PIC 与 PIC 代码的区别主要在于 access global data, jump label 的不同。

比如一条 access global data 的指令,non-PIC 的形势是:ld r3, var1PIC 的形式则是:ld r3, var1-offset@GOT,意思是从 GOT 表的 index 为 var1-offset 的地方处指示的地址处装载一个值,即var1-offset@GOT处的4个 byte 其实就是 var1 的地址。这个地址只有在运行的时候才知道,是由 dynamic-loader(ld-linux.so) 填进去的。

再比如 jump label 指令

non-PIC 的形势是:jump printf ,意思是调用 printf。

PIC 的形式则是:jump printf-offset@GOT,意思是跳到 GOT 表的 index 为 printf-offset 的地方处指示的地址去执行,这个地址处的代码摆放在 .plt section,每个外部函数对应一段这样的代码,其功能是呼叫dynamic-loader(ld-linux.so) 来查找函数的地址(本例中是 printf),然后将其地址写到 GOT 表的 index 为 printf-offset 的地方,同时执行这个函数。这样,第2次呼叫 printf 的时候,就会直接跳到 printf 的地址,而不必再查找了。

GOT 是 data section, 是一个 table, 除专用的几个 entry,每个 entry 的内容可以再执行的时候修改;
PLT 是 text section, 是一段一段的 code,执行中不需要修改。

每个 target 实现 PIC 的机制不同,但大同小异。比如 MIPS 没有 .plt, 而是叫 .stub,功能和 .plt 一样。

可见,动态链接执行很复杂,比静态链接执行时间长;但是,极大的节省了 size,PIC 和动态链接技术是计算机发展史上非常重要的一个里程碑。

gcc manul上面有说

-fpic If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead. (These maximums are 8k on the SPARC and 32k on the m68k and RS/6000. The 386 has no such limit.)

-fPIC If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any limit on the size of the global offset table. This option makes a difference on the m68k, PowerPC and SPARC. Position-independent code requires special support, and therefore works only on certain machines.

关键在于GOT全局偏移量表里面的跳转项大小。
intel处理器应该是统一4字节,没有问题。
powerpc上由于汇编码或者机器码的特殊要求,所以跳转项分为短、长两种。

-fpic为了节约内存,在GOT里面预留了“短”长度。
而-fPIC则采用了更大的跳转项。

原文()

fpic fPIC

发表于 2019-11-19
本文字数: 218 阅读时长 ≈ 1 分钟

相同点:都是为了在动态库中生成位置无关的代码。通过全局偏移表(GOT)访问所有常量地址。程序启动时动态加载程序解析GOT条目。

不同点:如果链接的可执行文件的GOT大小超过计算机特定的最大大小,则会从链接器收到错误消息,指示-fpic不起作用;在这种情况下,请使用-fPIC重新编译。GOT大小根据操作系统的不同而大小不一样,SPARC上为8k,在AArch64上为28k,在m68k和RS / 6000上为32k。x86没有此限制。

GDB回退调试

发表于 2019-11-12
本文字数: 378 阅读时长 ≈ 1 分钟

GDB7.0以上版本的调试器并且运行在支持反向调试的平台可以进行回退调试

  1. reverse-continue

反向运行程序直到遇到一个能使程序中断的事件(比如断点,观察点,异常)。

  1. reverse-step

反向运行程序到上一次被执行的源代码行。

  1. reverse-stepi

反向运行程序到上一条机器指令

  1. reverse-next

反向运行到上一次被执行的源代码行,但是不进入函数。

  1. reverse-nexti

反向运行到上一条机器指令,除非这条指令用来返回一个函数调用、整个函数将会被反向执行。

  1. reverse-finish

反向运行程序回到调用当前函数的地方。

  1. set exec-direction [forward | reverse]

设置程序运行方向,可以用平常的命令step和continue等来执行反向的调试命令。

1…91011…26
AIRobot

AIRobot

AIRobot quick note
130 日志
15 分类
23 标签
GitHub E-Mail
Creative Commons
0%
© 2023 AIRobot | 716k | 10:51