2014-10-09 16 views
7

Tôi đang cố hiểu mã lắp ráp này liên quan đến mã C ở trên. Tôi không chắc chắn liệu mình có đi đúng hướng hay không vì vậy có lẽ ai đó có thể giúp tôi hiểu rõ hơn về điều này.Hiểu ngôn ngữ lắp ráp

int silly(int n, int *p) 
{ 
    int val, val2; 
    if (n > 0) 
     val2 = silly(n << 1, &val); 
    else 
     val = val2 = 0; 
    *p = val + val2 + n; 
    return val + val2; 
} 

này mang mã máy sau:

silly: 
pushl %ebp    // Here I am making space for the function on the stack 
movl %esp,%ebp   // Moving the stack pointer where the base pointer is 
subl $20,%esp   // Subtracting 20 from the stack pointer to allocate more space 
pushl %ebx    // Pushing the %ebx register on top of the stack 
movl 8(%ebp),%ebx  // Getting the first argument(which is n) and store it in register %ebx 
testl %ebx,%ebx  // The first if-statement which compares if n > 0 
jle .L3    // Jump if less or equal - meaning if n < 0 then jump to .L3 
addl $-8,%esp   // Add -8 to %esp to allocate more space 
leal -4(%ebp),%eax  // Storing the first local variable (which is val) in %eax 
pushl %eax    // Pushing the register %eax on top of the stack 
leal (%ebx,%ebx),%eax // n + n and stores it as 2n in %eax 
pushl %eax    // Pushing register %eax on top of the stack (Which I find strange 
         // considering that I've just pushed %eax onto the stack above 
call silly    // Call the function silly 
jmp .L4    // Jump to .L4 (Unconditionally) 
.p2align 4,,7   // Don't know what this means. 
.L3:     // .L3 is the else-statement 
xorl %eax,%eax   // Basically making %eax = 0 
movl %eax,-4(%ebp)  // Moving the value in %eax which is 0 to the first local variable 
         // meaning val = 0 
.L4:     // .L4 is the section after the else-statement 
movl -4(%ebp),%edx  // Getting val again and now storing it in %edx 
addl %eax,%edx   // Adding what is in %eax (which is 0) to %edx 
movl 12(%ebp),%eax  // Getting the second parameter (*p) and storing it in %eax 
addl %edx,%ebx   // Adding value from %edx to %ebx - meaning val + n 
movl %ebx,(%eax)  // Moving what is in %ebx and storing it in memory location of %eax 
movl -24(%ebp),%ebx // Getting the second local variable (val2) and moving it to %ebx 
movl %edx,%eax   // Move val to %eax - and the return value will be in %eax 
movl %ebp,%esp   
popl %ebp 
ret 

Tôi cố gắng để quấn quanh đầu tôi và tôi đã chỉ mới bắt đầu suy nghĩ về lắp ráp để gợi ý về đề tài này sẽ thực sự thoải mái. Tôi có một vài câu hỏi tôi cần hỏi về mã lắp ráp này có thể giúp tôi hiểu về chồng:

  • (a) Val biến có được lưu trữ trên ngăn xếp không?
    (b) Nếu vậy, tại những gì oset byte (tương đối so với% ebp) là nó được lưu trữ?
    (c) Tại sao cần lưu trữ nó trên ngăn xếp?

  • (a) Biến val2 được lưu trữ trên ngăn xếp?
    (b) Nếu vậy, tại những gì oset byte (tương đối so với% ebp) là nó được lưu trữ?
    (c) Tại sao cần lưu trữ nó trên ngăn xếp?

  • (a) Điều gì (nếu có) được lưu trữ ở -24 (% ebp)?
    (b) Nếu một cái gì đó được lưu trữ ở đó, tại sao nó là cần thiết để lưu trữ nó?

  • (a) Điều gì (nếu có) được lưu trữ ở -8 (% ebp)?
    (b) Nếu một cái gì đó được lưu trữ ở đó, tại sao nó là cần thiết để lưu trữ nó?

Cảm ơn trước :)

+4

Câu hỏi của bạn chính xác là gì? – o11c

+0

Tôi vừa mới cập nhật câu hỏi. Xin lỗi :) – drleifz

+0

LƯU Ý: 'val2' được uninitialised.Sometimes. Và đôi khi là 'val'. – wildplasser

Trả lời

1

Trước khi trả lời câu hỏi của bạn. Thay vì nhận xét đang làm gì, tôi nhận xét nơi tất cả giá trị nằm trong sổ đăng ký hoặc trên ngăn xếp.

Đối số nằm trên ngăn xếp, giá trị trả lại nằm trong %eax.

Đăng ký %eax, %ecx%edx là người gọi đã được lưu. Tất cả các thanh ghi khác, bao gồm %ebx, %ebp%esp, được lưu trữ theo thứ tự (%edi%esi không được sử dụng).

Ký hiệu của tôi cho ngăn xếp là 4 byte tại một thời điểm và tôi sử dụng ; cho vị trí điểm ebp, nếu đã biết.

silly:      ; eax: ?, ebx: ebx0, edx: ?, stack: [eip0, n, p] 
    pushl %ebp    ; eax: ?, ebx: ebx0, edx: ?, stack: [ebp0, eip0, n, p] 
    movl %esp,%ebp   ; eax: ?, ebx: ebx0, edx: ?, stack: [; ebp0, eip0, n, p] 
    subl $20,%esp   ; eax: ?, ebx: ebx0, edx: ?, stack: [?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    pushl %ebx    ; eax: ?, ebx: ebx0, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    movl 8(%ebp),%ebx  ; eax: ?, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    testl %ebx,%ebx  ; set flags from n 
    jle .L3    ; if flags indicates <= 0, goto .L3, else fallthrough 

          ; set up for calling the function 
    addl $-8,%esp   ; eax: ?, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    leal -4(%ebp),%eax  ; eax: &val, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, (stackeax); ebp0, eip0, n, p] 
    pushl %eax    ; eax: &val, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p] 
    leal (%ebx,%ebx),%eax ; eax: 2*n, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p] 
    pushl %eax    ; eax: 2*n, ebx: n, edx: ?, stack: [2*n, &val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p] 
    call silly    ; pushes eip; args: (2*n, &val); val will be initialized on return 
    jmp .L4    ; 
          ; 
.p2align 4,,7    ; request alignment (there should be one before `silly:` too) 
.L3:      ; 
    xorl %eax,%eax   ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    movl %eax,-4(%ebp)  ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
          ; 
.L4:      ; eax: val2=φ(function result, 0), ebx: n, edx: ?, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl -4(%ebp),%edx  ; eax: val2, ebx: n, edx: val, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    addl %eax,%edx   ; eax: val2, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl 12(%ebp),%eax  ; eax: p, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    addl %edx,%ebx   ; eax: p, ebx: n+val+val2, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl %ebx,(%eax)  ; *p = n+val+val2 
    movl -24(%ebp),%ebx ; eax: p, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl %edx,%eax   ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl %ebp,%esp   ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [; ebp0, eip0, n, p] 
    popl %ebp    ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [eip0, n, p] 
    ret     ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [n, p] 

DỪNG.

Quay lại và đọc lại mã. Bạn chỉ làm tổn thương bản thân nếu bạn không tự mình tìm ra câu trả lời. Nó sẽ dễ dàng với các loại bình luận tôi đã viết.

Nhưng dù sao ...


  1. a. val thường có trên ngăn xếp, tại -4(%ebp). Thời gian duy nhất không nằm trên dòng xorl %eax,%eax
    b. nó được lưu trữ tại -4(%ebp), được minh chứng trên các dòng leal -4(%ebp),%eax, movl %eax,-4(%ebp)movl -4(%ebp),%edx. Ngoài ra, khung trước của val*p
    c. val phải nằm trên ngăn xếp sao cho địa chỉ của nó có thể được thực hiện và chuyển đến cuộc gọi đệ quy.
  2. a. val2 không bao giờ được lưu trữ trên ngăn xếp, mặc dù rất có thể một số trong số đó là ? s là không gian dành riêng cho nó.
    b. nó được lưu trữ trong regixter eax tại .L4, mà trên nhánh đầu tiên của hàm phi là giá trị trả về của cuộc gọi đệ quy, và trên nhánh thứ hai là giá trị 0, cũng được lưu trữ trong val.
    c. val2 không bao giờ cần phải nằm trên ngăn xếp vì địa chỉ của nó không được thực hiện, nó không tồn tại trước cuộc gọi đệ quy để nó không cần phải được lưu, và có rất ít đăng ký sử dụng mà không cần tràn.
  3. a. -24(%ebp) là giá trị đã lưu của %ebx, từ dòng pushl %ebx
    b. %ebx là một đăng ký được lưu trữ bằng callee, vì vậy giá trị của nó phải được giữ nguyên.
  4. a. Không, không có gì ở đó cả.
    b. Nó rất có thể sẽ là val2 nếu nó là cần thiết để tràn. Dự đoán tốt nhất của tôi là ba số khác ? được dành riêng cho các sổ đăng ký được gọi là không được sử dụng-gọi-đệ quy-gọi-đệ quy: %eax, %ecx%edx.
0

Bạn đã yêu cầu rất nhiều.

Tôi sẽ bắt đầu với phần này ...

.p2align 4,,7 // Don't know what this means.

Hiểu; nebulous, phải không!

Trình lập trình (trông giống như trình biên dịch trong trường hợp của bạn) muốn hướng dẫn tại L3: được đặt trên cái được gọi là "ranh giới 16 byte".

Bạn có thể đọc chi tiết về nội dung đó HERE. Nếu điều đó không có ý nghĩa, hãy hỏi lại ở đây và tôi sẽ giải thích thêm một số.

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