kill的意思是,作为在Fedora linux中加载程序的响应



我有一个结构简单的汇编程序,一个文本段和一个bss段。十多年来,我一直在编写类似的程序。这是一个Forth编译器,我用elf头玩把戏。我已经习惯了,如果我把elf头搞砸了,我就无法启动程序,加载程序甚至在出错之前就说"已杀死"。

但现在我有一个Fedora版本6 linux的用户,他做以下工作:

as -32 lina.s
ld a.out -N -melf_i386 -o lina
./lina

并得到一条消息"killed"和137作为"echo$?"的结果

显然,这个过程只使用了官方工具,因此elf标头至少应该是有效的。在像我的ubuntu或Debian系统这样的其他系统上,完全相同的过程会导致程序正常工作。结果程序的objdumps至少与段的映射相同。

请告诉我这里发生了什么,我不知道如何解决这个问题。

我想强调的是,可能没有执行任何指令,即gdb拒绝运行它

(gdb) run
Starting program: /home/gerard/Desktop/lina-5.1/glina32
Warning:
Cannot insert breakpoint -2.
Error accessing memory address 0x8048054: Input/output error.

(gdb)

在极少数情况下,如果进程试图执行新程序时发生错误,Linux内核将向该进程发送SIGKILL信号,而不是返回错误。该信号将导致外壳打印";被杀死";,而不是一个更有用的错误消息;内存不足";。您创建的可执行文件会触发一个错误,内核只能通过杀死试图执行该错误的进程来恢复该错误

通常,shell通过进行两个系统调用来执行程序:forkexecve。第一个系统调用创建一个新进程,但不加载新的可执行文件。相反,fork系统调用复制了调用它的进程。第二个系统调用加载了一个新的可执行文件,但没有创建一个新进程。相反,进程中运行的程序将被可执行文件中的新程序替换。

在执行execve系统调用的过程中,内核需要丢弃进程地址空间中以前的内容,以便用全新的内容完全替换它。在此之后,execve系统调用不能再向调用它的程序返回错误代码,因为该程序已不存在。如果在这一点之后发生错误,导致无法加载可执行文件,那么内核除了终止进程之外别无选择。

这种行为记录在Linux execve(2)手册页中:

execve()失败的大多数情况下,控制返回到原始可执行映像,然后execve()的调用程序可以处理错误然而,在(罕见)情况下(通常由资源引起衰竭),失败可能发生在不归路点之后:原始可执行映像已被删除,但新映像可能不能完全建成。在这种情况下,内核会终止进程带有SIGKILL信号。

bash根据终止进程的信号号打印消息。"Killed"是指收到SIGKILL:的进程

$ pgrep cat  # check that there aren't other cat processes running that you might not want to kill while doing this
$ cat         # in another terminal, pkill cat
Terminated
$ cat         # in another terminal, pkill -9 cat  (or pkill -KILL cat)
Killed
$ cat         #  pkill -QUIT cat   or hit control-
Quit (core dumped)
$ cat         #  pkill -STOP cat  or hit control-z
[1]+  Stopped                 cat
$ fg
cat                 # pkill -BUS cat
Bus error (core dumped)
$ cat               # pkill -PWR cat
Power failure

Bash不会为SIGINT打印任何内容,因为这是control-C发送的内容。

运行kill -l列出信号缩写。

$ strace cat            # then pkill -KILL cat
... dynamic library opening and mapping, etc. etc.
read(0,  <unfinished ...>)              = ?
+++ killed by SIGKILL +++
Killed

我无法用as -32 hello.s/ld -N -melf_i386重现您的问题,以生成一个我的内核不会运行的可执行文件,或者立即接收SIGKILL。

使用gcc -m32 -c/ld -Ngcc -m32 -E hello.S > hello.s && as -32,我得到一个打印Hello World的二进制文件(使用sys_write和sys_exit)。

// hello.S   a simple example I had lying around
// Use  gcc -m32 -E hello.S > hello.s to create input for as -32   
#include <asm/unistd.h>
#include <syscall.h>
#define STDOUT 1
.data               # should really be .rodata
hellostr:
    .ascii "hello wolrdn";
helloend:
.text
.globl _start
_start:
    movl $(SYS_write) , %eax  //ssize_t write(int fd, const void *buf, size_t count);
    movl $(STDOUT) , %ebx
    movl $hellostr , %ecx
    movl $(helloend-hellostr) , %edx
    int $0x80
    movl $(SYS_exit), %eax //void _exit(int status);
    xorl %ebx, %ebx
    int $0x80
    ret

您可以从使用strace开始,查看可执行文件在杀死自己之前发出了哪些系统调用(如果有的话)。

查看系统调用通常会发现问题所在的线索。

如果您试图在32位Linux上运行64位程序,则会出现相同的信息"killed"。所以我的解释是,如果它试图加载一个程序,但不知怎么没能运行它,这就是来自shell的消息

最新更新