Understanding ELF using readelf and objdump

Understanding ELF Understanding ELF 介绍ELF格式 立即下载
 
Contributed by Mulyadi Santosa in Misc on 2006-06-16 00:00:00

What is ELF? ELF (Executable and Linking Format) is file format that defines how an object file is composed and organized. With this information, your kernel and the binary loader know how to load the file, where to look for the code, where to look the initialized data, which shared library that needs to be loaded and so on.

First of all, you should know about different kind of ELF object:

  • Relocatable file: an object file that holds code and data suitable for linking with other object files to create an executable or a shared object file. In other word, you can say that relocatable file is a foundation for creating executables and libraries.

    This is kind of file you get if you compile a source code like this:

    $ gcc -c test.c

    That will produce test.o, which is a relocatable file.

    Kernel module (either suffixed with .o or .ko) is also a form of relocatable file.

  • Executable file: object file that holds a program suitable for execution. Yes, that means, your XMMS mp3 player, your vcd software player, even your text editor are all ELF executable files.

    This is also a familiar file if you compile a program:

    $ gcc -o test test.c

    After you make sure the executable bit of "test" is enabled, you can execute it. The question is, what about shell script? Shell script is NOT ELF executable, but the interpreter IS.

  • Shared object file: This file holds code and data suitable for linking in two contexts:

    1. The link editor may process it with other relocatable and shared shared object file to create another object file.
    2. The dynamic linker combines it with an executable file and other shared objects to create a process image.

    In simple words, these are the files that you usually see with suffix .so (normally located inside /usr/lib on most Linux installation).

Is there any other way to detect the ELF type? Yes there is. In every ELF object, there is a file header that explains what kind file it is. Assuming you have installed binutils package, you can use readelf to read this header. For example (command results are shortened to show related fields only):

$ readelf -h /bin/ls
Type: EXEC (Executable file)

$ readelf -h /usr/lib/crt1.o
Type: REL (Relocatable file)

$ readelf -h /lib/libc-2.3.2.so
Type: DYN (Shared object file)

"File" command works too for object file identification, but I won't discuss it further. Let's focus on readelf and objdump, since we will use both of them.

To make us easier to study ELF, you can use the following simple C program:

/* test.c */
#include

int global_data = 4;
int global_data_2;

int main(int argc, char **argv)
{
int local_data = 3;

printf("Hello World/n");
printf("global_data = %d/n", global_data);
printf("global_data_2 = %d/n", global_data_2);
printf("local_data = %d/n", local_data);

return (0);
}

And compile it:

$ gcc -o test test.c

A. Examining ELF header.

The produced binary will be our examination target. Let's start with the content of the ELF header:

$ readelf -h test
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x80482c0
Start of program headers: 52 (bytes into file)
Start of section headers: 2060 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 28
Section header string table index: 25

What does this header tell us?

  • This executable is created for Intel x86 32 bit architecture ("machine" and "class" fields).

  • When executed, program will start running from virtual address 0x80482c0 (see entry point address). The "0x" prefix here means it is a hexadecimal number. This address doesn't point to our main() procedure, but to a procedure named _start. Never felt you had created such thing? Of course you don't. _start procedure is created by the linker whose purpose is to initialize your program.

  • This program has a total of 28 sections and 7 segments.

What is section? Section is an area in the object file that contains information which is useful for linking: program's code, program's data (variables, array, string), relocation information and other. So, in each area, several information is grouped and it has a distinct meaning: code section only hold code, data section only holds initialized or non-initialized data, etc. Section Header Table (SHT) tells us exactly what sections the ELF object has, but at least by looking on "Number of section headers" field above, you can tell that "test" contains 28 sections.

If section has meaning for the binary, our Linux kernel doesn't see it the same way. The Linux kernel prepares several VMA (virtual memory area) that contains virtually contigous page frames. Inside these VMA, one or more sections are mapped. Each VMA in this case represents an ELF segment. How the kernel knows which section goes to which segment? This is the function of Program Header Table(PHT).

Figure 1. ELF structure in two different point of view.


B. Examining Section Header Table(SHT).

Let's see what kind of sections that exist inside our program (output is shortened):

$ readelf -S test

There are 28 section headers, starting at offset 0x80c:

Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
........
[ 4] .dynsym DYNSYM 08048174 000174 000060 10 A 5 1 4
........
[11] .plt PROGBITS 08048290 000290 000030 04 AX 0 0 4
[12] .text PROGBITS 080482c0 0002c0 0001d0 00 AX 0 0 4
........
[20] .got PROGBITS 080495d8 0005d8 000004 04 WA 0 0 4
[21] .got.plt PROGBITS 080495dc 0005dc 000014 04 WA 0 0 4
........
[22] .data PROGBITS 080495f0 0005f0 000010 00 WA 0 0 4
[23] .bss NOBITS 08049600 000600 000008 00 WA 0 0 4
........
[26] .symtab SYMTAB 00000000 000c6c 000480 10 27 2c 4
........

.text section is a place where the compiler put executables code. As the consequence, this section is marked as executable ("X" on Flg field). In this section, you will see the machine codes of our main() procedure:

$ objdump -d -j .text test

-d tells objdump to diassembly the machine code and -j tells objdump to focus on specific section only (in this case, .text section)

08048370 
  
   :
   
.......
8048397: 83 ec 08 sub $0x8,%esp
804839a: ff 35 fc 95 04 08 pushl 0x80495fc
80483a0: 68 c1 84 04 08 push $0x80484c1
80483a5: e8 06 ff ff ff call 80482b0

.data section hold all the initialized variable inside the program which doesn't live inside the stack. "Initialized" here means it is given an initial value like we did on "global_data". How about "local_data"? No, local_data's value isn't in .data since it lives on process's stack.

Here is what objdump found about .data section:

$ objdump -d -j .data test
.....
080495fc :
80495fc: 04 00 00 00 ....

.....

One thing that we can conclude so far is that objdump kindly does address-to-symbol transformation for us. Without looking into symbol table, we know that 0x08049424 is the address of global_data. There, we clearly see that it is initialized with 4. Please note that common executables installed by most Linux distribution has been striped out, thus there is no entry in its symbol table. It makes objdump difficult to interpret the addresses.

And what is .bss? BSS (Block Started by Symbol) is a section where all unitialized variables are mapped. You might think "everything surely has an initial value". True, in Linux case, all unitialized variables are set as zero, that's why .bss section is just bunch of zeroes. For character type variables, that means null character. Knowing this fact, we know that global_data_2 is assigned 0 on runtime:

$ objdump -d -j .bss test-lagi
Disassembly of section .bss:
.....
08049604 :
8049604: 00 00 00 00 ....
.....

Previously, we mentioned a bit about symbol table. This table is useful to find the correlation between a symbol name (non external function, variable) and an address. Using -s, readelf will decode the symbol table for you:

$ readelf -s ./test
Symbol table '.dynsym' contains 6 entries:
Num: Value Size Type Bind Vis Ndx Name
.....
2: 00000000 57 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.0 (2)
.....

Symbol table '.symtab' contains 72 entries:
Num: Value Size Type Bind Vis Ndx Name
.....
49: 080495fc 4 OBJECT GLOBAL DEFAULT 22 global_data
.....
55: 08048370 109 FUNC GLOBAL DEFAULT 12 main
.....
59: 00000000 57 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.0
.....
61: 08049604 4 OBJECT GLOBAL DEFAULT 23 global_data_2
.....

"Value" denotes the address of the symbol. For example, if an instruction refers to this address (e.g: pushl 0x80495fc), that means it refers to global_data. Printf() is treated differently, since it is a symbol that refers to an external function. Remember that printf is defined in glibc, not inside our program. Later, I will explain how our program calls printf.

C. Examining Program Header Table(PHT).

Like I explained previously, segment is the way operating system "sees" our program. Thus, let's see how will our program be segmented:

$ readelf -l test
.....
There are 7 program headers, starting at offset 52

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
[00] PHDR 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4
[01] INTERP 0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1
[02] LOAD 0x000000 0x08048000 0x08048000 0x004fc 0x004fc R E 0x1000
[03] LOAD 0x0004fc 0x080494fc 0x080494fc 0x00104 0x0010c RW 0x1000
[04] DYNAMIC 0x000510 0x08049510 0x08049510 0x000c8 0x000c8 RW 0x4
[05] NOTE 0x000128 0x08048128 0x08048128 0x00020 0x00020 R 0x4
[06] STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4

Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version
.gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini
.rodata .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag
06
Note:I add numbers on the left of each PHT entries to make the reader easier to study the section to segment mapping.

The mapping is quite straightforward. For example, inside segment number 02, there are 15 sections mapped. .text section is mapped in this segment. Its flags are R and E, which means it is Readable and Executable. If you see W in segment's flag, that means it is writable.

By looking on "VirtAddr" column, we can discover the virtual start address of each segment. Back to the segment number #2, the start address is 0x08048000. Later in this section, we will discover that this address isn't the real address of the segment on memory. You can ignore the PhysAddr, because in Linux always operate in protected mode (on Intel/AMD 32 bit and 64 bit) thus virtual address is the thing that matters.

Segment has many types, but let's focus on two types:

  • LOAD: The segment's content is loaded from the executable file. "Offset" denotes the offset of the file where the kernel should start reading the file's content. "FileSiz" tells us how many bytes must be read from the file.

    For example,segment #2 is actually the content of the file starting from offset 0 to 4fc (offset+filesiz). To speed up the execution, the file's content is read on demand, thus it is only read from the disk if it is referenced at runtime.

  • STACK : The segment is stack area. Interesting to see that all the fields except "Flg" and "Align" are given 0. Is it an error? No, it is valid. It is the kernel's job to decide where the stack segment starts from and how big it is. Remember that on Intel compatible processor, stack grows downward (address is decremented each time a value is pushed).

Courious to see the real layout of process segment? We can use /proc/<pid>/maps file to reveal it. <pid> is the PID of the process we want to observe. Before we move on, we have a small problem here. Our test program runs so fast that it ends before we can even dump the related /proc entry. I use gdb to solve this. You can use another trick such as inserting sleep() before it calls return().

In a console (or a terminal emulator such as xterm) do:

$ gdb test
(gdb) b main
Breakpoint 1 at 0x8048376
(gdb) r
Breakpoint 1, 0x08048376 in main ()

Hold right here, open another console and find out the PID of program "test". If you want the quick way, type:

$ cat /proc/`pgrep test`/maps

You will see an output like below (you might get different output):

[1]  0039d000-003b2000 r-xp 00000000 16:41 1080084  /lib/ld-2.3.3.so
[2] 003b2000-003b3000 r--p 00014000 16:41 1080084 /lib/ld-2.3.3.so
[3] 003b3000-003b4000 rw-p 00015000 16:41 1080084 /lib/ld-2.3.3.so
[4] 003b6000-004cb000 r-xp 00000000 16:41 1080085 /lib/tls/libc-2.3.3.so
[5] 004cb000-004cd000 r--p 00115000 16:41 1080085 /lib/tls/libc-2.3.3.so
[6] 004cd000-004cf000 rw-p 00117000 16:41 1080085 /lib/tls/libc-2.3.3.so
[7] 004cf000-004d1000 rw-p 004cf000 00:00 0
[8] 08048000-08049000 r-xp 00000000 16:06 66970 /tmp/test
[9] 08049000-0804a000 rw-p 00000000 16:06 66970 /tmp/test
[10] b7fec000-b7fed000 rw-p b7fec000 00:00 0
[11] bffeb000-c0000000 rw-p bffeb000 00:00 0
[12] ffffe000-fffff000 ---p 00000000 00:00 0
Note: I add number on each line as reference.

Back to gdb, type:

(gdb) q

So, in total, we see 12 segment (also known as Virtual Memory Area--VMA). Focus on the first and the last field. First field denotes VMA address range, while last field shows the backing file. Do you see the similarity between VMA #8 and segment #02 listed in PHT? The difference is, SHT said it is ended on 0x080484fc, but on VMA #8, we see that it ends on 0x08049000. Same thing happens between VMA #9 and segment #03; SHT said it starts at 0x080494fc, while the VMA starts at 0x0804900.

There are several facts we must observe:

  1. Even though the VMA started on different address, the related sections are still mapped on exact virtual address.

  2. The kernel allocate memory on per page basis and the page size is 4KB. Thus, every page address is actually a multiple of 4KB e.g: 0x1000, 0x2000 and so on. So, for the first page of VMA #9, the page's address is 0x0804900. Or technically speaking, the address of the segment is rounded down (aligned) to the nearest page boundary.

Last, which one is the stack? That is VMA #11. Usually, the kernel allocate several pages dynamically and map to the highest virtual address possible in user space to form stack area. Simply speaking, each process address space is divided into two part (this assume Intel compatible 32 bit processor): user space and kernel space. User space is in 0x00000000-0xc0000000 range, while kernel space starts on 0xc0000000 onwards.

So, it is clear that stack is assigned address range near the 0xc0000000 boundary. The end address is static, while the start address is changing according to how many values are stored on stack.

D. How a function is referenced?

If a program calls a function that resides within its own executable, all it has to do is simple: just call the procedure. But what happens if it calls something like printf() that is defined inside glibc shared library?

Here, I won't discuss deeply about how the dynamic linker really works, but I focus on how the calling mechanism is implemented inside the executable itself. With this assumption in mind, let's continue.

When a program wants to call a function, it actually does following flow:

  1. It made a jump to relevant entry in PLT (Procedure Linkage Table).

  2. In PLT, there is another jump to an address mentioned in related entry in GOT (Global Offset Table).

  3. If this is the first the function is called, follow step #4. If this isn't, follow step #5.

  4. The related GOT entry contains an address that points back to next instruction in PLT. Program will jump to this address and then calls the dynamic linker to resolve the function's address. If the function is found, its address is put in related GOT entry and then the function itself is executed.

    So, another time the function is called, GOT already holds its address and PLT can jump directly to the address. This procedure is called lazy binding; all external symbols are not resolved until the time it is really needed (in this case, when a function is called). Jump to step #6.

  5. Jump to the address mentioned in GOT. It is the address of the function thus PLT is no longer used.

  6. Execution of the function is finished. Jump back to the next instruction in the main program.

As always, looking inside the executable is the best way to explain it. If you do:

$ objdump -d -j .text test

You will see the following code fragment:

.....
08048370 :
.....
804838f: e8 1c ff ff ff call 80482b0

What we have on 0x80482b0 is:

 080482b0 

As you see, the jump on 0x80482b0 is indirect jump ('*' in front of the address). So, to see where it will jump, we must peek into 0x80482b0. The guesses are, either this address is in .got section or in .got.plt. Looking back in SHT, it is clear that we must check .got.plt. I use readelf to do hexadecimal dump because it does number reordering for us:

$ readelf -x 21 test
Hex dump of section '.got.plt':
0x080495dc 080482a6 00000000 00000000 08049510 ................
0x080495ec 080482b6 ....
(Note: first column is virtual address. The data in this address is described at the 5th column, not the second one! So, from right to left, the address is in ascending order.)

Bingo! We have "080482b6" here. In other word, we go back to PLT and there we eventually jump another address. This is where the work of the dynamic linker is started, so we will skip it. Assuming the dynamic linker has finished its magic work, the related GOT entry now holds the address of printf().

E. Alternative tool to inspect ELF structure.

Besides counting on readelf and objdump, there is another tool called Biew. This is actually a file viewer but it is capable to parse the ELF structure.. You can grab the source from http://biew.sourceforge.net/ and compile it by yourself. Usually biew is included in hacking oriented Linux Live CD such as Phlak. Refer to the website and the packaged documents on how to compile and install Biew.

I personally like Biew because it offers curses based GUI display. Navigation between sections, checking ELF header, listing symbols and other tasks are now just a matter of pressing certain keyboard shortcut and you're done.

For example, you can list the symbols and directly jump to the symbol's address. Here, we try to jump to main(). First execute biew:

$ biew test

Press Ctrl+A followed by F7 to view symbol table. To avoid wasting time traversing the table, press again F7 to open "Find string" menu. Type "main" and press Enter. Once the highlighted entry is what you're looking for, simply press Enter and Biew will jump to the address of main(). Don't forget to switch to the disassembler mode (press F2 to select it) so you can see the high level interpretation of the opcodes.

Figure 2. Biew lists all symbols

Since we usually refer to virtual address, not file offset, it is better to switch to virtual address view. Press Ctrl+C followed by F6 and select "Local". Now, what you see in the leftmost column is the virtual address.

Conclusion

This article is just an overview on how to study ELF structure. Using readelf and objdump, you are ready to take your first journey. If needed, tool like Biew can help you to explore the binary internal faster. Use any arsenal you have, be creative and practice it regularly, then soon you can master the technique. Happy exploring.

Further reading

Understanding_ELF.pdf 有需要的没有积分的,可以发邮件h5ru@qq.com,我发给你。 ELF 格式解析,基于ELF规范v1.2版本。 版权方为:E-mail: fion2009.z@gmail.com 备用邮箱及MSN:fyzhao2004@hotmail.com 作者赵凤阳 现就职于爱立信(Ericsson)。 立即下载

相关推荐

elf的头文件

对elf文件中的结构体描述的头文件,对解析elf文件很有用的

ELF文件格式解析一

通过以上的定义以及示例讲解,相信大家已经对ELF的文件格式有所了解了,如果想要继续深挖ELF文件的细节,大家可以参考以下这些资料。

m0_37564426的博客 604

elf 加密机制

比较全面的总结了elf文件加密的方法,如何对开源软件或商用软件保护的方法

Understanding the Memory Layout of Linux Executables

Understanding the Memory Layout of Linux Executables Required tools for playing around with memory: hexdump objdump readelf xxd gcore strace diff cat We're going to go through this: https://spl...

weixin_30947043的博客 325

政府科技管理者在推动科技成果转化过程中,如何解决科研成果与市场需求脱节的问题?.docx

政府科技管理者在推动科技成果转化过程中,如何解决科研成果与市场需求脱节的问题?

ChipCamp探索系列 -- 7A. 开源CPU之BOOM的来龙去脉

本文梳理一下Berkeley的乱序超标量CPU项目----Berkeley Out of Order Machine (BOOM),作为探索7系的首篇(7A)。

ChipCamp的博客---https://chipcamp.blog.youkuaiyun.com/ 1558

恶意软件分析入门:Security-Paper项目中的Linux恶意软件研究资料

恶意软件分析是网络安全领域的重要技能,而Linux系统由于其广泛的服务器应用和开源特性,成为恶意软件攻击的重要目标。Security-Paper项目作为一个安全资料收集仓库,提供了丰富的Linux恶意软件分析学习资源,帮助新手快速掌握恶意软件分析的基础知识和实践方法。 ## 为什么学习Linux恶意软件分析? 随着Linux系统在服务器、嵌入式设备和云计算环境中的普及,针对Linux的恶意软件

gitblog_01112的博客 718

Redis+QMT实战:如何用Stream模式实现聚宽策略的毫秒级跟单(附完整代码)

本文详细介绍了如何利用Redis Stream模式构建一个低延迟、高可靠的量化交易信号中继系统,实现从聚宽策略到本地QMT的毫秒级跟单。通过对比传统方案,解析了Redis Stream在消息持久化、消费组和显式确认方面的核心优势,并提供了完整的架构设计思路与核心代码实现,帮助量化开发者解决云端策略信号稳定传递至本地实盘的难题。

weixin_29280657的博客 477

从硅到软件:计算机系统五层抽象深度解析

计算机系统本质是一套层层封装又相互制约的物理与逻辑协同体。其核心原理源于晶体管开关特性、指令集硬件语义、内存一致性模型等底层约束,技术价值在于打破‘纯软件思维’幻觉,建立软硬协同的问题定位能力。典型应用场景涵盖嵌入式驱动调试、高性能计算优化、操作系统定制及eBPF系统追踪等工程实践。理解硅层电气行为与ISA层内存模型,是诊断缓存伪共享、时钟漂移、链接时地址错位等疑难问题的关键前提。

liangqilang的专栏 111

手把手教你用树莓派蓝牙抓取小米温湿度计2代数据,接入HomeAssistant(附密钥获取避坑指南)

本文详细介绍了如何通过树莓派蓝牙抓取小米温湿度计2代数据并接入HomeAssistant的完整流程。重点解析了获取32位加密密钥的三种方法,包括使用Telink Flasher工具、米家APP抓包和开源工具ATC_MiThermometer,并提供了HomeAssistant集成配置和常见问题排查指南,帮助用户实现稳定可靠的温湿度监测。

一名菜鸟攻城师 779

SAP_MM模块库存概览俄罗斯报表简介

本文介绍了SAP MM模块中"库存概览俄罗斯报表"的功能与应用。该报表主要用于查看物料在不同库存地点和类型的库存情况,并满足俄罗斯当地法规要求。文章解释了"俄罗斯报表"可能指代本地化合规库存报表或客户自定义报表,详细说明了事务代码J3RFLVMOBVEDH的操作步骤,包括公司代码、物料编码、日期范围等查询条件,并解释了报表中各字段含义如期初期末库存数量与价值。最后强调在物料分类账处理完成后使用该报表可获得实际库存价值,为SAP用户提供了实用的库存管理参考。

我小时候很黑的博客 1089

《ELF格式解析》完成,发布1.0版

本文详细讲解了ELF文件格式,并配有示例。

-第二月-的专栏 3348

YOLOv5 自定义模型 Android 部署完整指南

本文详细介绍了将YOLOv5模型部署到Android设备的完整流程,包含三个核心部分:首先验证官方模型测试,确保基础环境配置正确;随后进行模型转换,从PyTorch导出ONNX格式并优化,再转换为NCNN格式;最后在Android项目中集成自定义模型,包括文件替换、参数修改和代码适配。教程基于YOLOv5 6.1版本,使用NCNN框架进行移动端推理,涵盖了常见问题解决方案和关键配置要点,为开发者提供了从训练到部署的完整技术路线。

FJN110的博客 592

objdump命令详解

objdump命令详解

C/C++、嵌入式开发、深度学习算法、模型部署与推理优化 2129

基于51单片机的智能台灯设计:嵌入式程序设计实现

随着智能家居和物联网的快速发展,智能台灯作为一种典型的智能家居产品,已成为现代家庭中不可或缺的设备。传统的台灯只能提供简单的照明功能,而智能台灯不仅具备基础的照明功能,还能根据用户的需求进行自动调节,比如自动调节亮度、色温,甚至具备定时开关、远程控制等智能功能。本文将介绍如何基于51单片机设计一款智能台灯。我们将涉及硬件设计、嵌入式系统架构、传感器选择、调光控制、语音识别、远程控制等方面,详细阐述如何实现这些功能,并给出相关的代码和实现步骤。

2201_76125393的博客 836

槽型光电开关传感器原理图设计,已量产(光电传感器)

在嵌入式设备的位置限位、物料计数等场景中,槽型光电开关是性价比极高的传感器方案 —— 它通过遮挡发射器与接收器之间的光路实现电平切换,电路简单且抗干扰性优于漫反射式光耦。今天分享一个实际项目中落地的槽型光电开关检测电路,从器件选型到逻辑设计都做了简化适配,适合小批量原型或低成本产品的需求。

不脱发的程序猿 719

linux elf 文件理解与分析

https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/ 我们理所当然的使用一些真正的工艺品。其中一部分就是 linux 上常见的工具,像 ps 和 ls。虽然这些命令看起来很简单,当仔细探究就会发现很多东西。这就要讲到 ELF(Executable and Linkable Format)。一个广泛使用的文件格式,只有少部分人真正了解。让我们通过这篇介绍教程去了解它。 通过阅读本手册,你讲学到: 为什么要用 ELF

择一事终一生 3922

华为OD 面试手撕代码真题【岛屿的周长】

0代表水,1代表陆地,岛由陆地组成且岛内不允许有湖,让你求岛的周长。

MISAYAONE的博客 8420

The 101 of ELF files on Linux: Understanding and Analysis

转自 https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/   Some of the true craftsmanship in the world we take for granted. One of these things is the common tools on Linux, like...

weixin_42284785的博客 556

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Load-time relocation of shared libraries

This article's aim is to explain how a modern operating system makes it possible to use shared libraries with load-time relocation. It focuses on the Linux OS running on 32-bit x86, but the general pr...

qinrenzhi的博客 455

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

another issue: I encoutered such a strace stack

another issue: I encoutered such a strace stack  #9  0xb6af99ca in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available.  #10 0xb6aa401d in ?? () from /lib/i386-linux-gn

middilestep的专栏 3308

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

ELF 解析符号包,包含symtab 和dynsym

ELF 解析符号包,包含symtab 和dynsym,并未对所以平台支持 /* * ParseDynSymTable.c * * Created on: 2014年7月19日 * Author: angel-toms */ #include "ElfParser.h" Elf32_Sym* get_elf_section_of_sym_table(MemMapping*

ylcangel的专栏 8171
上一篇: x87FPU状态寄存器
下一篇: C++操作数的类型转换(一)
mindview
博客等级 码龄19年 7粉丝 10原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值