共享对象的rodata部分中字符串文字的行为

问题描述 投票:0回答:1
#include <stdio.h>
#include <string.h>

#define CONFDIR "/opt/hp9300/pov64_IworkspaceIdocpv989Ieightonews-r7.6-dev_tests-000001"
#define NEW_CONFDIR "/etc" CONFDIR
// test.c
int foo() {
  char confdir[127+1]; // plz ignore the buffer checks
  strcpy(confdir, NEW_CONFDIR);
  // strncpy(confdir, NEW_CONFDIR, sizeof(confdir));
  return 0;
}

// output when strcpy
// objdump -s test.so
// no .rodata section, only .text

Contents of section .text:
 1040 488d3dc1 2f000048 8d05ba2f 00004839  H.=./..H.../..H9
 1050 f8741548 8b056e2f 00004885 c07409ff  .t.H..n/..H..t..
 1060 e00f1f80 00000000 c30f1f80 00000000  ................
 1070 488d3d91 2f000048 8d358a2f 00004829  H.=./..H.5./..H)
 1080 fe4889f0 48c1ee3f 48c1f803 4801c648  .H..H..?H...H..H
 1090 d1fe7414 488b053d 2f000048 85c07408  ..t.H..=/..H..t.
 10a0 ffe0660f 1f440000 c30f1f80 00000000  ..f..D..........
 10b0 f30f1efa 803d4d2f 00000075 2b554883  .....=M/...u+UH.
 10c0 3d1a2f00 00004889 e5740c48 8d3d2e2d  =./...H..t.H.=.-
 10d0 0000e859 ffffffe8 64ffffff c605252f  ...Y....d.....%/
 10e0 0000015d c30f1f00 c30f1f80 00000000  ...]............
 10f0 f30f1efa e977ffff ff554889 e54883ec  .....w...UH..H..
 1100 08488d45 8048ba2f 6574632f 6f707448  .H.E.H./etc/optH
 1110 b92f6870 39333030 2f488910 48894808  ./hp9300/H..H.H.
 1120 48be706f 7636345f 497748bf 6f726b73  H.pov64_IwH.orks
 1130 70616365 48897010 48897818 48ba4964  paceH.p.H.x.H.Id
 1140 6f637076 393848b9 39496569 6768746f  ocpv98H.9Ieighto
 1150 48895020 48894828 48be6e65 77732d72  H.P H.H(H.news-r
 1160 372e48bf 362d6465 765f7465 48897030  7.H.6-dev_teH.p0
 1170 48897838 48ba6576 5f746573 747348b9  H.x8H.ev_testsH.
 1180 2d303030 30303100 4889503b 48894843  -000001.H.P;H.HC
 1190 b8000000 00c9c3                      .......         


// output when strncpy
// objdump -s test.so
// readelf -p ".rodata" test.so
Contents of section .rodata:
 2000 2f657463 2f6f7074 2f687039 3330302f  /etc/opt/hp9300/
 2010 706f7636 345f4977 6f726b73 70616365  pov64_Iworkspace
 2020 49646f63 70763938 39496569 6768746f  Idocpv989Ieighto
 2030 6e657773 2d72372e 362d6465 765f7465  news-r7.6-dev_te
 2040 7374732d 30303030 303100             sts-000001.     

// output when strncpy
// readelf -p ".rodata" test.so
String dump of section '.rodata':
  [     0]  /etc/opt/hp9300/pov64_IworkspaceIdocpv989Ieightonews-r7.6-dev_tests-000001


当我使用 gcc -o test.so -fPIC -shared -g 在 Linux 上编译它并使用 objdump 或字符串检查共享 lib test.so 的字符串常量时,我看到 NEW_CONFDIR 的子字符串,被截断为多个16 字节。

但是,如果我更改代码以使用 strncpy (如上面的代码所示)并使用同一组标志再次编译,它会显示完整的字符串,没有截断。

这是预期的吗?编译器是否对字符串常量进行了任何优化? 或者在这种情况下使用 strcpy 和 strncpy 存在问题及其对共享对象文件的rodata 的影响?

我只关心编译阶段和共享对象的生成,而不关心代码的实际执行。 该工具在共享库的rodata中搜索NEW_CONFDIR。

c gcc shared-libraries strcpy objdump
1个回答
0
投票

我重现了这种行为:获取OP的源代码,使用

gcc -o test.so -fPIC -shared -g
进行编译,运行
strings test.so

_ITM_deregisterTMCloneTable
_ITM_registerTMCloneTable
__cxa_finalize
u+UH
/etc/optH
/hp9300/H
pov64_IwH
orkspaceH
Idocpv98H
9IeightoH
news-r7.H
6-dev_teH
ev_testsH
-000001
;*3$"
GCC: (Debian 13.2.0-5) 13.2.0
...

那么让我们弄清楚发生了什么。

objdump -d test.so
显示:

00000000000010f9 <foo>:
    10f9:       55                      push   %rbp
    10fa:       48 89 e5                mov    %rsp,%rbp
    10fd:       48 83 ec 08             sub    $0x8,%rsp

; RAX = &configdir[0]
    1101:       48 8d 45 80             lea    -0x80(%rbp),%rax 
    1105:       48 ba 2f 65 74 63 2f    movabs $0x74706f2f6374652f,%rdx
    110c:       6f 70 74
    110f:       48 b9 2f 68 70 39 33    movabs $0x2f3030333970682f,%rcx
    1116:       30 30 2f

; copy 8 bytes "/etc/opt" to &confdir[0]
    1119:       48 89 10                mov    %rdx,(%rax)

; copy "/hp9300/" to &confdir[8]
    111c:       48 89 48 08             mov    %rcx,0x8(%rax)

; ... etc.
    1120:       48 be 70 6f 76 36 34    movabs $0x77495f3436766f70,%rsi
    1127:       5f 49 77
    112a:       48 bf 6f 72 6b 73 70    movabs $0x65636170736b726f,%rdi
    1131:       61 63 65
    1134:       48 89 70 10             mov    %rsi,0x10(%rax)
    1138:       48 89 78 18             mov    %rdi,0x18(%rax)
    113c:       48 ba 49 64 6f 63 70    movabs $0x38397670636f6449,%rdx
    1143:       76 39 38
    1146:       48 b9 39 49 65 69 67    movabs $0x6f74686769654939,%rcx
    114d:       68 74 6f
    1150:       48 89 50 20             mov    %rdx,0x20(%rax)
    1154:       48 89 48 28             mov    %rcx,0x28(%rax)
    1158:       48 be 6e 65 77 73 2d    movabs $0x2e37722d7377656e,%rsi
    115f:       72 37 2e
    1162:       48 bf 36 2d 64 65 76    movabs $0x65745f7665642d36,%rdi
    1169:       5f 74 65
    116c:       48 89 70 30             mov    %rsi,0x30(%rax)
    1170:       48 89 78 38             mov    %rdi,0x38(%rax)
    1174:       48 ba 65 76 5f 74 65    movabs $0x73747365745f7665,%rdx
    117b:       73 74 73
    117e:       48 b9 2d 30 30 30 30    movabs $0x3130303030302d,%rcx
    1185:       30 31 00
    1188:       48 89 50 3b             mov    %rdx,0x3b(%rax)
    118c:       48 89 48 43             mov    %rcx,0x43(%rax)
    1190:       b8 00 00 00 00          mov    $0x0,%eax
    1195:       c9                      leave
    1196:       c3                      ret

那么

H
从何而来?

查看从 0x1122 开始的“字符串”常量后面的字节。

MOVABS
指令代码是
0x48
0xbf
,而
0x48
恰好“拼写”
H
,这就是为什么那里有一个
H

有关 AWAVAUATUSH 和类似字符串的相关

answer


那么当您使用

strncpy
时会发生什么?

编译器决定调用外部版本而不是内联

strcpy
:

objdump -d test.so
...
0000000000001109 <foo>:
    1109:       55                      push   %rbp
    110a:       48 89 e5                mov    %rsp,%rbp
    110d:       48 83 c4 80             add    $0xffffffffffffff80,%rsp
    1111:       48 8d 45 80             lea    -0x80(%rbp),%rax
    1115:       ba 80 00 00 00          mov    $0x80,%edx
    111a:       48 8d 0d df 0e 00 00    lea    0xedf(%rip),%rcx        # 2000 <_fini+0xecc>
    1121:       48 89 ce                mov    %rcx,%rsi
    1124:       48 89 c7                mov    %rax,%rdi
    1127:       e8 04 ff ff ff          call   1030 <strncpy@plt>
    112c:       b8 00 00 00 00          mov    $0x0,%eax
    1131:       c9                      leave
    1132:       c3                      ret
© www.soinside.com 2019 - 2024. All rights reserved.