我已经创建了一个C程序来写入嵌入式ARM系统上的串行端口(/ dev / ttyS0)。在嵌入式ARM系统上运行的内核是Linux 3.0.4版,使用与下面列出的相同的交叉编译器构建。
我的交叉编译器是arm-linux-gcc(Buildroot 2011.08)4.3.6,在Ubuntu x86_64主机(3.0.0-14-generic#23-Ubuntu SMP)上运行。我已经使用stty实用程序从命令行设置串口。
神奇的是,如果存在单行代码,程序似乎将拒绝在嵌入式ARM系统上运行。如果删除该行,程序将运行。
以下是复制问题的完整代码:
编辑:我现在关闭错误的文件,如下面的评论所示。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
int test();
void run_experiment();
int main()
{
run_experiment();
return 0;
}
void run_experiment()
{
printf("Starting program\n");
test();
}
int test()
{
int fd;
int ret;
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
printf("fd = %u\n", fd);
if (fd < 0)
{
close(fd);
return 0;
}
fcntl(fd, F_SETFL, 0);
printf("Now writing to serial port\n");
//TODO:
// segfault occurs due to line of code here
// removing this line causes the program to run properly
ret = write( fd, "test\r\n", sizeof("test\r\n") );
if (ret < 0)
{
close(fd);
return 0;
}
close(fd);
return 1;
}
ARM系统上该程序的输出如下:
Segmentation fault
但是,如果我删除上面列出的行并重新编译该程序,则问题就会消失,输出结果如下:
Starting program
fd = 3
Now writing to serial port
这里可能出现什么问题,如何调试问题?这是代码,交叉编译器编译器还是操作系统版本的问题?
打开文件时,我还尝试了O_WRONLY和O_RDWR的各种组合而没有O_NOCTTY,但问题仍然存在。
正如@wildplasser在下面的评论中所建议的那样,我已经用以下代码替换了测试函数,这很大程度上基于另一个站点的代码(http://www.warpspeed.com.au/cgi-bin/inf2html .CMD?.. \ HTML \书\ Toolkt40 \ XPG4REF.INF + 112)。
然而,程序仍然无法运行,我再次收到神秘的Segmentation Fault
。
以下是代码:
int test()
{
int fh;
FILE *fp;
char *cp;
if (-1 == (fh = open("/dev/ttyS0", O_RDWR)))
{
perror("Unable to open");
return EXIT_FAILURE;
}
if (NULL == (fp = fdopen(fh, "w")))
{
perror("fdopen failed");
close(fh);
return EXIT_FAILURE;
}
for (cp = "hello world\r\n"; *cp; cp++)
fputc( *cp, fp);
fclose(fp);
return 0;
}
这是非常神秘的,因为使用我编写的其他程序,我可以以类似的方式使用write()
函数来写入sysfs文件,没有任何问题。
但是,如果程序完全在同一个结构中,那么我就不能写入/ dev / null。
但我可以使用完全相同的程序成功写入sysfs文件!
如果段错误发生在函数中的某一行,那么我会假设函数调用会导致段错误。但是,整个程序没有运行!
更新:要提供更多信息,以下是用于在ARM系统上构建的交叉编译器信息:
$ arm-linux-gcc --v 使用内置规格。 目标:arm-unknown-linux-uclibcgnueabi 配置为:/media/RESEARCH/SAS2-version2/device-system/buildroot/buildroot-2011.08/output/toolchain/gcc-4.3.6/configure --prefix = / media / RESEARCH / SAS2-version2 / device-system / buildroot / buildroot-2011.08 / output / host / usr --build = x86_64-unknown-linux-gnu --host = x86_64-unknown-linux-gnu --target = arm-unknown-linux-uclibcgnueabi --enable-languages = c,c ++ --with-sysroot = / media / RESEARCH / SAS2-version2 / device-system / buildroot / buildroot-2011.08 / output / host / usr / arm-unknown-linux-uclibcgnueabi / sysroot --with-build-time -tools = / media / RESEARCH / SAS2-version2 / device-system / buildroot / buildroot-2011.08 / output / host / usr / arm-unknown-linux-uclibcgnueabi / bin --disable -__ cxa_atexit --enable-target-optspace - -disable-libgomp --with-gnu-ld --disable-libssp --disable-multilib --enable-tls --enable-shared --with-gmp = / media / RESEARCH / SAS2-version2 / device-system / buildroot / buildroot-2011.08 / output / host / usr --with-mpfr = / media / RESEARCH / SAS2-version2 / device-system / buildroot / buildroot-2011.08 / output / host / usr --disable-n ls --enable-threads --disable-decimal-float --with-float = soft --with-abi = aapcs-linux --with-arch = armv5te --with-tune = arm926ej-s --disable-largefile --with-pkgversion =&#39; Buildroot 2011.08&#39; --with-bugurl = HTTP://bugs.buildroot.net/ 线程模型:posix gcc版本4.3.6(Buildroot 2011.08)
这是我用来编译代码的makefile:
CC=arm-linux-gcc
CFLAGS=-Wall
datacollector: datacollector.o
clean:
rm -f datacollector datacollector.o
更新:使用下面的评论和答案中给出的调试建议,我发现segfault是由字符串中包含\r
转义序列引起的。由于某些奇怪的原因,编译器不喜欢\r
转义序列,并且会在不运行代码的情况下导致段错误。
如果删除\r
转义序列,则代码按预期运行。
因此,违规行代码应如下:
ret = write(fd,&#34; test \ n&#34;,sizeof(&#34; test \ n&#34;));
因此,对于记录,实际运行的完整测试程序如下(有人可以评论吗?):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
int test();
void run_experiment();
int main()
{
run_experiment();
return 0;
}
void run_experiment()
{
printf("Starting program\n");
fflush(stdout);
test();
}
int test()
{
int fd;
int ret;
char *msg = "test\n";
// NOTE: This does not work and will cause a segfault!
// even if the fflush is called after each printf,
// the program will still refuse to run
//char *msg = "test\r\n";
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
printf("fd = %u\n", fd);
fflush(stdout);
if (fd < 0)
{
close(fd);
return 0;
}
fcntl(fd, F_SETFL, 0);
printf("Now writing to serial port\n");
fflush(stdout);
ret = write( fd, msg, strlen(msg) );
if (ret < 0)
{
close(fd);
return 0;
}
close(fd);
return 1;
}
编辑:除此之外,使用它是否更好:
ret = write( fd, msg, sizeof(msg) );
或者使用起来更好:
ret = write( fd, msg, strlen(msg) );
哪个更好?使用sizeof()或strlen()更好吗?看来字符串中的某些数据被截断,而不是使用sizeof()函数写入串口。
正如我从Pavel的评论中所理解的那样,如果strlen()
被声明为msg
,最好使用char*
。
此外,当转义序列\r
用于写入tty时,gcc似乎没有创建正确的二进制文件。
参考上面帖子中给出的最后一个测试程序,下面的代码行会导致没有程序运行的段错误:
char *msg = "test\r\n";
正如Igor在评论中所建议的,我已经使用有问题的代码行在二进制文件上运行了gdb调试器。我不得不用-g
开关编译程序。
gdb调试器正在ARM系统上本机运行,并且正在使用相同的Makefile为主机上的ARM体系结构构建所有二进制文件。所有二进制文件都是使用arm-linux-gcc交叉编译器构建的。
gdb的输出(在ARM系统上本机运行)如下:
GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-unknown-linux-uclibcgnueabi"...
"/programs/datacollector": not in executable format: File format not recognized
(gdb) run
Starting program:
No executable file specified.
Use the "file" or "exec-file" command.
(gdb) file datacollector
"/programs/datacollector": not in executable format: File format not recognized
(gdb)
但是,如果我将单行代码更改为以下内容,则二进制文件将编译并正常运行。请注意,\r
转义序列丢失了:
char *msg = "test\n";
以下是更改单行代码后gdb的输出:
GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-unknown-linux-uclibcgnueabi"...
(gdb) run
Starting program: /programs/datacollector
Starting program
fd = 4
Now writing to serial port
test
Program exited normally.
(gdb)
更新:
正如Zack在下面的答案中所建议的,我现在已经在嵌入式计算机上运行了一个测试程序 Linux系统。虽然Zack提供了一个在嵌入式系统上运行的详细脚本,但我确实如此 由于缺少根文件系统中安装的开发工具(编译器和头文件),无法运行该脚本。 我只是编译了Zack在脚本中提供的很好的测试程序,而不是安装这些工具 使用了strace实用程序。 strace实用程序在嵌入式系统上运行。
最后,我认为我理解发生了什么。
使用SPI到以太网桥(KSZ8851SNL)将错误的二进制文件通过FTP传输到嵌入式系统。 Linux内核中有一个KSZ8851SNL的驱动程序。
看起来Linux内核驱动程序,嵌入式系统上运行的proftpd服务器软件或实际硬件本身(KSZ8851SNL) 以某种方式腐蚀二进制文件。二进制文件在嵌入式系统上运行良好。
以下是通过以太网串行链路传输到嵌入式Linux系统的testz二进制文件的strace输出:
错误的二进制测试:
# strace ./testz /dev/null
execve("./testz", ["./testz", "/dev/null"], [/* 17 vars */]) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40089000
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
Segmentation fault
# strace ./testz /dev/ttyS0
execve("./testz", ["./testz", "/dev/ttyS0"], [/* 17 vars */]) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x400ca000
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
Segmentation fault
#
以下是在SD卡上传输到嵌入式Linux系统的testz二进制文件的strace输出:
良好的二元测试:
# strace ./testz /dev/null
execve("./testz", ["./testz", "/dev/null"], [/* 17 vars */]) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40058000
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=298016, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x400b8000
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\240\230\0\0004\0\0\0"..., 4096) = 4096
mmap2(NULL, 348160, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40147000
mmap2(0x40147000, 290576, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x40147000
mmap2(0x40196000, 4832, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x47) = 0x40196000
mmap2(0x40198000, 14160, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40198000
close(3) = 0
munmap(0x400b8000, 4096) = 0
stat("/lib/ld-uClibc.so.0", {st_mode=S_IFREG|0755, st_size=25296, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x400c4000
set_tls(0x400c4470, 0x400c4470, 0x4007b088, 0x400c4b18, 0x40) = 0
mprotect(0x40196000, 4096, PROT_READ) = 0
mprotect(0x4007a000, 4096, PROT_READ) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B115200 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B115200 opost isig icanon echo ...}) = 0
open("/dev/null", O_RDWR|O_NOCTTY|O_NONBLOCK) = 3
write(3, "1\n", 2) = 2
write(3, "12\n", 3) = 3
write(3, "123\n", 4) = 4
write(3, "1234\n", 5) = 5
write(3, "12345\n", 6) = 6
write(3, "1\r\n", 3) = 3
write(3, "12\r\n", 4) = 4
write(3, "123\r\n", 5) = 5
write(3, "1234\r\n", 6) = 6
close(3) = 0
exit_group(0) = ?
# strace ./testz /dev/ttyS0
execve("./testz", ["./testz", "/dev/ttyS0"], [/* 17 vars */]) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x400ed000
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=298016, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40176000
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\240\230\0\0004\0\0\0"..., 4096) = 4096
mmap2(NULL, 348160, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40238000
mmap2(0x40238000, 290576, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x40238000
mmap2(0x40287000, 4832, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x47) = 0x40287000
mmap2(0x40289000, 14160, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40289000
close(3) = 0
munmap(0x40176000, 4096) = 0
stat("/lib/ld-uClibc.so.0", {st_mode=S_IFREG|0755, st_size=25296, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x400d1000
set_tls(0x400d1470, 0x400d1470, 0x40084088, 0x400d1b18, 0x40) = 0
mprotect(0x40287000, 4096, PROT_READ) = 0
mprotect(0x40083000, 4096, PROT_READ) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B115200 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, {B115200 opost isig icanon echo ...}) = 0
open("/dev/ttyS0", O_RDWR|O_NOCTTY|O_NONBLOCK) = 3
write(3, "1\n", 21
) = 2
write(3, "12\n", 312
) = 3
write(3, "123\n", 4123
) = 4
write(3, "1234\n", 51234
) = 5
write(3, "12345\n", 612345
) = 6
write(3, "1\r\n", 31
) = 3
write(3, "12\r\n", 412
) = 4
write(3, "123\r\n", 5123
) = 5
write(3, "1234\r\n", 61234
) = 6
close(3) = 0
exit_group(0) = ?
答案 0 :(得分:9)
编辑:继续阅读血腥详情,但快速回答是,您的FTP客户端正在破坏您的程序。这是FTP的一个有意识的功能,可以通过在binary
或get whatever
之前的FTP提示符下键入put whatever
来关闭它。如果您使用的是图形化FTP客户端,则应该在某处具有相同效果的复选框。或者切换到scp
,这没有这个不方便的功能。
首先,生成的汇编代码没有区别 (一个)工作对象文件和损坏的对象文件之间。
$ objdump -dr dc-good.o > dc-good.s
$ objdump -dr dc-bad.o > dc-bad.s
$ diff -u dc-good.s dc-bad.s
--- dc-good.s 2012-01-21 08:20:05.318518596 -0800
+++ dc-bad.s 2012-01-21 08:20:10.954566852 -0800
@@ -1,5 +1,5 @@
-dc-good.o: file format elf32-littlearm
+dc-bad.o: file format elf32-littlearm
Disassembly of section .text:
实际上,只有两个字节在商品和商品之间有所不同
坏对象文件。 (你误解了我要求的东西
"test\r\n"
与"testX\n"
:我想要两个字符串
相同的长度,以便所有内容都具有相同的偏移量
目标文件。幸运的是,你的编译器填充了较短的字符串
与较长的字符串长度相同,所以一切都一样
无论如何偏移。)
$ hd dc-good.o > dc-good.x
$ hd dc-bad.o > dc-bad.x
$ diff -u1 dc-good.x dc-bad.x
--- dc-good.x 2012-01-21 08:17:28.713174977 -0800
+++ dc-bad.x 2012-01-21 08:17:39.129264489 -0800
@@ -154,3 +154,3 @@
00000990 53 74 61 72 74 69 6e 67 20 70 72 6f 67 72 61 6d |Starting program|
-000009a0 00 00 00 00 74 65 73 74 58 0a 00 00 2f 64 65 76 |....testX.../dev|
+000009a0 00 00 00 00 74 65 73 74 58 0d 0a 00 2f 64 65 76 |....testX.../dev|
000009b0 2f 74 74 79 53 30 00 00 66 64 20 3d 20 25 75 0a |/ttyS0..fd = %u.|
@@ -223,3 +223,3 @@
00000de0 61 72 69 65 73 2f 64 61 74 61 63 6f 6c 6c 65 63 |aries/datacollec|
-00000df0 74 6f 72 2d 62 61 64 2d 62 69 6e 61 72 79 2d 32 |tor-bad-binary-2|
+00000df0 74 6f 72 2d 62 61 64 2d 62 69 6e 61 72 79 2d 31 |tor-bad-binary-1|
00000e00 00 46 49 4c 45 00 5f 5f 73 74 61 74 65 00 5f 5f |.FILE.__state.__|
第一个区别是应该存在的差异:74 65 73
74 58 0a 00 00
是"test\n"
的正确编码(带一个字节)
填充),74 65 73 74 58 0d 0a 00
是正确的编码
"test\r\n"
。另一个区别似乎是调试
information:您编译的目录的名称
程式。这是无害的。
目标文件应该是它们应该是,所以在这一点上我们可以统治 编译器或汇编程序中的错误。现在让我们来看看 可执行文件。
$ hd dc-good > dc-good.xe
$ hd dc-bad > dc-bad.xe
$ diff -u1 dc-good.xe dc-bad.xe
--- dc-good.xe 2012-01-21 08:31:33.456437417 -0800
+++ dc-bad.xe 2012-01-21 08:31:38.388480238 -0800
@@ -120,3 +120,3 @@
00000770 f0 af 1b e9 53 74 61 72 74 69 6e 67 20 70 72 6f |....Starting pro|
-00000780 67 72 61 6d 00 00 00 00 74 65 73 74 58 0a 00 00 |gram....testX...|
+00000780 67 72 61 6d 00 00 00 00 74 65 73 74 58 0d 0a 00 |gram....testX...|
00000790 2f 64 65 76 2f 74 74 79 53 30 00 00 66 64 20 3d |/dev/ttyS0..fd =|
@@ -373,3 +373,3 @@
00001750 63 6f 6c 6c 65 63 74 6f 72 2d 62 61 64 2d 62 69 |collector-bad-bi|
-00001760 6e 61 72 79 2d 32 00 46 49 4c 45 00 5f 5f 73 74 |nary-2.FILE.__st|
+00001760 6e 61 72 79 2d 31 00 46 49 4c 45 00 5f 5f 73 74 |nary-1.FILE.__st|
00001770 61 74 65 00 5f 5f 67 63 73 00 73 74 64 6f 75 74 |ate.__gcs.stdout|
相同的两个差异,可执行文件中的不同偏移量。这个 也应该如此。我们也可以排除链接器中的错误 (如果它搞砸了字符串的地址,就必须这样做 在两个可执行文件中以相同的方式将它搞砸了,他们都应该这样做 崩溃)。
此时我认为我们正在查看C库中的错误或
核心。为了进一步确定,我希望你尝试这个测试
脚本。在ARM板上以sh testz.sh
运行它,然后发送给我们
完整输出。
#! /bin/sh
set -e
cat >testz.c <<\EOF
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define W(f, s) write(f, s, sizeof s - 1)
int
main(int ac, char **av)
{
int f;
if (ac != 2) return 2;
f = open(av[1], O_RDWR|O_NOCTTY|O_NONBLOCK);
if (f == -1) return 1;
W(f, "1\n");
W(f, "12\n");
W(f, "123\n");
W(f, "1234\n");
W(f, "12345\n");
W(f, "1\r\n");
W(f, "12\r\n");
W(f, "123\r\n");
W(f, "1234\r\n");
close(f);
return 0;
}
EOF
arm-linux-gcc -Wall -g testz.c -o testz
set +e
strace ./testz /dev/null
echo ----
strace ./testz /dev/ttyS0
echo ----
exit 0
我看过你提供的损坏的二进制文件,现在我知道出了什么问题。
$ ls -l testz*
-rwxr-x--- 1 zack zack 7528 Dec 31 1979 testz-bad
-rwxr-x--- 1 zack zack 7532 Jan 21 16:35 testz-good
忽略奇怪的日期戳;看看-bad
版本如何比-good
版本小四个字节?源代码中恰好有四个\r
个字符。我们来看看十六进制转储的差异。我已经把有趣的差异拉出来并将它拖了一下,以便更容易看到发生了什么。
00000620 00 00 00 00 31 32 33 34 0a 00 00 00 31 32 33 34 |....1234....1234|
-00000630 35 0a 00 00 31 0d 0a 00 31 32 0d 0a 00 00 00 00 |5...1...12......|
+00000630 35 0a 00 00 31 0a 00 31 32 0a 00 00 00 00 31 32 |5...1..12.....12|
-00000640 31 32 33 0d 0a 00 00 00 31 32 33 34 0d 0a 00 00 |123.....1234....|
+00000640 33 0a 00 00 00 31 32 33 34 0a 00 00 00 00 00 00 |3....1234.......|
-00000650 00 00 00 00 68 84 00 00 1c 84 00 00 00 00 00 00 |....h...........|
+00000650 68 84 00 00 1c 84 00 00 00 00 00 00 01 00 00 00 |h...............|
文件传输正在将0d 0a
(即\r\n
)序列替换为0a
(仅\n
)。这会导致文件中此点之后的所有内容从其应有的位置移位四个字节。代码在此之前,内核查看的所有ELF头文件都是如此,这就是为什么你没有得到
execve("./testz-bad", ["./testz-bad", "/dev/null"], [/* 36 vars */]) = -1 ENOEXEC (Exec format error)
来自测试脚本;相反,你在动态加载器中得到一个段错误,因为DYNAMIC段(它告诉动态加载器要做什么)在位移开始后是。
$ readelf -d testz-bad 2> /dev/null
Dynamic section at offset 0x660 contains 13 entries:
Tag Type Name/Value
0x00000035 (<unknown>: 35) 0xc
0x0000832c (<unknown>: 832c) 0xd
0x00008604 (<unknown>: 8604) 0x19
0x00010654 (<unknown>: 10654) 0x1b
0x00000004 (HASH) 0x1a
0x00010658 (<unknown>: 10658) 0x1c
0x00000004 (HASH) 0x4
0x00008108 (<unknown>: 8108) 0x5
0x0000825c (<unknown>: 825c) 0x6
0x0000815c (<unknown>: 815c) 0xa
0x00000098 (<unknown>: 98) 0xb
0x00000010 (SYMBOLIC) 0x15
0x00000000 (NULL) 0x3
对比:
$ readelf -d testz-good
Dynamic section at offset 0x660 contains 18 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libc.so.0]
0x0000000c (INIT) 0x832c
0x0000000d (FINI) 0x8604
0x00000019 (INIT_ARRAY) 0x10654
0x0000001b (INIT_ARRAYSZ) 4 (bytes)
0x0000001a (FINI_ARRAY) 0x10658
0x0000001c (FINI_ARRAYSZ) 4 (bytes)
0x00000004 (HASH) 0x8108
0x00000005 (STRTAB) 0x825c
0x00000006 (SYMTAB) 0x815c
0x0000000a (STRSZ) 152 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x10718
0x00000002 (PLTRELSZ) 56 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x82f4
0x00000000 (NULL) 0x0
调试信息也在位移之后,这就是gdb不喜欢该程序的原因。
那为什么这个非常特别的腐败呢?这不是任何事情的错误;它是您的FTP 客户端的故意功能,默认以“文本模式”传输文件,这意味着(除其他外)它将DOS样式的行结尾(\r\n
)转换为Unix风格(\n
)。因为如果这是1991年,那就是你想要的,并且你正在将IBM PC上的文本文件传输到机构文件服务器。即使你 移动文本文件,它基本上也不是现在想要的东西。幸运的是,您可以将其关闭:只需在文件传输命令之前在FTP提示符下键入binary
。 * Un *幸运的是,据我所知,没有办法让棒;你必须每次都这样做。我建议切换到scp
,它总是逐字传输文件,也更容易从构建自动化操作。
答案 1 :(得分:1)
首先要做的事情 - 您只看到seg故障并不表示程序根本无法运行。发生的事情是printf调用的输出是行缓冲的,当程序seg出错时,它永远不会被写出来。
如果你添加 fflush(stdout中); 在每个printf之后,你会在segfault之前看到你的输出。
现在,在您的原始程序中,fcntl的意思是什么(fd,F_SETFL,0);呼叫?你想用它做什么?你想关闭非阻塞模式吗?如果你不接听电话怎么办?
至于你的第二次测试,我发现你正在使用perror,但是缺少错误消息并没有告诉你程序没有运行 - 它只是告诉你没有收到任何错误消息,你仍然没有刷新标准输出,所以你永远不会从run_experiment看到printf。
我还看到,在你的第二次测试中,你正在使用读取模式进行fdopen,然后尝试写入该FILE指针。虽然这当然不应该崩溃,但它也肯定不会起作用。
现在,在你的程序之外,你确定串口工作正常吗?尝试做'猫&gt; / dev / ttyS0'看看会发生什么,只是为了确保它不是硬件的坏事。