2008-11-04 25 views
44

Đã một thời gian kể từ khi tôi lắp ráp bộ mã hóa bằng tay cuối cùng và tôi hơi yếu về chi tiết. Nếu tôi gọi hàm C từ cánh tay, tôi chỉ phải lo lắng về việc tiết kiệm r0-r3 và lr, phải không? Nếu hàm C sử dụng bất kỳ thanh ghi nào khác, nó có chịu trách nhiệm tiết kiệm chúng trên ngăn xếp và khôi phục chúng không? Nói cách khác, trình biên dịch sẽ tạo mã để làm điều này cho các hàm C. Ví dụ nếu tôi sử dụng r10 trong một chức năng lắp ráp, tôi không phải đẩy giá trị của nó trên ngăn xếp, hoặc bộ nhớ, và bật/khôi phục lại nó sau khi một cuộc gọi C, phải không?Quy ước gọi cho ARM đến C, đăng ký để lưu

Điều này dành cho arm-eabi-gcc 4.3.0.

Tôi nhận ra mình có thể đọc toàn bộ EABI, nhưng sau đó rút ngắn RTFM là SO là gì, phải không? :-)

+1

Đây là liên kết bên ngoài có thể hữu ích. [APCS giới thiệu] (http://www.heyrick.co.uk/assembler/apcsintro.html), đặc biệt là một số [tên khác nhau] (http://sourceware.org/ml/binutils/2000-06/msg00240.html) để sử dụng 'register'. –

Trả lời

59

Tùy thuộc vào số ABI cho nền tảng mà bạn đang biên dịch. Trên Linux, có hai ARM ABIs; cái cũ và cái mới. AFAIK, cái mới (EABI) thực ra là AAPCS của ARM. Các định nghĩa EABI hoàn chỉnh hiện đang hoạt động here on ARM's infocenter.

Từ the AAPCS, §5.1.1:

  • r0-r3 là những lập luận và đầu đăng ký; r0-r1 cũng là kết quả đăng ký
  • R4-r8 được callee lưu thanh ghi
  • r9 có thể là một callee lưu đăng ký hay không (trên một số biến thể của AAPCS nó là một thanh ghi đặc biệt)
  • r10-R11 là callee lưu thanh ghi
  • r12-R15 là thanh ghi đặc biệt

Một đăng ký lưu trữ callee phải được lưu bởi callee (đối lập với một đăng ký người gọi lưu, nơi người gọi lưu sổ đăng ký); do đó, nếu đây là ABI bạn đang sử dụng, bạn không phải lưu r10 trước khi gọi một chức năng khác (chức năng khác có trách nhiệm lưu nó).

Chỉnh sửa: Trình biên dịch bạn đang sử dụng không có sự khác biệt; gcc cụ thể có thể được cấu hình cho một số ABI khác nhau và thậm chí nó có thể được thay đổi trên dòng lệnh. Nhìn vào đoạn mở đầu/mã kết xuất nó tạo ra không hữu ích, vì nó được thiết kế riêng cho từng hàm trình biên dịch có thể sử dụng các cách khác để lưu sổ đăng ký (ví dụ, lưu nó ở giữa hàm).

+0

Cảm ơn, điều này dường như đổ chuông. Tôi nghĩ rằng "r0-r4" đầu tiên trong danh sách của bạn là một lỗi đánh máy, phải không? 1 (và có lẽ là câu trả lời hay nhất trừ khi có một bước ngoặt xung quanh) – richq

+0

Vâng, đó là một lỗi đánh máy (và không phải là duy nhất, nhưng tôi đã sửa lỗi khác trước khi nhấn gửi lần đầu tiên - hoặc vì vậy tôi hy vọng). – CesarB

+1

"Bạn có thể tải xuống toàn bộ đặc điểm ABI và các tài liệu hỗ trợ và mã ví dụ của nó dưới dạng lưu trữ ZIP từ trang này". Lưu trữ Zip: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0036b/bsabi.zip – jww

21

Để thêm lên thông tin mất tích trên thanh ghi NEON:

Từ the AAPCS, §5.1.1 thanh ghi Core:

  • r0-r3 là những lập luận và đầu đăng ký; r0-r1 cũng là kết quả đăng ký
  • R4-r8 được callee lưu thanh ghi
  • r9 có thể là một callee lưu đăng ký hay không (trên một số biến thể của AAPCS nó là một thanh ghi đặc biệt)
  • r10-R11 là callee lưu thanh ghi
  • r12-R15 là thanh ghi đặc biệt

Từ AAPCS, §5.1.2.1 VFP đăng ký công ước sử dụng:

  • S16-S31 (D8-D15, q4-q7) phải được bảo quản
  • s0-S15 (d0-d7, q0-q3)D16-D31 (q8-Q15) không cần phải được bảo tồn

Original post:
arm-to-c-calling-convention-neon-registers-to-save

4

Câu trả lời của CesarB và Pavel cung cấp các trích dẫn từ AAPCS, nhưng vẫn còn các vấn đề mở. Callee có tiết kiệm r9 không? Điều gì về r12? Điều gì về r14? Hơn nữa, các câu trả lời là rất chung chung, và không cụ thể cho chuỗi công cụ arm-eabi theo yêu cầu. Dưới đây là một cách tiếp cận thực tế để tìm ra đăng ký nào được lưu trữ và không được đăng ký.

Mã C sau chứa một khối lắp ráp nội tuyến, yêu cầu sửa đổi thanh ghi r0-r12 và r14. Trình biên dịch sẽ tạo mã để lưu các thanh ghi được yêu cầu bởi ABI.

void foo() { 
    asm volatile ("nop" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14"); 
} 

Sử dụng dòng lệnh arm-eabi-gcc-4.7 -O2 -S -o - foo.c và thêm thiết bị chuyển mạch cho nền tảng của bạn (chẳng hạn như -mcpu=arm7tdmi ví dụ). Lệnh sẽ in mã assembly được tạo trên STDOUT. Nó có thể trông giống như sau:

foo: 
    stmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} 
    nop 
    ldmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} 
    bx lr 

Lưu ý rằng trình biên dịch tạo mã tiết kiệm và khôi phục r4-r11. Trình biên dịch không lưu r0-r3, r12. Rằng nó khôi phục r14 (bí danh lr) hoàn toàn ngẫu nhiên như tôi biết từ kinh nghiệm rằng mã thoát cũng có thể tải lr đã lưu vào r0 và sau đó làm một "bx r0" thay vì "bx lr". Hoặc bằng cách thêm -mcpu=arm7tdmi -mno-thumb-interwork hoặc bằng cách sử dụng -mcpu=cortex-m4 -mthumb chúng tôi có được mã lắp ráp hơi khác nhau trông như thế này:

foo: 
    stmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr} 
    nop 
    ldmfd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc} 

Một lần nữa, R4-R11 được lưu và phục hồi. Nhưng r14 (bí danh lr) không được phục hồi.

Để tóm tắt:

  • r0-r3 là không callee-lưu
  • R4-R11 là callee-lưu
  • r12 (bí danh ip) là không callee-lưu
  • r13 (bí danh sp) được lưu lại một cách thoải mái
  • r14 (bí danh lr) là không callee-saved
  • R15 (bí danh pc) là chương trình truy cập và được thiết lập với giá trị của lr trước khi chức năng gọi

này nắm giữ ít nhất là cho mặc định cánh tay-EABI-gcc của của. Có các công tắc dòng lệnh (đặc biệt là công tắc -mabi) có thể ảnh hưởng đến kết quả.

+1

Phân tích của bạn là * đúng *; 'lr' được ** xuất hiện ** làm' pc' để quay lại nhanh hơn. Câu trả lời cho câu hỏi 'r9' của bạn nằm trong [APCS] (http://www.cl.cam.ac.uk/~fms27/teaching/2001-02/arm-project/02-sort/apcs.txt) . Nó được gọi là * cơ sở tĩnh * trong tài liệu này và phần * Reentrant vs Non-Reentrant Code * là tương đối. ** APCS ** hỗ trợ một số cấu hình, nhưng 'gcc' nói chung * tham gia lại * mà không có * giới hạn ngăn xếp *. Đặc biệt, * Có các vai trò dành riêng cho 'sb/r9' và' sl/r10' trong một số biến thể của APCS. Trong các biến thể khác, chúng có thể được sử dụng làm sổ đăng ký được lưu trữ bằng callee * –

+0

Xem [Liên kết ARM và con trỏ khung] (http://stackoverflow.com/questions/15752188/arm-link-register-and-frame-pointer) để biết chi tiết về 'pc' và' lr'. 'r12' còn được gọi là' ip' và có thể được sử dụng trong phần * mở đầu * và * phần kết *. Nó là một đăng ký * dễ bay hơi *. Điều này quan trọng đối với các thường trình đang phân tích cú pháp ngăn xếp cuộc gọi/khung hình. –

+0

Phân tích của tôi liên quan đến 'lr' là gì? Tôi nghĩ bạn đã hiểu sai tôi. Nhưng dù sao, tôi đã trình bày đoạn mã lắp ráp thứ hai như đoạn mã đầu tiên trông giống như 'lr' đã được lưu lại. Tuy nhiên, tôi nghĩ rằng nó không phải là. Có, trong đoạn thứ hai, 'lr' được bật như' pc' như một cách nhanh hơn để quay lại và tôi không giải thích điều đó, nhưng điểm trình bày đoạn thứ hai là nó cho thấy rằng 'lr' không được lưu lại. – Sven

13

Đối với 64-bit ARM, A64 (từ Procedure Call tiêu chuẩn cho ARM Architecture 64-bit)

Có ba mươi mốt, 64-bit, có mục đích chung (số nguyên) đăng ký có thể nhìn thấy các Tập lệnh A64; các nhãn này được gắn nhãn r0-r30. Trong bối cảnh 64 bit, các thanh ghi này thường được gọi bằng cách sử dụng các tên x0-x30; trong bối cảnh 32 bit, thanh ghi được chỉ định bằng cách sử dụng w0-w30. Ngoài ra, một thanh ghi ngăn xếp ngăn xếp, SP, có thể được sử dụng với số lượng lệnh giới hạn.

  • SP Stack Pointer
  • R30 LR, hãy đăng ký
  • R29 FP Các Khung Pointer
  • thanh ghi R19 ... R28 callee-lưu
  • r18 Đăng ký nền tảng, nếu cần thiết; nếu không một đăng ký tạm thời.
  • r17 IP1 Sổ đăng ký tạm thời gọi thủ tục nội bộ thứ hai (có thể được sử dụng bằng mã gọi điện và mã PLT); vào những thời điểm khác có thể được sử dụng làm đăng ký tạm thời.
  • r16 IP0 Thanh ghi đầu tiên gọi thủ tục nội bộ đầu tiên (có thể được sử dụng bằng cách gọi số mặt dán và mã PLT); vào những thời điểm khác có thể được sử dụng làm đăng ký tạm thời.
  • r9 ... R15 đăng ký tạm thời
  • r8 kết quả gián tiếp vị trí đăng ký
  • r0 ... r7 Parameter/kết quả đăng ký

Tám đăng ký đầu tiên, r0-r7, là được sử dụng để chuyển các giá trị đối số vào một chương trình con và trả về các giá trị kết quả từ một hàm. Chúng cũng có thể được sử dụng để giữ các giá trị trung gian trong một thường trình (nhưng, nói chung, chỉ giữa các cuộc gọi chương trình con).

Thanh ghi R16 (IP0)r17 (IP1) có thể được sử dụng bởi một mối liên kết như một thanh ghi đầu giữa một thói quen và bất kỳ chương trình con nó gọi. Chúng cũng có thể được sử dụng trong một thường trình để giữ các giá trị trung gian giữa các cuộc gọi chương trình con.

Vai trò của thanh ghi r18 là nền tảng cụ thể. Nếu một ABI nền tảng có nhu cầu của một mục đích chung đăng ký chuyên dụng để thực hiện liên tiểu bang thủ tục (ví dụ, bối cảnh thread) sau đó nó nên sử dụng đăng ký này cho mục đích đó. Nếu nền tảng ABI không có yêu cầu như vậy, thì nó nên sử dụng r18 như một thanh ghi tạm thời bổ sung. Đặc tả ABI nền tảng phải ghi lại cách sử dụng cho thanh ghi này.

SIMD

Các ARM kiến ​​trúc 64-bit cũng có thêm ba mươi hai thanh ghi, v0-V31, có thể được sử dụng bởi SIMD và các hoạt động Floating-Point. Tên chính xác của thanh ghi sẽ thay đổi cho biết kích thước của truy cập.

Lưu ý: Không giống như trong AArch32, trong AArch64 quan điểm 128-bit và 64-bit của một SIMD và Floating-Point đăng ký không chồng chéo nhiều thanh ghi trong một cái nhìn hẹp hơn, để q1, d1 và s1 tất cả tham khảo vào cùng một mục trong ngân hàng đăng ký.

Tám thanh ghi đầu tiên, v0-v7, được sử dụng để chuyển giá trị đối số vào chương trình con và trả về giá trị kết quả từ hàm. Chúng cũng có thể được sử dụng để giữ các giá trị trung gian trong một thường trình (nhưng, nói chung, chỉ giữa các cuộc gọi chương trình con).

Đăng ký v8-v15 phải được giữ nguyên bởi một sự thoải mái trong các cuộc gọi chương trình con; các thanh ghi còn lại (v0-v7, v16-v31) không cần phải được giữ nguyên (hoặc phải được người gọi giữ lại). Ngoài ra, chỉ 64 bit dưới cùng của mỗi giá trị được lưu trữ trong v8-v15 cần được bảo toàn; đó là trách nhiệm của người gọi để bảo tồn các giá trị lớn hơn.

0

Ngoài ra còn có sự khác biệt ít nhất tại kiến ​​trúc Cortex M3 cho chức năng gọi và ngắt.

Nếu xảy ra gián đoạn, nó sẽ tự động đẩy R0-R3, R12, LR, PC lên ngăn xếp và khi biểu mẫu POP tự động IRQ trả về. Nếu bạn sử dụng các thanh ghi khác trong quy trình IRQ, bạn phải đẩy/bật chúng lên Stack theo cách thủ công.

Tôi không nghĩ rằng PUSH và POP tự động này được thực hiện cho lệnh gọi hàm (lệnh nhảy).Nếu quy ước nói R0-R3 chỉ có thể được sử dụng như một đối số, kết quả hoặc đầu ghi, vì vậy không cần lưu trữ chúng trước khi gọi hàm bởi vì không nên sử dụng bất kỳ giá trị nào sau khi trả về hàm. Nhưng giống như trong một ngắt, bạn phải lưu trữ tất cả các thanh ghi CPU khác nếu bạn sử dụng chúng trong hàm của bạn.

Các vấn đề liên quan