FTP ASCII上传下载

FTP ASCII 上传失效 近期在进行AIX到Linux迁移,发现从windows终端ftp时,客户端设置ASCII传输模式, 服务端并不能自动转换换行符号,脚本出现^M,需要手工删除。 Linux环境为RedHat7.3+vsftpd(3.0.2),vsftpd.conf中ascii_download_enable/ascii_upload_enable 注释掉了,未开启. RFC959中的ASCII TYPE 3.1.1.1. ASCII TYPE This is the default type and must be accepted by all FTP implementations. It is intended primarily for the transfer of text files, except when both hosts would find the EBCDIC type more convenient. The sender converts the data from an internal character representation to the standard 8-bit NVT-ASCII representation (see the Telnet specification). The receiver will convert the data from the standard form to his own internal form. In accordance with the NVT standard, the <CRLF> sequence should be used where necessary to denote the end of a line of text. (See the discussion of file structure at the end of the Section on Data Representation and Storage.) Using the standard NVT-ASCII representation means that data must be interpreted as 8-bit bytes. 使用ASCII模式进行ftp传输时, 会把发送端本地NewLine编码, 转为NVT-ASCII格式( ), 接收端收到后,再转为本地NewLine编码。 ...

2019-08-31 · 3 min · 543 words

Linux进程创建

Linux进程创建 准备 以fork函数为例,看下Linux进程创建具体工作流程: 下面是使用fork函数创建进程的一段C代码: #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { pid_t pid; pid = fork (); if (pid < 0){ printf("fork() error\n"); }else if (pid == 0){ printf("child process \n"); }else { printf("parent process \n"); } exit(0); } 进程创建流程 trace跟踪 用户程序调用glibc中的提供fork函数,fork函数触发系统调用clone, 去创建一个进程, 下面通过strace跟踪下编译链接后的可执行文件: # strace ./fork ... open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 .... clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD ,child_tidptr=0x7fb0be0eca10) = 16273 ... 从trace日志可以看到,在fork()对应系统调用clone而非fork fork man(2) Since version 2.3.3, rather than invoking the kernel’s fork() system call, the glibc fork() wrapper that is provided as part of the NPTL threading implementation invokes clone(2) with flags that provide the same effect as the traditional system call. (A call to fork() is equivalent to a call to clone(2) specifying flags as just SIGCHLD.) The glibc wrapper invokes any fork handlers that have been established using pthread_atfork(3). ...

2019-08-18 · 13 min · 2585 words

asm-offset.h生成过程

asm-offset.h 文件 asm-offset.h 文件是在内核编译过程中生成的,生成过程 之前整理了一份笔记 TASK_threadsp的实现及asm-offsets.h, 其中涉及sed处理包含在内核代码 /scripts/Makefile.lib的sed-offsets中,工作是将生成的asm-offset.s转化为asm-offset.h。 /scripts/Makefile.lib ... # ASM offsets # --------------------------------------------------------------------------- # Default sed regexp - multiline due to syntax constraints # # Use [:space:] because LLVM's integrated assembler inserts <tab> around # the .ascii directive whereas GCC keeps the <space> as-is. define sed-offsets 's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \ /^->/{s:->#\(.*\):/* \1 */:; \ s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ s:->::; p;}' endef ...

2019-08-05 · 3 min · 591 words

Linux如何管理和度量时间

Timing Measurement Linux 内核的Timer必须要完成两种定时测量(timing measurement) 保存当前的日期时间 维护定时器(Timer) 保存当前时间提供给相关系统调用time(), ftime(),gettimeofday(),以便他们将日期时间返回给用户程序;维护定时器提醒内核某一段时间已经过去。要实现以上定时测量就离不开相关硬件的支持,下面看下X86体系下相关时钟和定时电路有哪些。 时钟和定时电路 下面仅列出X86体系结构下常见的时间相关硬件定时器、时钟。 RTC :Real Time Clock 实时时钟, 依靠电池供电,集成在CMOS芯片上(结合NVRAM和RTC),可以得到日期和时间 TSC :Time Stamp Counter 80x86处理器通过CLK引线,接收外部时钟信号,从Pentium开始 80x86处理器提供了一个TSC寄存器, 收到时钟信号后加一。可以通过rtdsc指令获取该值。因此TSC可以做为时钟设备。 PIT :Programmable Interval Timer 又被称作8253/8254芯片, 这种设备不是通过振铃而是通过发出一种特殊中断,时钟中断通知内核一个时间间隔又过去了。时钟频率大约1.193182 MHz CPU Local APIC Timer: APIC timer 由于是CPU内部的振荡器所有避免了资源抢占,APIC timer分为三种模式: Periodic Mode(周期模式),One-Shot Mode(一次性模式),TSC-Deadline Mode(Deadline模式) HPET: High Precision Event Timer 是Intel和Microsoft设计的硬件,用于替换PIT,RTC, 提供更高的频率, 包含一个64位的主计数器和3到32个32位或64位的比较器。工作模式分为: eriodic Mode(周期模式),One-Shot Mode(一次性模式) ACPI PMT: ACPI Power Management Timer 在所有基于 ACPI 的主板, 频率为 3.579545 MHz 关于 Timer Interrupt Sources 的比较 ...

2019-08-03 · 2 min · 222 words

TASK_threadsp的实现及asm-offsets.h

主动调度与上下文切换 在学习极客时间刘超《趣谈Linux操作系统》 16 节时,讲到了主动调度, 通过__schedule() 函数让出cpu三个步骤: 1. 取出任务队列; 2. 从队列取下一个任务; 3. 进行上下文切换; 其中第三步中上下文切换中 调用switch_to函数, 通过调用switch_to_asm函数完成栈顶执政寄存器的交换。 代码如下: /arch/x86/include/asm/switch_to.h #define switch_to(prev, next, last) \ do { \ prepare_switch_to(next); \ \ ((last) = __switch_to_asm((prev), (next))); \ } while (0) /arch/x86/entry/entry_64.S ENTRY(__switch_to_asm) UNWIND_HINT_FUNC 。。。 /* switch stack */ movq %rsp, TASK_threadsp(%rdi) movq TASK_threadsp(%rsi), %rsp 。。。。 END(__switch_to_asm) 其中 %rdi代表第一个参数, %rsi代表第二个参数, 分别代表 prev task, next task 将当前栈顶指针放入prev task_struct 结构 thread_struct的 sp0 中。 将next_task栈顶 指做为当前栈顶指针,完成切换。 关于 TASK_threadsp,涉及以下几个文件:(当然一开始的时候正是因为找不到才有了有序寻找答案的过程) ...

2019-07-21 · 3 min · 507 words

Linux 进程,线程的调度策略API

LINUX进程调度: 调度策略: 实时进程的调度策略: SCHED_FIFO SCHED_RR SCHED_DEADLINE 普通进程的调度策略: SCHED_NORMAL SCHED_BATCH SCHED_IDLE 调度类: stop_sched_class dl_sched_class rt_sched_class fair_sched_class idle_sched_class CFS调度策略: 普通进程使用的调度策略CFS调度策略,通过平衡各个进程vruntime来实现公平的调度, CFS维护了一个以时间为顺序的红黑树, 对处理器需求时间最多的,vruntime最小的存放在树的最左端. CPU取出运行完毕后,如果进程还在运行,增加运行时间计算vruntime后插会红黑树。 CFS相关结构: cfs_rq队列中存放树根节点和最左端节点rb_root_cached,每个节点都包含在 sched_entity,中,sched_entity中存放vruntime做为红黑树的索引, sched_entity 又属于 task_struct, task_struct 中通过 sched_class 指定调度类 具体可以参考是极客时间 《趣谈操作系统》 15-17节 LINUX进程调度API: sched - overview of CPU scheduling nice(2) 设置当前进程线程的优先级 getpriority(2) 获取指定用户的进程,进程组,线程优先级 setpriority(2) 设置指定用户的进程,进程组,线程优先级 sched_setscheduler(2) 设置调度策略 sched_getscheduler(2) 获取调度策略 sched_setparam(2) 设置调度参数. sched_getparam(2) 获取调度参数. sched_get_priority_max(2) 返回指定调度策略的优先级最大值 sched_get_priority_min(2) 返回指定调度策略的优先级最小值 sched_rr_get_interval(2) 获取SCHED_RR调度策略时间片长度 sched_yield(2) 主动让出CPU sched_setaffinity(2) (Linux-specific) 线程设置到指定CPU sched_getaffinity(2) (Linux-specific) 获取相关CPU设置 sched_setattr(2) 设置调度策略和参数 sched_getattr(2) 获取调度策略和参数 Posix Threads API : ...

2019-07-16 · 6 min · 1127 words

函数栈的调用

 本篇主要通过反汇编与GDB两种方式分析函数栈的使用过程。 反编译方法: gcc -S Stop after the stage of compilation proper; do not assemble. The output is in theform of an assembler code file for each non-assembler input file specified.By default, the assembler file name for a source file is made by replacing the suffix.c, .i, etc., with .s.Input files that don't require compilation are ignored. gcc -S -o [source].s [source].c objdump gcc stack.c -o stack.oobjdump -S ./stack.o > stack_objdump.s 编译环境: 环境: cenos7, X86_64 ...

2019-07-07 · 9 min · 1777 words

linux 任务状态定义

结构定义: Linux task_struct 结构中 涉及进程状态的属性有三个,其中进程对应的状态分为两类, 一类是运行中状态, 另一类是进程退出状态。 struct task_struct { ... /* -1 unrunnable, 0 runnable, >0 stopped: */ volatile long state; int exit_state; unsigned int flags; ... } 状态说明: TASK_RUNNING 等待运行状态 TASK_INTERRUPTIBLE 可中断睡眠状态 TASK_UNINTERRUPTIBLE 不可中断睡眠状态 TASK_STOPPED 停止状态(收到 SIGSTOP、SIGTTIN、SIGTSTP 、 SIG.TTOU信号后状态) TASK_TRACED 被调试状态 TASK_KILLABLE 新可中断睡眠状态 TASK_PARKED kthread_park使用的特殊状态 TASK_NEW 创建任务临时状态 TASK_DEAD 任务退出状态 TASK_WAKING 被唤醒状态 TASK_IDLE 任务空闲状态 /* * Task state bitmask. NOTE! These bits are also * encoded in fs/proc/array.c: get_task_state(). * * We have two separate sets of flags: task->state * is about runnability, while task->exit_state are * about the task exiting. Confusing, but this way * modifying one set can't modify the other one by * mistake. */ /* Used in tsk->state: */ #define TASK_RUNNING 0x0000 #define TASK_INTERRUPTIBLE 0x0001 #define TASK_UNINTERRUPTIBLE 0x0002 #define __TASK_STOPPED 0x0004 #define __TASK_TRACED 0x0008 /* Used in tsk->exit_state: */ #define EXIT_DEAD 0x0010 #define EXIT_ZOMBIE 0x0020 #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD) /* Used in tsk->state again: */ #define TASK_PARKED 0x0040 #define TASK_DEAD 0x0080 #define TASK_WAKEKILL 0x0100 #define TASK_WAKING 0x0200 #define TASK_NOLOAD 0x0400 #define TASK_NEW 0x0800 #define TASK_STATE_MAX 0x1000 /* Convenience macros for the sake of set_current_state: */ #define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) #define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED) #define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED) #define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD) /* Convenience macros for the sake of wake_up(): */ #define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE) /* get_task_state(): */ #define TASK_REPORT (TASK_RUNNING | TASK_INTERRUPTIBLE | \ TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \ __TASK_TRACED | EXIT_DEAD | EXIT_ZOMBIE | \ TASK_PARKED) 相关代码: 下面通过内核代码,看下任务状态转换的一个大致过程。 ...

2019-06-29 · 4 min · 671 words

Posix Threads API 整理

定义: 并发与并行: 并发(concurrency):实际上串行发生的事情好像同时发生,表述了单核处理器中线程或者进程的行为特点 并行(parallelism):并发序列同时执行, 真正的并行只能在多处理其上存在。 异步与同步: 异步(asynchronous)与同步(synchronous)区别在于发需求的人是否需要等到需要完成才可以执行其他事情。 线程安全和可重入: 线程安全:能够被多个线程调用而不会产生灾难性结果,大部分函数可以利用互斥量,条件变量,线程私有数据实现线程安全。 可重入:采用比将函数和库转换为一系列更为复杂方式使得代码成为线程安全。可重入函数应该避免任何静态数据和共享全局数据,避免依赖线程间任何形式的同步。 数据类型: 线程相关数据类型 类型 描述 pthread_t 线程标识符 pthread_mutex_t 互斥量 pthread_spinlock_t 自旋锁 pthread_cond_t 条件变量 pthread_key_t 线程私有数据访问键 pthread_attr_t 线程属性对象 pthread_mutexattr_t 互斥量属性对象 pthread_rwlockattr_t 读写锁属性 pthread_condattr_t 条件变量属性对象 pthread_once_t 一次性初始化属性对象 sigevent 线程通知机制 线程POSIX API: 基本操作 建立与终止 pthread_create pthread_exit 等待 pthread_join 取消 pthread_cancel 线程分离 pthread_detach 获取线程标识符 pthread_self 比较线程标识符 pthread_equal 基本操作 example 建立与终止 pthread_create pthread_exit 等待 pthread_join //线程创建 #include <pthread.h> #include <stdlib.h> #include <stdio.h> void * thread (void *arg) { char *ret; printf ("thread() entered with argument '%s'\n", arg); if ((ret = (char *) malloc (20)) == NULL) { perror ("malloc() error"); exit (2); } strcpy (ret, "This is a test"); pthread_exit (ret); } main () { pthread_t thid; void *ret; if (pthread_create (&thid, NULL, thread, "thread 1") != 0) { perror ("pthread_create() error"); exit (1); } if (pthread_join (thid, &ret) != 0) { perror ("pthread_create() error"); exit (3); } printf ("thread exited with '%s'\n", ret); } [root@centosgpt threaddemo]# ./create thread() entered with argument 'thread 1' thread exited with 'This is a test'. 取消 pthread_cancel //线程取消, 通过pthread_cancel 取消正在运行的线程 #include <errno.h> #include <pthread.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> int thstatus; void * thread (void *arg) { puts ("thread has started. now sleeping"); while (1) sleep (1); } main (int argc, char *argv[]) { pthread_t thid; void *status; if (pthread_create (&thid, NULL, thread, NULL) != 0) { perror ("pthread_create failed"); exit (2); } if (pthread_cancel (thid) == -1) { perror ("pthread_cancel failed"); exit (3); } if (pthread_join (thid, &status) == -1) { perror ("pthread_join failed"); exit (4); } if (status == (int *) -1) puts ("thread was cancelled"); else puts ("thread was not cancelled"); exit (0); } [root@centosgpt threaddemo]# ./cancel thread has started. now sleeping thread was cancelled 线程分离 pthread_detach // 线程分离, 线程退出后自动释放资源 #include <stdlib.h> #include <stdio.h> void * thread (void *arg) { char *ret; printf ("thread() entered with argument '%s'\n", arg); if ((ret = (char *) malloc (20)) == NULL) { perror ("malloc() error"); exit (2); } strcpy (ret, "This is a test"); pthread_exit (ret); } main () { pthread_t thid; void *ret; if (pthread_create (&thid, NULL, thread, "thread 1") != 0) { perror ("pthread_create() error"); exit (1); } if (pthread_detach (&thid) != 0) { perror ("pthread_detach() error"); exit (4); } sleep(2); printf ("thread exited with '%s'\n", ret); } [root@centosgpt threaddemo]# ./detach thread() entered with argument 'thread 1' thread exited with '(null)' [root@centosgpt threaddemo]# ./detach pthread_detach() error: Success 获取线程标识符 pthread_self 比较线程标识符 pthread_equal #include <pthread.h> #include <stdio.h> pthread_t thid, IPT; void * thread (void *arg) { if (pthread_equal (IPT, thid)) puts ("the thread is the IPT...?"); else puts ("the thread is not the IPT"); } main () { IPT = pthread_self (); if (pthread_create (&thid, NULL, thread, NULL) != 0) { perror ("pthread_create() error"); exit (1); } if (pthread_join (thid, NULL) != 0) { perror ("pthread_create() error"); exit (3); } } [root@centosgpt threaddemo]# ./self the thread is not the IPT [root@centosgpt threaddemo]# 私有数据 私有数据创建 pthread_key_create pthread_key_delete 私有数据使用 pthread_setspecific pthread_getspecific 私有数据 example 私有数据创建 pthread_key_create pthread_key_delete 私有数据使用 pthread_setspecific pthread_getspecific #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <pthread.h> #define threads 3 #define BUFFSZ 48 pthread_key_t key; void * threadfunc (void *parm) { int status; void *value; int threadnum; int *tnum; void *getvalue; char Buffer[BUFFSZ]; tnum = parm; threadnum = *tnum; printf ("Thread %d executing\n", threadnum); if (!(value = malloc (sizeof (Buffer)))) printf ("Thread %d could not allocate storage, errno = %d\n", threadnum, errno); sprintf (value, "Thread %d executing\n", threadnum); status = pthread_setspecific (key, (void *) value); if (status < 0) { printf ("pthread_setspecific failed, thread %d, errno %d", threadnum, errno); pthread_exit ((void *) 12); } printf ("Thread %d setspecific value: %d\n", threadnum, value); getvalue = 0; getvalue = pthread_getspecific (key); if (status < 0) { printf ("pthread_getspecific failed, thread %d, errno %d", threadnum, errno); pthread_exit ((void *) 13); } printf("key = %s\n", getvalue); if (getvalue != value) { printf ("getvalue not valid, getvalue=%d", (int) getvalue); pthread_exit ((void *) 68); } pthread_exit ((void *) 0); } void destr_fn (void *parm) { printf ("Destructor function invoked\n"); free (parm); } main () { int getvalue; int status; int i; int threadparm[threads]; pthread_t threadid[threads]; int thread_stat[threads]; if ((status = pthread_key_create (&key, destr_fn)) < 0) { printf ("pthread_key_create failed, errno=%d", errno); exit (1); } for (i = 0; i < threads; i++) { threadparm[i] = i + 1; status = pthread_create (&threadid[i], NULL, threadfunc, (void *) &threadparm[i]); if (status < 0) { printf ("pthread_create failed, errno=%d", errno); exit (2); } } for (i = 0; i < threads; i++) { status = pthread_join (threadid[i], (void *) &thread_stat[i]); if (status < 0) { printf ("pthread_join failed, thread %d, errno=%d\n", i + 1, errno); } if (thread_stat[i] != 0) { printf ("bad thread status, thread %d, status=%d\n", i + 1, thread_stat[i]); } } exit (0); } [root@centosgpt threaddemo]# ./key Thread 1 executing Thread 2 executing Thread 1 setspecific value: -1140848448 key = Thread 1 executing Thread 2 setspecific value: -1275066176 key = Thread 2 executing Thread 3 executing Thread 3 setspecific value: -1207957312 key = Thread 3 executing Destructor function invoked Destructor function invoked Destructor function invoked 同步: 互斥量 互斥量创建与销毁 pthread_mutex_init pthread_mutex_destroy 加锁解锁互斥量(阻塞) pthread_mutex_lock pthread_mutex_unlock 加锁解锁互斥量(非阻塞) pthread_mutex_trylock 互斥变量优先级上限 pthread_mutex_getprioceiling pthread_mutex_setprioceiling 互斥量 example 互斥量创建与销毁: pthread_mutex_init pthread_mutex_destroy 加锁解锁互斥量(阻塞) pthread_mutex_lock pthread_mutex_unlock ## 阻塞模式 pthread_mutex_lock #include <pthread.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> pthread_mutex_t mutex; void * thread (void *arg) { if (pthread_mutex_lock (&mutex) != 0) { perror ("pthread_mutex_lock() error"); exit (1); } puts ("thread was granted the mutex"); if (pthread_mutex_unlock(&mutex) != 0) { perror("pthread_mutex_unlock() error"); exit(2); } } main () { pthread_t thid; if (pthread_mutex_init (&mutex, NULL) != 0) { perror ("pthread_mutex_init() error"); exit (2); } if (pthread_create (&thid, NULL, thread, NULL) != 0) { perror ("pthread_create() error"); exit (3); } if (pthread_mutex_lock (&mutex) != 0){ perror ("pthread_mutex_lock() error"); exit (4); } puts ("IPT was granted the mutex"); if (pthread_mutex_unlock(&mutex) != 0) { perror("pthread_mutex_unlock() error"); exit(2); } if (pthread_join (thid, NULL) != 0) { perror ("pthread_mutex_trylock() error"); exit (5); } if (pthread_mutex_destroy(&mutex) != 0) { perror("pthread_mutex_destroy() error"); exit(2); } } [root@centosgpt threaddemo]# ./mutexb IPT was granted the mutex thread was granted the mutex 加锁解锁互斥量(非阻塞) pthread_mutex_trylock ### 非阻塞模式 #include <pthread.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> pthread_mutex_t mutex; void * thread (void *arg) { int rc; while (1){ if ((rc=pthread_mutex_trylock (&mutex))!=0){ if (rc == EBUSY){ puts ("thread was denied access to the mutex"); continue; } else { perror ("sub pthread_mutex_trylock() error"); exit (1); } puts ("sub thread can do other thing"); } else { puts ("thread was granted the mutex"); break; } } if (pthread_mutex_unlock(&mutex) != 0) { perror("pthread_mutex_unlock() error"); exit(2); } } main () { pthread_t thid; int rc; if (pthread_mutex_init (&mutex, NULL) != 0) { perror ("pthread_mutex_init() error"); exit (2); } if (pthread_create (&thid, NULL, thread, NULL) != 0) { perror ("pthread_create() error"); exit (3); } while(1){ if ((rc=pthread_mutex_trylock (&mutex)) != 0){ if (rc == EBUSY){ puts ("IPT was denied access to the mutex"); continue; } else { perror ("main pthread_mutex_trylock() error"); exit (4); } puts ("main thread can do other thing"); } else { puts ("IPT was granted the mutex"); break; } } if (pthread_mutex_unlock(&mutex) != 0) { perror("pthread_mutex_unlock() error"); exit(2); } if (pthread_join (thid, NULL) != 0) { perror ("pthread_mutex_trylock() error"); exit (5); } if (pthread_mutex_destroy(&mutex) != 0) { perror("pthread_mutex_destroy() error"); exit(2); } } [root@centosgpt threaddemo]# ./mutex IPT was granted the mutex thread was denied access to the mutex thread was granted the mutex 互斥变量优先级上限 pthread_mutex_getprioceiling pthread_mutex_setprioceiling 依赖于互斥锁属性的协议的设置 ...

2019-06-20 · 33 min · 6942 words

ELF 文件格式分析

定义: ELF: Executable and Linkable Format ELF文件常见的三种文件类型: relocatable (可重定位) executable(可执行) shared object(共享目标) core dumps (核心转储) [root@centosgpt 10]# file process.oprocess.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped[root@centosgpt 10]# file dynamiccreateprocessdynamiccreateprocess: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=d6fa7d670a47b7aaf05d17c92c82508bcabc48dc, not stripped[root@centosgpt 10]# file libdynamicprocess.solibdynamicprocess.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=0a9fb4457819ecf54d9762f3aff5eda0c19600fc, not stripped 组成: ELF header program header table section header table binary data 常用的elf文件分析工具, readelf, objdump, nm, hexdump ...

2019-06-11 · 25 min · 5113 words