LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 4838|回复: 14

C语言问题一则

[复制链接]
发表于 2004-2-22 13:35:29 | 显示全部楼层 |阅读模式
[PHP] 首先,来看如下一段程序
char* xyzstring = "hello,world!";
int main(void)
{
xyzstring[0] = 'a';
printf("%s\n",xyzstring);
return 0;
}

这段程序有问题吗?有,xyzstring的数据应该是静态数据,不能被修改。对,C语言的标准上也是这样说的。

果然是这样吗,我们做一个测试,使用四种编译器来看看实际运行的情况。

Codewarrior 8.0、Visual C++ 6.0、Borland C++ 5.6编译后运行都没有问题,都打出了"aello,world!",GCC 3.2编译后运行程序死掉。

为什么会出现这种情况,答案很简单,GCC将"hello,world!"放到了.text段中,而其它三种编译器则是将"hello,world!"到了.data段中。程序中,.text段是用来存放代码的,因此不能被修改,所以,当我们用xyzstring[0]来修改其中内容的时候,程序当然会当掉了。而.data段因为是数据段,是可以被修改的,因此程序不会当掉。

下面为了验证以上说法,我们使用GCC将源代码汇编成test.s

运行如下命令gcc -S test.c
.file "test.c"
.globl _xyzstring
.text
LC0:
.ascii "hello,world!\0"
.data
.align 4
_xyzstring:
.long LC0
.def ___main; .scl 2; .type 32; .endef
.text
LC1:
.ascii "%s\12\0"
.align 2
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
call __alloca
call ___main
movl _xyzstring, %eax
movb $97, (%eax)
subl $8, %esp
pushl _xyzstring
pushl $LC1
call _printf
addl $16, %esp
movl $0, %eax
leave
ret
.def _printf; .scl 2; .type 32; .endef

以上是输出结果,我们看到test.s的头两行是
.globl _xyzstring
.text
说明_xyzstring是定义在了.text段中,现在,我们将其改称如下
.globl _xyzstring
.data
然后编译gcc -o test.exe test.s,接着执行test.exe,出现了什么,哈哈"aello,world!",执行没有问题了。

以上就是不同编译器对这种类型代码的解决方法,但是为了兼容,我们绝对不应该写出上面的代码
[/PHP]

http://blog.ifthen.net/archives/2003_10.html
发表于 2004-2-23 15:59:00 | 显示全部楼层
OK,看了之后长见识。
发表于 2004-2-23 16:12:57 | 显示全部楼层
谢谢
发表于 2004-2-27 14:37:26 | 显示全部楼层
有见地,顶一个
但是我用gcc编了一下
结果是
        .file   "xyz.c"
        .section        .rodata
.LC0:
        .string "hello,world!"
.globl xyzstring
        .data
        .align 4
        .type   xyzstring,@object
        .size   xyzstring,4
xyzstring:
        .long   .LC0
        .section        .rodata
.LC1:
        .string "%s\n"
        .text
.globl main
        .type   main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $0, %eax
        subl    %eax, %esp
        movl    xyzstring, %eax
        movb    $97, (%eax)
        subl    $8, %esp
        pushl   xyzstring
        pushl   $.LC1
        call    printf
        addl    $16, %esp
        movl    $0, %eax
        leave
        ret
.Lfe1:
        .size   main,.Lfe1-main
        .ident  "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
.s文件中本来就是.text啊
我编了之后运行是段错误
发表于 2005-3-31 23:03:14 | 显示全部楼层
char* xyzstring = "hello,world!";
int main(void)
{
xyzstring[0] = 'a';
printf("%s\n",xyzstring);
return 0;
}
为什么我在vc6中编译通过,但是一执行就出错啊……根本不能向你说的能过显示“xello world“
回复 支持 反对

使用道具 举报

发表于 2005-4-1 09:07:24 | 显示全部楼层
问题的关键是让大家知道char *xyzstring里的内容被放到哪里了,.text里,并且不能被随意的修改!
回复 支持 反对

使用道具 举报

发表于 2005-4-1 09:11:44 | 显示全部楼层
Post by zhangqiang
有见地,顶一个
但是我用gcc编了一下
结果是

  1.         .file   "xyz.c"
  2.         .section        .rodata
  3. .LC0:
  4.         .string "hello,world!"
  5. .globl xyzstring
  6.         .data
  7.         .align 4
  8.         .type   xyzstring,@object
  9.         .size   xyzstring,4
  10. xyzstring:
  11.         .long   .LC0
  12.         .section        .rodata
  13. .LC1:
  14.         .string "%s\n"
复制代码

.s文件中本来就是.text啊
我编了之后运行是段错误

汇编代码不是很清楚吗?字符串已经是rodata了,修改它肯定是得到段错误了。
回复 支持 反对

使用道具 举报

发表于 2005-4-1 09:14:33 | 显示全部楼层
Post by UnWindows
char* xyzstring = "hello,world!";
int main(void)
{
xyzstring[0] = 'a';
printf("%s\n",xyzstring);
return 0;
}
为什么我在vc6中编译通过,但是一执行就出错啊……根本不能向你说的能过显示“xello world“

你好象没有理解原文的意思。再好好看一遍。
回复 支持 反对

使用道具 举报

发表于 2005-4-1 09:14:56 | 显示全部楼层
我碰到的是段错误!
回复 支持 反对

使用道具 举报

发表于 2005-4-1 09:25:38 | 显示全部楼层
Post by kyanite
我碰到的是段错误!

你要是真有兴趣研究这个,先把linux汇编学好,再研究一下编译原理,想怎么玩都行。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表