首页 > 解决方案 > FILE 结构在操作系统和体系结构之间是否一致?

问题描述

对于以下 C 代码片段,LLVM 将生成下面的 IR。

#include <stdio.h>
#include <stdlib.h>

int main(){
  printf("Hello world\n");
  fflush(NULL);
  return 0;
}
; ModuleID = 'a.c'
source_filename = "a.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"

%struct.__sFILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, %struct.__sFILEX*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64 }
%struct.__sFILEX = type opaque
%struct.__sbuf = type { i8*, i32 }

@str = private unnamed_addr constant [12 x i8] c"Hello world\00", align 1

; Function Attrs: nounwind ssp uwtable
define i32 @main() local_unnamed_addr #0 {
  %1 = tail call i32 @puts(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @str, i64 0, i64 0))
  %2 = tail call i32 @fflush(%struct.__sFILE* null)
  ret i32 0
}

; Function Attrs: nounwind
declare i32 @fflush(%struct.__sFILE* nocapture) local_unnamed_addr #1

; Function Attrs: nounwind
declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #2

attributes #0 = { nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "darwin-stkchk-strong-link" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "probe-stack"="___chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "darwin-stkchk-strong-link" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "probe-stack"="___chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }

!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}

!0 = !{i32 2, !"SDK Version", [3 x i32] [i32 10, i32 15, i32 4]}
!1 = !{i32 1, !"wchar_size", i32 4}
!2 = !{i32 7, !"PIC Level", i32 2}
!3 = !{!"Apple clang version 11.0.3 (clang-1103.0.32.59)"}

我可以认为相应 FILE 结构的结构声明在不同操作系统之间是一致的吗?有没有一种编程方式来获取这个结构的 LLVM 表示?

标签: cllvmllvm-ir

解决方案


FILE *作为用户和操作系统之间的变量,后面的类型结构对您来说是不透明的。

更正式地说,它取决于您使用的 C(或 C++)编译器和支持库,但这通常是每个硬件和操作系统组合一个库,除了可能同时支持 32 位和 64 位的系统位代码。

一些程序 (Perl) 准备在配置阶段在不同机器上的结构内部进行探索,但它们这样做是在内部知识的情况下进行的。没有标准结构,除非像 GNU C 库这样的库可以跨机器对其进行标准化。但是假设它在任何地方都不一样是最安全的。

为了反驳Asadefa在他们的回答中提出的乐观观点,下面是 AIX 7.2 中的结构定义:

#if defined(__64BIT__) || defined(__ia64)
typedef struct {
    unsigned char   *_ptr;
    unsigned char   *_base;
    unsigned char   *_bufendp;
    char    *__newbase;
    void    *_lock;
    int _cnt;
    int _file;
    int __stdioid;
    short   _flag;
    short   _unused;
    long    _unused1[4];
} FILE;
#else /* 32-bit POWER */
typedef struct {
    unsigned char   *_ptr;
    int _cnt;
    unsigned char   *_base;
    unsigned char   *_bufendp;
    short   _flag;
    short   _file;
    int __stdioid;
    char    *__newbase;
    void    *_lock;
} FILE;
#endif /* __64BIT__ || __ia64 */

这在单个操作系统上的 32 位和 64 位之间有所不同,并且与 Linux 和 macOS 上的结构完全无关。

Solaris 10 上的结构再次不同——使用了一些其他的不使用的位域:

struct __FILE_TAG   /* needs to be binary-compatible with old versions */
{
#ifdef _STDIO_REVERSE
    unsigned char   *_ptr;  /* next character from/to here in buffer */
    int     _cnt;   /* number of available characters in buffer */
#else
    int     _cnt;   /* number of available characters in buffer */
    unsigned char   *_ptr;  /* next character from/to here in buffer */
#endif
    unsigned char   *_base; /* the buffer */
    unsigned char   _flag;  /* the state of the stream */
    unsigned char   _file; /* Old home of the file descriptor */
                /* Only fileno(3C) can retrieve the value now */
    unsigned    __orientation:2; /* the orientation of the stream */
    unsigned    __ionolock:1;   /* turn off implicit locking */
    unsigned    __seekable:1;   /* is file seekable? */
    unsigned    __extendedfd:1; /* enable extended FILE */
    unsigned    __xf_nocheck:1; /* no extended FILE runtime check */
    unsigned    __filler:10;
};

而我在 HP-UX 11.31 上找到的版本又不一样了:

   typedef struct {
    int      __cnt;
    unsigned char   *__ptr;
    unsigned char   *__base;
    unsigned short   __flag;
    unsigned char    __fileL;       /* low byte of file desc */
    unsigned char    __fileH;       /* high byte of file desc */
   } FILE;

当然,如果您的雷达屏幕上没有 Solaris、HP-UX、AIX,您可能会得出不同的结论,但不同系统之间肯定存在巨大差异。


推荐阅读