簡體   English   中英

哪種類型的代碼可以動態觸發未對齊的數據訪問sigbus陷阱?

[英]what type of code can trigger unaligned data access sigbus trap dynamically?

我正在尋找有關未對齊數據訪問的SIGBUS。 我正在跟蹤此錯誤之一,我想知道這在西塔拉am335x上是如何發生的。 有人可以給我一個示例代碼來描述或確保觸發它。

添加代碼段:

int Read( void *value, uint32_t *size, const uint32_t baseAddress )
{
    uint8_t *userDataAddress = (uint8_t *)( baseAddress + sizeof( DBANode ));
    memcpy( value, userDataAddress, ourDataSize );
    *size = ourDataSize;
    return 0;
}

DBA節點是一個20字節的類對象。 baseAddress再次是對共享內存文件的mmap,它是強制轉換為uint32_t的DBANode類對象類型的,因此可以執行該算法。

這是本節的重點:

    91a8:   e51b3010    ldr r3, [fp, #-16]
    91ac:   e5933000    ldr r3, [r3]
    91b0:   e51b0014    ldr r0, [fp, #-20]  ; 0xffffffec
    91b4:   e51b1008    ldr r1, [fp, #-8]
    91b8:   e1a02003    mov r2, r3
    91bc:   ebffe72b    bl  2e70 <memcpy@plt>
    91c0:   e51b3010    ldr r3, [fp, #-16]
    91c4:   e5932000    ldr r2, [r3]
    91c8:   e51b3018    ldr r3, [fp, #-24]  ; 0xffffffe8
    91cc:   e5832000    str r2, [r3]

00002e70 <memcpy@plt>:
    2e70:   e28fc600    add ip, pc, #0, 12
    2e74:   e28cca08    add ip, ip, #8, 20  ; 0x8000
    2e78:   e5bcf868    ldr pc, [ip, #2152]!    ; 0x868

當重建完全相同的代碼庫時,問題就消失了。 gcc可以使用為gcc指定的-O0相同的優化來創建2個不同版本的指令嗎?

我還比較了庫,以便在兩個編譯中都將文件obj轉儲。 他們是完全一樣的。 該API經常使用。 但是,崩潰只有在長時間使用后才會發生。 我每500毫秒讀取一次相同的節點。 因此,這是不一致的。 我應該看看指針損壞嗎?

從Cortex-A8技術參考手冊中:

處理器支持未對齊字和半字的加載和存儲。 處理器進行所需數量的內存訪問,並透明地傳輸相鄰字節。

注意跨越單詞邊界的數據訪問可能會增加訪問時間。

將CP15 c1控制寄存器中的A位置1可啟用對齊檢查。 當A位設置為1時,兩種類型的存儲器訪問會產生數據中止信號和對齊故障狀態代碼:

  • 不是半字對齊的16位訪問

  • 未對齊的32位加載或存儲

對齊錯誤檢測是強制性的地址生成功能,而不是外部內存管理硬件的可選支持功能。有關未對齊數據訪問支持的更多信息,請參見《 ARM體系結構參考手冊 》。

如果未與傳輸大小對齊,則從ARM ARM發出總是會產生對齊錯誤的指令:LDREX,STREX,LDREXD,STREXD,LDM,STM,LDRD,RFE,SRS,STRD,SWP,LDC,LDC2,STC,STC2, VLDM,VLDR,VPOP,VPUSH,VSTM,VSTR

另外,大多數PUSH,POP和VLDx都指定了:align:。

進一步,

在包含虛擬化擴展的實現中,對設備或強序內存的未對齊訪問總是會導致對齊錯誤數據中止異常

就像在鏈接的問題中一樣,結構是導致“預期的”未對齊訪問的最明顯方法,但是堆棧指針或其他變量指針的任何損壞也將產生相同的結果。 根據內核的配置方式,會影響正常的單個字/半字訪問速度是否緩慢還是觸發故障。

如果您有權訪問ETM跟蹤,則可以識別確切的訪問。 似乎該零件具有ETM / ETB(因此不需要花哨的跟蹤捕獲設備),但我不知道獲得使用工具的容易程度。

至於什么代碼可以觸發此問題,是的,甚至memcpy()都可能是個問題 由於ARM指令集具有用於傳輸多個寄存器(或AA64中的寄存器對)的優化,因此優化的庫函數將更喜歡“流式傳輸”數據,而不是逐字節地進行加載和存儲。 根據數據結構和編譯目標,完全有可能以非法的LDM結束未對齊的地址。

原來baseAddress是問題所在。 正如我所提到的,它是到mmap可能失敗的共享內存位置的mmap。 失敗的mmap返回-1,並且代碼正在檢查NULL並繼續寫入-1,即0xFFFFFFFF導致sigbus。 使用memcpy時會看到代碼1。 嘗試任何其他訪問方式(如直接字節尋址)都會使sigbus出現代碼3。

我仍然不確定為什么它會觸發SIGBUS而不是SIGSEGV。 難道這不應該是內存沖突嗎? 這是一個例子:

int main(int argc, char **argv)
{
    // Shared memory example                                                    
     const char *NAME = "SharedMemory";                                          
     const int SIZE = 10 * sizeof(uint8_t);                                      
     uint8_t src[]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00};          
     int shm_fd = -1;                                                            

     shm_fd = shm_open(NAME, O_CREAT | O_RDONLY, 0666);                          
     ftruncate(shm_fd, SIZE);                                                    

    // Map shared memory segment to address space                               
     uint8_t *ptr = (uint8_t *) mmap(0, SIZE, PROT_READ | PROT_WRITE | _NOCACHE, MAP_SHARED, shm_fd, 0);
     if(ptr == MAP_FAILED)                                                       
     {                                                                           
          std::cerr << "ERROR in mmap()" << std::endl;                            
      //  return -1;                                                              
      }                                                                           
      printf("ptr = 0x%08x\n",ptr);                                               
      std::cout << "Now storing data to mmap() memory" << std::endl;              
      #if 0                                                                           
      ptr[0] = 0x11;                                                              
      ptr[1] = 0x22;                                                              
      ptr[2] = 0x33;                                                              
      ptr[3] = 0x44;                                                              
      ptr[4] = 0x55;                                                              
      ptr[5] = 0x66;                                                              
      ptr[6] = 0x77;                                                              
      ptr[7] = 0x88;                                                              
      ptr[8] = 0x99;                                                              
      ptr[9] = 0x00;                                                              
      #endif                                                                          

      memcpy(ptr,src,SIZE);   //causes sigbus code 1                              
      shm_unlink(NAME);
}

我仍然不知道為什么mmap不能在shm上失敗,即使我有100MB的可用RAM,並且我的所有資源限制都設置為無限制,而1000 fds限制中仍然有超過400 fds(文件描述符)可用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM