OpenWatcom是否支持与ELF弱符号等价的符号:

64jmpszr  于 2023-05-22  发布在  其他
关注(0)|答案(1)|浏览(84)

我有两个C源文件:

/* w1.c */
#include <stdio.h>
__attribute__((weak)) void fw(void) { printf("FW1\n"); }
int main(int argc, char **argv) {
  (void)argc; (void)argv;
  fw();
  return 0;
}
/* w2.c */
#include <stdio.h>
void fw(void) { printf("FW2\n"); }

如果我使用gcc编译并运行它们,则会打印FW1或FW2,具体取决于是否使用w2.c:

$ gcc -s -O2 -o prog1 w1.c
$ ./prog1
FW1
$ gcc -s -O2 -o prog12 w1.c w2.c
$ ./prog12
FW2

这是这样工作的,因为在 w1.c 中,符号 fw 是弱的,所以如果另一个文件(即 w2.c)定义了一个同名的非弱符号。
因此,仅仅是 w2.c 的存在就可以通过 w1.c 中定义的弱符号来修改 w1.c 的行为。
OpenWatcom C编译器有类似的东西吗?__attribute__((weak))的语法是什么?简单地省略__attribute__((weak))是行不通的,因为重复的符号会导致链接失败。我希望上面的编译器命令和程序./prog1./prog12)使用owcc而不是gcc,并可能添加一些标志。
我需要这个,因为我想实现一个清理机制(调用函数 fw),如果还使用了其他源(或对象)文件,它应该自动替换为更复杂的东西。因此,我需要两个清理机制的实现(简单的 fww1.c 中,复杂的 fww2.c 中)。

rryofs0p

rryofs0p1#

几种方法来获得一个弱符号,而不知道owcc...
1.生成并修改.s文件
1.使用实用程序修改ELF .o文件
这样我们就能达成共识了我们需要一种方法来确定我们想要哪些符号是弱的。
我们可以扫描源文件,查找owcc将忽略的“指令”。
特别的评论往往是好的:

// .weak fw
void
fw(void)
{
}

或者,我们可以使用一个“假”宏:

#define WEAK /**/

WEAK
void
fw(void)
{
}

或者,我们可以有一个列出弱符号的weak.txt文件。
无论哪种方式,现在转换器知道要更改哪些符号……

修改生成的汇编器,添加.weak指令

我从github repo中提取了watcom的源代码。当然,watcom汇编程序相对简单。
owcc使用什么汇编程序?它可以使用gcc et附带的GNU as吗?al.?
我猜它可以,因为弱符号[通常]是ELF的特征。我还假设owcc的本机汇编程序不支持它们。
如果我们可以使用GNU as,那么就有一种方法。看看.s,它来自gcc下的w1.c的构建。
通常,我们得到:

.globl fw

但是,请注意,我们刚刚得到:

.weak fw

我们可以告诉owcc生成汇编器源代码。然后,编辑它并更改我们想要弱的任何符号的指令。然后,从.s构建
为了方便起见,这些步骤可以隐藏在脚本中。

使用实用程序更改ELF可重定位中的符号绑定

同样,我假设我们有一个ELF可重定位。
下面是来自您的源代码 * 的readelf -s,不带 * __attribute__((weak))

Symbol table '.symtab' contains 13 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS s1.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    9
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT   10
     9: 0000000000000000     0 SECTION LOCAL  DEFAULT    8
    10: 0000000000000000    10 FUNC    GLOBAL DEFAULT    1 fw
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND puts
    12: 0000000000000000    21 FUNC    GLOBAL DEFAULT    6 main

请注意,fw的绑定为GLOBAL
这里是这里是readelf -s从您的源 * 与 * 的__attribute__((weak))

Symbol table '.symtab' contains 13 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS w1.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    9
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT   10
     9: 0000000000000000     0 SECTION LOCAL  DEFAULT    8
    10: 0000000000000000    10 FUNC    WEAK   DEFAULT    1 fw
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND puts
    12: 0000000000000000    16 FUNC    GLOBAL DEFAULT    6 main

请注意,fw的绑定是WEAK
有各种ELF实用程序允许操作.o文件。应该有一个可以改变符号属性的方法来改变WEAK的绑定。
或者,看看man 5 elflibelf。我们可以编写自己的实用程序。网上应该有很多例子可以[轻松]修改。
这是源代码的修改版本(例如:com.c):

/* com.c */
#if 0
#include <stdio.h>
#endif

#if WEAK
#define BIND    __attribute__((weak))
#else
#define BIND    /**/
#endif

BIND
void
fw(void)
{
#if 0
    printf("FW1\n");
#endif
}

#if 0
int
main(int argc, char **argv)
{
    (void) argc;
    (void) argv;
    fw();
    return 0;
}
#endif

下面是我运行的一些命令:

cc -O2 -DWEAK=0 com.c -o st.s -S
cc -O2 -DWEAK=0 com.c -o st.o -c
cc -O2 -DWEAK=1 com.c -o wk.s -S
cc -O2 -DWEAK=1 com.c -o wk.o -c

然后我对st.owk.o的十六进制转储进行了比较:

--- sdcmp0
+++ sdcmp1
@@ -20,7 +20,7 @@
 00000130: 00000000 03000600 00000000 00000000  ................
 00000140: 00000000 00000000 00000000 03000400  ................
 00000150: 00000000 00000000 00000000 00000000  ................
-00000160: 07000000 12000100 00000000 00000000  ................
+00000160: 07000000 22000100 00000000 00000000  ...."...........
 00000170: 01000000 00000000 00636F6D 2E630066  .........com.c.f
 00000180: 77000000 00000000 20000000 00000000  w....... .......
 00000190: 02000000 02000000 00000000 00000000  ................

因此,GLOBALWEAK之间的差异是单个位/字节。也就是说,global是0x 12,weak是0x 22。
我们可以通过查看/usr/include/elf.h的一部分来理解这一点:

/* How to extract and insert information held in the st_info field.  */

#define ELF32_ST_BIND(val)      (((unsigned char) (val)) >> 4)
#define ELF32_ST_TYPE(val)      ((val) & 0xf)
#define ELF32_ST_INFO(bind, type)   (((bind) << 4) + ((type) & 0xf))

/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
#define ELF64_ST_BIND(val)      ELF32_ST_BIND (val)
#define ELF64_ST_TYPE(val)      ELF32_ST_TYPE (val)
#define ELF64_ST_INFO(bind, type)   ELF32_ST_INFO ((bind), (type))

/* Legal values for ST_BIND subfield of st_info (symbol binding).  */

#define STB_LOCAL   0       /* Local symbol */
#define STB_GLOBAL  1       /* Global symbol */
#define STB_WEAK    2       /* Weak symbol */
#define STB_NUM     3       /* Number of defined types.  */
#define STB_LOOS    10      /* Start of OS-specific */
#define STB_GNU_UNIQUE  10      /* Unique symbol.  */
#define STB_HIOS    12      /* End of OS-specific */
#define STB_LOPROC  13      /* Start of processor-specific */
#define STB_HIPROC  15      /* End of processor-specific */

/* Legal values for ST_TYPE subfield of st_info (symbol type).  */

#define STT_NOTYPE  0       /* Symbol type is unspecified */
#define STT_OBJECT  1       /* Symbol is a data object */
#define STT_FUNC    2       /* Symbol is a code object */
#define STT_SECTION 3       /* Symbol associated with a section */
#define STT_FILE    4       /* Symbol's name is file name */
#define STT_COMMON  5       /* Symbol is a common data object */
#define STT_TLS     6       /* Symbol is thread-local data object*/
#define STT_NUM     7       /* Number of defined types.  */
#define STT_LOOS    10      /* Start of OS-specific */
#define STT_GNU_IFUNC   10      /* Symbol is indirect code object */
#define STT_HIOS    12      /* End of OS-specific */
#define STT_LOPROC  13      /* Start of processor-specific */
#define STT_HIPROC  15      /* End of processor-specific */

相关问题