【问题标题】:Bit field ordering on Big-Endian (SPARC) processorBig-Endian (SPARC) 处理器上的位域排序
【发布时间】:2012-12-20 04:57:59
【问题描述】:

考虑下面的代码:

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

#define FORCE_CAST(var, type) *(type*)&var

struct processor_status_register
{
unsigned int cwp:5;
unsigned int et:1;
unsigned int ps:1;
unsigned int s:1;
unsigned int pil:4;
unsigned int ef:1;
unsigned int ec:1;
unsigned int reserved:6;

unsigned int c:1;
unsigned int v:1;
unsigned int z:1;
unsigned int n:1;

unsigned int ver:4;
unsigned int impl:4;
}__attribute__ ((__packed__));



struct registers
{
       unsigned long* registerSet;
       unsigned long* globalRegisters;
       unsigned long* cwptr;
       unsigned long wim, tbr, y, pc, npc;
       unsigned short registerWindows;

       /* Though Intel x86 architecture allows un-aligned memory access, SPARC mandates memory accesses to be 8 byte aligned. Without __attribute__ ((aligned (8))) or a preceding dummy byte e.g. unsigned short dummyByte, the code below crashes with a dreaded Bus error and Core dump. For more details, follow the links below:

        http://blog.jgc.org/2007/04/debugging-solaris-bus-error-caused-by.html
        https://groups.google.com/forum/?fromgroups=#!topic/comp.unix.solaris/8SgFiMudGL4
*/

       struct processor_status_register __attribute__ ((aligned (8))) psr;
}__attribute__ ((__packed__));


int getBit(unsigned long bitStream, int position)
{
int bit;
bit = (bitStream & (1 << position)) >> position;
return bit;
}


char* showBits(unsigned long bitStream, int startPosition, int endPosition)
{
// Allocate one extra byte for NULL character
char* bits = (char*)malloc(endPosition - startPosition + 2);
int bitIndex;
for(bitIndex = 0; bitIndex <= endPosition; bitIndex++)
bits[bitIndex] = (getBit(bitStream, endPosition - bitIndex)) ? '1' : '0';
bits[bitIndex] = '\0';
return bits;
}


int main()
{
struct registers sparcRegisters; short isLittleEndian;

// Check for Endianness
        unsigned long checkEndian = 0x00000001;
        if(*((char*)(&checkEndian)))
            {printf("Little Endian\n"); isLittleEndian = 1;} // Little
Endian architecture detected
        else
            {printf("Big Endian\n"); isLittleEndian = 0;} // Big
Endian architecture detected

unsigned long registerValue = 0xF30010A7;

unsigned long swappedRegisterValue = isLittleEndian ? registerValue :
__builtin_bswap32(registerValue);

sparcRegisters.psr = FORCE_CAST(swappedRegisterValue, struct
processor_status_register);
registerValue = isLittleEndian ? FORCE_CAST (sparcRegisters.psr,
unsigned long) : __builtin_bswap32(FORCE_CAST (sparcRegisters.psr,
unsigned long));
printf("\nPSR=0x%0X, IMPL=%u, VER=%u, CWP=%u\n", registerValue,
sparcRegisters.psr.impl, sparcRegisters.psr.ver,
sparcRegisters.psr.cwp);
printf("PSR=%s\n",showBits(registerValue, 0, 31));

sparcRegisters.psr.cwp = 7;
sparcRegisters.psr.et = 1;
sparcRegisters.psr.ps = 0;
sparcRegisters.psr.s = 1;
sparcRegisters.psr.pil = 0;
sparcRegisters.psr.ef = 0;
sparcRegisters.psr.ec = 0;
sparcRegisters.psr.reserved = 0;
sparcRegisters.psr.c = 0;
sparcRegisters.psr.v = 0;
sparcRegisters.psr.z = 0;
sparcRegisters.psr.n = 0;
sparcRegisters.psr.ver = 3;
sparcRegisters.psr.impl = 0xF;

registerValue = isLittleEndian ? FORCE_CAST (sparcRegisters.psr,
unsigned long) : __builtin_bswap32(FORCE_CAST (sparcRegisters.psr,
unsigned long));

printf("\nPSR=0x%0X, IMPL=%u, VER=%u, CWP=%u\n", registerValue,
sparcRegisters.psr.impl, sparcRegisters.psr.ver,
sparcRegisters.psr.cwp);

printf("PSR=%s\n\n",showBits(registerValue, 0, 31));

return 0;
}  

我在 SPARC 上的 Solaris 10 上使用 gcc-4.7.2 来编译以下内容 生成 Big-Endian 输出的代码:

Big Endian

PSR=0xF30010A7, IMPL=3, VER=15, CWP=20
PSR=11110011000000000001000010100111

PSR=0x3F00003D, IMPL=15, VER=3, CWP=7
PSR=00111111000000000000000000111101

我在 Intel-x86 上的 Ubuntu-10.04 上使用 gcc-4.4 来编译 以下代码生成 Little-Endian 输出:

Little Endian

PSR=0xF30010A7, IMPL=15, VER=3, CWP=7
PSR=11110011000000000001000010100111

PSR=0xF30000A7, IMPL=15, VER=3, CWP=7
PSR=11110011000000000000000010100111

虽然后一个符合预期,但谁能解释一下 大端对应?考虑 showBits() 方法是 正确,PSR=0x3F00003D 如何导致 IMPL=15、VER=3、CWP=7 价值观?位域是如何排列和解释的 Big-Endian 系统上的内存?

【问题讨论】:

    标签: field bit sparc


    【解决方案1】:

    ... PSR=0x3F00003D 会产生 IMPL=15、VER=3、CWP=7 值吗?

    它不能。我不知道您为什么要调用 __builtin_bswap32 但 0x3F00003D 并不代表您初始化 sparcRegisters 结构的内存。

    让我们检查一下这段代码:

    sparcRegisters.psr.cwp = 7;
    sparcRegisters.psr.et = 1;
    sparcRegisters.psr.ps = 0;
    sparcRegisters.psr.s = 1;
    sparcRegisters.psr.pil = 0;
    sparcRegisters.psr.ef = 0;
    sparcRegisters.psr.ec = 0;
    sparcRegisters.psr.reserved = 0;
    sparcRegisters.psr.c = 0;
    sparcRegisters.psr.v = 0;
    sparcRegisters.psr.z = 0;
    sparcRegisters.psr.n = 0;
    sparcRegisters.psr.ver = 3;
    sparcRegisters.psr.impl = 0xF;
    

    个别译文如下:

    7 => 00111
    1 => 1
    0 => 0
    1 => 1
    0 => 0000
    0 => 0
    0 => 0
    0 => 000000
    0 => 0
    0 => 0
    0 => 0
    0 => 0
    3 => 0011
    F => 1111
    

    因此在内存中的结构变为 00111101000000000000000000111111,即大端的 0x3D00003F。

    您可以使用此代码进行确认(在 solaris 中使用 CC 测试):

    #include <stdio.h>
    #include <string.h>
    
    struct processor_status_register
    {
       unsigned int cwp:5;
       unsigned int et:1;
       unsigned int ps:1;
       unsigned int s:1;
       unsigned int pil:4;
       unsigned int ef:1;
       unsigned int ec:1;
       unsigned int reserved:6;
    
       unsigned int c:1;
       unsigned int v:1;
       unsigned int z:1;
       unsigned int n:1;
    
       unsigned int ver:4;
       unsigned int impl:4;
    }__attribute__ ((__packed__));
    
    int getBit(unsigned long bitStream, int position)
    {
       int bit;
       bit = (bitStream & (1 << position)) >> position;
       return bit;
    }
    
    char* showBits(unsigned long bitStream, int startPosition, int endPosition)
    {
       // Allocate one extra byte for NULL character
       static char bits[33];
       memset(bits, 0, 33);
       int bitIndex;
       for(bitIndex = 0; bitIndex <= endPosition; bitIndex++)
       {
          bits[bitIndex] = (getBit(bitStream, endPosition - bitIndex)) ? '1' : '0';
       }
       return bits;
    }
    
    int main()
    {
       processor_status_register psr;
       psr.cwp = 7;
       psr.et = 1;
       psr.ps = 0;
       psr.s = 1;
       psr.pil = 0;
       psr.ef = 0;
       psr.ec = 0;
       psr.reserved = 0;
       psr.c = 0;
       psr.v = 0;
       psr.z = 0;
       psr.n = 0;
       psr.ver = 3;
       psr.impl = 0xF;
    
       unsigned long registerValue = 0;
    
       memcpy(&registerValue, &psr, sizeof(registerValue));
       printf("\nPSR=0x%0X, IMPL=%u, VER=%u, CWP=%u\n", registerValue,
          psr.impl, psr.ver,
          psr.cwp);
    
       printf("PSR=%s\n\n",showBits(registerValue, 0, 31)); 
    
       return 0;
    }
    

    这个的输出是:

    PSR=0x3D00003F, IMPL=15, VER=3, CWP=7
    PSR=00111101000000000000000000111111
    

    【讨论】:

      猜你喜欢
      • 2012-10-09
      • 1970-01-01
      • 2010-10-16
      • 2017-01-03
      • 2020-12-01
      • 2014-02-14
      • 2014-05-25
      • 2018-05-15
      • 1970-01-01
      相关资源
      最近更新 更多