ARTS-week57

Algorithms

Keyboard Row

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public:
vector<string> findWords(vector<string>& words) {
vector<string> res;
string k1 = "qwertyuiopQWERTYUIOP";
string k2 = "asdfghjklASDFGHJKL";
string k3 = "zxcvbnmZXCVBNM";
unordered_map<char, int> m;

for (auto k:k1) m[k] = 1;
for (auto k:k2) m[k] = 2;
for (auto k:k3) m[k] = 3;

for (auto word:words) {
bool flag = true;
for (auto w:word) {
if (m[w] != m[word[0]]) {
flag = false;
break;
}
}
if (flag) {
res.push_back(word);
}
}
return res;
}
};

Review

本周阅读英文文章:
1、For The Love of Big Data, Threat Schema and Directed Graphs in Cybersecurity

2、‘I Agree to the Terms and Conditions:’ One of the Largest Lies in Tech

3、You Only Need 20 Percent to Become an Effective Developer

4、TCP: OutOfMemory — Consider tuning tcp_mem

5、Great Developers Never Stop Learning

Technique

链接器一般提供多种控制整个链接过程的方法,以用来产生用户所需要的文件。一般有三种:

  • 使用命令行来给链接器指定参数,比如ld的-o-e参数。
  • 将链接指令存放在目标文件,编译器通过该方法向链接器传递指令。
  • 使用链接控制脚本,是最为灵活、最为强大的链接控制方法。

最”小”程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
char* str = "hello world!\n";

/* fixed: movl %0, %%ecx to movl %%eax, %%ecx*/
void print()
{
asm( "movl $13, %%edx \n\t"
"movl %%eax, %%ecx \n\t"
"movl $0, %%ebx \n\t"
"movl $4, %%eax \n\t"
"int $0x80 \n\t"
::"r"(str):"edx","ecx","ebx");
}

void exit()
{
asm( "movl $42, %ebx \n\t"
"movl $1, %eax \n\t"
"int $0x80 \n\t");
}

void nomain()
{
print();
exit();
}
  • 通过命令行的方式编译和链接:
    1
    2
    3
    4
    $ gcc -c -fno-builtin TinyHelloWorld.c
    $ ld -static -e nomain -o TinyHelloWorld TinyHelloWorld.o
    $ ./TinyHelloWorld
    hello world!

关于-fno-builtin: GCC编译器提供了很多的内置函数(Built-in Function),它会把一些常用的C库函数替换为编译器的内置函数,以达到优化的功能。比如GCC会将只有字符串参数的printf函数替换为puts,以节省解析的时间。所以需要-fno-builtin参数来关闭GCC内置函数功能。

关于ld -e: -e nomain表示程序的入口为nomain,也就是将ELF文件头Elf32_Ehdr的e_entry成员赋值成nomain函数的地址。

控制链接过程无非是控制输入段如何变成输出段,比如哪些输入段要合并一个输出段,哪些输入段要丢弃: 指定输出段的名字、装载地址、属性等等。

  • ld链接脚本:
    Script
    1
    2
    3
    4
    5
    6
    7
    ENTRY(nomain)
    SECTIONS
    {
    . = 0x08048000 + SIZEOF_HEADERS;
    tinytext : { *(.text) *(.data) *(.rodata) }
    /DISCARD/ : { *(.comment) }
    }

脚本说明:

第一行ENTRY(nomain)指定了入口为nomain()函数;
SECTIONS命令是链接脚本的主体,指定了各种输入段到输出段的变换,括号内的就是变换规则;
tinytext : { *(.text) *(.data) *(.rodata) }意思是为所有输入文件中的名字为”.text”、”.data”、”.rodata”的段依次合并到输出文件的”tinytext”;
/DISCARD/ : { *(.comment) }是说将所有输入文件中”.comment”段丢弃。

  • 通过命令行编译执行
    1
    2
    3
    4
    $ gcc -c -fno-builtin TinyHelloWorld.c
    $ ld -static -T TinyHelloWorld.lds -o TinyHelloWorld TinyHelloWorld.o
    $ ./TinyHelloWorld
    hello world!

通过objdump和readelf查看两种方式生成的文件,可以对比出不同。

Share

ZAO这个软件这两天刷了屏,因为生成的效果还有那个条款在朋友圈、微博都有很多人讨论,但是仔细想想,还是有点害怕的,且不说厂商怎么使用,现有的技术手段真的能防止用户数据泄露么?一旦出现数据泄露的情况,会引发什么样的后果呢?

参考

《程序员的自我修养-链接、装载与库》
https://xgh.io/blog/tinyhelloworld-c-in-ubuntu-x64/

0%