Điều gì xảy ra khi một chương trình máy tính chạy?


180

Tôi biết lý thuyết chung nhưng tôi không thể phù hợp với các chi tiết.

Tôi biết rằng một chương trình nằm trong bộ nhớ thứ cấp của máy tính. Khi chương trình bắt đầu thực thi, nó được sao chép hoàn toàn vào RAM. Sau đó, bộ xử lý lấy lại một vài hướng dẫn (tùy thuộc vào kích thước của bus) tại một thời điểm, đặt chúng vào các thanh ghi và thực thi chúng.

Tôi cũng biết rằng một chương trình máy tính sử dụng hai loại bộ nhớ: stack và heap, cũng là một phần của bộ nhớ chính của máy tính. Ngăn xếp được sử dụng cho bộ nhớ không động và heap cho bộ nhớ động (ví dụ: mọi thứ liên quan đến newtoán tử trong C ++)

Điều tôi không thể hiểu là hai thứ đó kết nối với nhau như thế nào. Tại điểm nào là ngăn xếp được sử dụng để thực hiện các hướng dẫn? Hướng dẫn đi từ RAM, đến ngăn xếp, đến thanh ghi?


43
+1 để hỏi một câu hỏi cơ bản!
mkelley33

21
hmm ... bạn biết đấy, họ viết sách về điều đó Bạn có thực sự muốn nghiên cứu phần này của kiến ​​trúc hệ điều hành với sự trợ giúp của SO không?
Andrey

1
Tôi đã thêm một vài thẻ dựa trên bản chất liên quan đến bộ nhớ của câu hỏi và tham chiếu đến C ++, mặc dù tôi nghĩ rằng một câu trả lời tốt cũng có thể đến từ một người am hiểu về Java hoặc C #!)
mkelley33

14
Nâng cao và ủng hộ. Tôi đã luôn sợ hãi khi hỏi ...
Tối đa

2
Thuật ngữ "đặt chúng trong sổ đăng ký" không hoàn toàn đúng. Trên hầu hết các bộ xử lý, các thanh ghi được sử dụng để giữ các giá trị trung gian, không phải mã thực thi.

Câu trả lời:


161

Nó thực sự phụ thuộc vào hệ thống, nhưng các hệ điều hành hiện đại có bộ nhớ ảo có xu hướng tải hình ảnh quá trình của chúng và phân bổ bộ nhớ giống như thế này:

+---------+
|  stack  |  function-local variables, return addresses, return values, etc.
|         |  often grows downward, commonly accessed via "push" and "pop" (but can be
|         |  accessed randomly, as well; disassemble a program to see)
+---------+
| shared  |  mapped shared libraries (C libraries, math libs, etc.)
|  libs   |
+---------+
|  hole   |  unused memory allocated between the heap and stack "chunks", spans the
|         |  difference between your max and min memory, minus the other totals
+---------+
|  heap   |  dynamic, random-access storage, allocated with 'malloc' and the like.
+---------+
|   bss   |  Uninitialized global variables; must be in read-write memory area
+---------+
|  data   |  data segment, for globals and static variables that are initialized
|         |  (can further be split up into read-only and read-write areas, with
|         |  read-only areas being stored elsewhere in ROM on some systems)
+---------+
|  text   |  program code, this is the actual executable code that is running.
+---------+

Đây là không gian địa chỉ quy trình chung trên nhiều hệ thống bộ nhớ ảo phổ biến. "Lỗ" là kích thước của tổng bộ nhớ của bạn, trừ đi không gian được chiếm bởi tất cả các khu vực khác; điều này mang lại một lượng lớn không gian cho đống phát triển thành. Đây cũng là "ảo", nghĩa là nó ánh xạ tới bộ nhớ thực của bạn thông qua bảng dịch và có thể được lưu trữ thực sự tại bất kỳ vị trí nào trong bộ nhớ thực. Nó được thực hiện theo cách này để bảo vệ một tiến trình truy cập vào bộ nhớ của tiến trình khác và để làm cho mỗi tiến trình nghĩ rằng nó đang chạy trên một hệ thống hoàn chỉnh.

Lưu ý rằng các vị trí của, ví dụ, ngăn xếp và đống có thể theo thứ tự khác nhau trên một số hệ thống (xem câu trả lời của Billy O'Neal bên dưới để biết thêm chi tiết về Win32).

Các hệ thống khác có thể rất khác nhau. Ví dụ, DOS chạy ở chế độ thực và cấp phát bộ nhớ của nó khi chạy các chương trình trông khác nhau nhiều:

+-----------+ top of memory
| extended  | above the high memory area, and up to your total memory; needed drivers to
|           | be able to access it.
+-----------+ 0x110000
|  high     | just over 1MB->1MB+64KB, used by 286s and above.
+-----------+ 0x100000
|  upper    | upper memory area, from 640kb->1MB, had mapped memory for video devices, the
|           | DOS "transient" area, etc. some was often free, and could be used for drivers
+-----------+ 0xA0000
| USER PROC | user process address space, from the end of DOS up to 640KB
+-----------+
|command.com| DOS command interpreter
+-----------+ 
|    DOS    | DOS permanent area, kept as small as possible, provided routines for display,
|  kernel   | *basic* hardware access, etc.
+-----------+ 0x600
| BIOS data | BIOS data area, contained simple hardware descriptions, etc.
+-----------+ 0x400
| interrupt | the interrupt vector table, starting from 0 and going to 1k, contained 
|  vector   | the addresses of routines called when interrupts occurred.  e.g.
|  table    | interrupt 0x21 checked the address at 0x21*4 and far-jumped to that 
|           | location to service the interrupt.
+-----------+ 0x0

Bạn có thể thấy rằng DOS cho phép truy cập trực tiếp vào bộ nhớ hệ điều hành, không có sự bảo vệ nào, điều đó có nghĩa là các chương trình không gian người dùng thường có thể truy cập trực tiếp hoặc ghi đè lên bất cứ thứ gì họ thích.

Tuy nhiên, trong không gian địa chỉ quy trình, các chương trình có xu hướng trông giống nhau, chỉ có chúng được mô tả là phân đoạn mã, phân đoạn dữ liệu, heap, phân đoạn ngăn xếp, v.v., và nó được ánh xạ hơi khác một chút. Nhưng hầu hết các khu vực chung vẫn còn đó.

Khi tải chương trình và các lib được chia sẻ cần thiết vào bộ nhớ và phân phối các phần của chương trình vào đúng khu vực, HĐH bắt đầu thực hiện quy trình của bạn bất cứ nơi nào có phương thức chính và chương trình của bạn tiếp tục từ đó, thực hiện các cuộc gọi hệ thống khi cần thiết nó cần chúng

Các hệ thống khác nhau (được nhúng, bất cứ thứ gì) có thể có các kiến ​​trúc rất khác nhau, chẳng hạn như hệ thống không chồng, hệ thống kiến ​​trúc Harvard (với mã và dữ liệu được giữ trong bộ nhớ vật lý riêng biệt), các hệ thống thực sự giữ BSS trong bộ nhớ chỉ đọc (ban đầu được đặt bởi lập trình viên), v.v ... Nhưng đây là ý chính chung.


Bạn đã nói:

Tôi cũng biết rằng một chương trình máy tính sử dụng hai loại bộ nhớ: stack và heap, cũng là một phần của bộ nhớ chính của máy tính.

"Ngăn xếp" và "đống" chỉ là các khái niệm trừu tượng, chứ không phải (nhất thiết) các "loại" bộ nhớ riêng biệt.

Một ngăn xếp chỉ là một cấu trúc dữ liệu vào trước, ra trước. Trong kiến ​​trúc x86, nó thực sự có thể được xử lý ngẫu nhiên bằng cách sử dụng phần bù từ cuối, nhưng các chức năng phổ biến nhất là PUSH và POP để thêm và xóa các mục khỏi nó, tương ứng. Nó thường được sử dụng cho các biến chức năng-cục bộ (còn gọi là "lưu trữ tự động"), đối số hàm, địa chỉ trả về, v.v. (nhiều hơn bên dưới)

Một "đống" chỉ là một biệt hiệu cho một đoạn bộ nhớ có thể được phân bổ theo yêu cầu, và được giải quyết một cách ngẫu nhiên (có nghĩa là, bạn có thể truy cập vào bất kỳ vị trí trong đó trực tiếp). Nó thường được sử dụng cho các cấu trúc dữ liệu mà bạn phân bổ trong thời gian chạy (trong C ++, sử dụng newdeletemallocvà bạn bè trong C, vv).

Ngăn xếp và đống, trên kiến ​​trúc x86, cả hai đều nằm trong bộ nhớ hệ thống (RAM) của bạn và được ánh xạ thông qua cấp phát bộ nhớ ảo vào không gian địa chỉ quy trình như được mô tả ở trên.

Các thanh ghi (vẫn trên x86), nằm bên trong bộ xử lý (trái ngược với RAM) và được bộ xử lý tải, từ khu vực TEXT (và cũng có thể được tải từ nơi khác trong bộ nhớ hoặc các vị trí khác tùy theo hướng dẫn của CPU được thực hiện). Chúng thực chất chỉ là những vị trí bộ nhớ trên chip rất nhỏ, rất nhanh được sử dụng cho một số mục đích khác nhau.

Bố cục đăng ký phụ thuộc nhiều vào kiến ​​trúc (trên thực tế, các thanh ghi, tập lệnh và bố cục / thiết kế bộ nhớ, chính xác là "kiến trúc" nghĩa là gì, và vì vậy tôi sẽ không mở rộng theo nó, nhưng khuyên bạn nên mở rộng khóa học ngôn ngữ để hiểu chúng tốt hơn.


Câu hỏi của bạn:

Tại điểm nào là ngăn xếp được sử dụng để thực hiện các hướng dẫn? Hướng dẫn đi từ RAM, đến ngăn xếp, đến thanh ghi?

Ngăn xếp (trong các hệ thống / ngôn ngữ có và sử dụng chúng) thường được sử dụng như thế này:

int mul( int x, int y ) {
    return x * y;       // this stores the result of MULtiplying the two variables 
                        // from the stack into the return value address previously 
                        // allocated, then issues a RET, which resets the stack frame
                        // based on the arg list, and returns to the address set by
                        // the CALLer.
}

int main() {
    int x = 2, y = 3;   // these variables are stored on the stack
    mul( x, y );        // this pushes y onto the stack, then x, then a return address,
                        // allocates space on the stack for a return value, 
                        // then issues an assembly CALL instruction.
}

Viết một chương trình đơn giản như thế này, sau đó biên dịch nó thành tập hợp ( gcc -S foo.cnếu bạn có quyền truy cập vào GCC), và hãy xem. Việc lắp ráp là khá dễ dàng để làm theo. Bạn có thể thấy rằng ngăn xếp được sử dụng cho các biến cục bộ của hàm và để gọi các hàm, lưu trữ các đối số của chúng và trả về các giá trị. Đây cũng là lý do tại sao khi bạn làm một cái gì đó như:

f( g( h( i ) ) ); 

Tất cả những thứ này được gọi lần lượt. Đó thực sự là xây dựng một chồng các lệnh gọi hàm và đối số của chúng, thực thi chúng và sau đó bật chúng ra khi nó quay ngược trở lại (hoặc lên;). Tuy nhiên, như đã đề cập ở trên, ngăn xếp (trên x86) thực sự nằm trong không gian bộ nhớ xử lý của bạn (trong bộ nhớ ảo) và do đó, nó có thể được thao tác trực tiếp; đó không phải là một bước riêng trong quá trình thực thi (hoặc ít nhất là trực giao với quy trình).

FYI, ở trên là quy ước gọi C , cũng được sử dụng bởi C ++. Các ngôn ngữ / hệ thống khác có thể đẩy các đối số lên ngăn xếp theo một thứ tự khác và một số ngôn ngữ / nền tảng thậm chí không sử dụng ngăn xếp và thực hiện theo các cách khác nhau.

Cũng lưu ý, đây không phải là dòng thực thi mã C. Trình biên dịch đã chuyển đổi chúng thành các hướng dẫn ngôn ngữ máy trong tệp thực thi của bạn. Sau đó, chúng (thường) được sao chép từ vùng văn bản vào đường ống CPU, sau đó vào các thanh ghi CPU và được thực hiện từ đó. [Điều này không chính xác. Xem phần chỉnh sửa của Ben Voigt bên dưới.]


4
xin lỗi, nhưng một đề xuất cuốn sách tốt sẽ là một câu trả lời tốt hơn, IMO
Andrey

13
Vâng, "RTFM" luôn tốt hơn.
Sdaz MacSk Ribbon

56
@Andrey: có lẽ bạn nên thay đổi nhận xét đó thành "đồng thời, bạn có thể muốn đọc lời giới thiệu cuốn sách hay của mình " .. "có lẽ bạn thực sự nên xem xét việc gắn cờ bài đăng cho sự chú ý của người điều hành hoặc ít nhất là đưa ra lời giải thích về lý do tại sao ý kiến ​​của bạn nên quan trọng với bất cứ ai.
mkelley33

2
Câu trả lời tuyệt vời. Nó chắc chắn đã xóa một số điều cho tôi!
Tối đa

2
@Mikael: Tùy thuộc vào việc triển khai, bạn có thể có bộ đệm ẩn bắt buộc, trong trường hợp bất kỳ dữ liệu nào được đọc từ bộ nhớ, toàn bộ dòng bộ đệm được đọc và bộ đệm được điền. Hoặc có thể cung cấp cho người quản lý bộ đệm một gợi ý rằng dữ liệu sẽ chỉ cần một lần, vì vậy sao chép nó vào bộ đệm không hữu ích. Đó là để đọc. Đối với ghi có bộ đệm ghi lại và ghi lại, ảnh hưởng đến khi bộ điều khiển DMA có thể đọc dữ liệu và sau đó có một loạt các giao thức kết hợp bộ đệm để xử lý nhiều bộ xử lý có bộ đệm riêng. Điều này thực sự xứng đáng với Q. của riêng mình
Ben Voigt

61

Sdaz đã nhận được một số lượng đáng kể các upvote trong một thời gian rất ngắn, nhưng thật đáng buồn là vẫn tồn tại một quan niệm sai lầm về cách các hướng dẫn di chuyển qua CPU.

Câu hỏi được hỏi:

Hướng dẫn đi từ RAM, đến ngăn xếp, đến thanh ghi?

Sdaz nói:

Cũng lưu ý, đây không phải là dòng thực thi mã C. Trình biên dịch đã chuyển đổi chúng thành các hướng dẫn ngôn ngữ máy trong tệp thực thi của bạn. Sau đó, chúng (thường) được sao chép từ vùng văn bản vào đường ống CPU, sau đó vào các thanh ghi CPU và được thực hiện từ đó.

Nhưng điều này là sai. Ngoại trừ trường hợp đặc biệt của mã tự sửa đổi, các hướng dẫn không bao giờ nhập datapath. Và chúng không, không thể, được thực thi từ datapath.

Các thanh ghi CPU x86 là:

  • Đăng ký chung EAX EBX ECX EDX

  • Phân đoạn đăng ký CS DS ES FS GS SS

  • Chỉ mục và con trỏ ESI EDI EBP EIP ESP

  • Chỉ số EFLAGS

Ngoài ra còn có một số thanh ghi dấu phẩy động và SIMD, nhưng với mục đích của cuộc thảo luận này, chúng tôi sẽ phân loại chúng là một phần của bộ đồng xử lý chứ không phải CPU. Đơn vị quản lý bộ nhớ bên trong CPU cũng có một số thanh ghi riêng, một lần nữa chúng ta sẽ coi đó là một đơn vị xử lý riêng biệt.

Không có thanh ghi nào trong số này được sử dụng cho mã thực thi. EIPchứa địa chỉ của lệnh thực thi, không phải chính lệnh đó.

Các hướng dẫn đi qua một con đường hoàn toàn khác trong CPU từ dữ liệu (kiến trúc Harvard). Tất cả các máy hiện tại là kiến ​​trúc Harvard bên trong CPU. Hầu hết những ngày này cũng là kiến ​​trúc Harvard trong bộ nhớ cache. x86 (máy tính để bàn phổ biến của bạn) là kiến ​​trúc Von Neumann trong bộ nhớ chính, nghĩa là dữ liệu và mã được đặt xen kẽ trong RAM. Đó là vấn đề bên cạnh, vì chúng ta đang nói về những gì xảy ra bên trong CPU.

Trình tự cổ điển được dạy trong kiến ​​trúc máy tính là tìm nạp-giải mã-thực thi. Bộ điều khiển bộ nhớ tra cứu lệnh được lưu trữ tại địa chỉ EIP. Các bit của lệnh đi qua một số logic tổ hợp để tạo ra tất cả các tín hiệu điều khiển cho các bộ ghép kênh khác nhau trong bộ xử lý. Và sau một số chu kỳ, đơn vị logic số học đến một kết quả, được đưa vào đích. Sau đó, hướng dẫn tiếp theo được lấy.

Trên một bộ xử lý hiện đại, mọi thứ hoạt động hơi khác một chút. Mỗi hướng dẫn đến được dịch thành một loạt các hướng dẫn vi mã. Điều này cho phép đường ống, bởi vì các tài nguyên được sử dụng bởi vi cấu trúc đầu tiên không cần thiết sau này, vì vậy họ có thể bắt đầu làm việc với vi cấu trúc đầu tiên từ hướng dẫn tiếp theo.

Trên hết, thuật ngữ hơi bị nhầm lẫn vì đăng ký là một thuật ngữ kỹ thuật điện cho một bộ sưu tập D-flipflops. Và các hướng dẫn (hoặc đặc biệt là các vi lệnh) rất có thể được lưu trữ tạm thời trong một bộ sưu tập D-flipflops như vậy. Nhưng đây không phải là ý nghĩa khi một nhà khoa học máy tính hoặc kỹ sư phần mềm hoặc nhà phát triển chạy bộ sử dụng thanh ghi thuật ngữ . Chúng có nghĩa là các thanh ghi datapath như được liệt kê ở trên, và chúng không được sử dụng để vận chuyển mã.

Tên và số lượng thanh ghi datapath khác nhau đối với các kiến ​​trúc CPU khác, chẳng hạn như ARM, MIPS, Alpha, PowerPC, nhưng tất cả chúng đều thực hiện các lệnh mà không chuyển chúng qua ALU.


Cảm ơn bạn đã làm rõ. Tôi đã do dự để thêm rằng vì tôi không quen thuộc lắm với nó, nhưng đã làm nó theo yêu cầu của người khác.
Sdaz MacSk Ribbon

s / ARM / RAM / in "có nghĩa là dữ liệu và mã được đặt xen kẽ trong ARM". Đúng?
Bjarke Freund-Hansen

@bjarkef: Lần đầu có, nhưng không phải lần thứ hai. Tôi sẽ sửa chữa nó.
Ben Voigt

17

Bố cục chính xác của bộ nhớ trong khi một quá trình đang thực thi hoàn toàn phụ thuộc vào nền tảng mà bạn đang sử dụng. Hãy xem xét chương trình kiểm tra sau:

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

int main()
{
    int stackValue = 0;
    int *addressOnStack = &stackValue;
    int *addressOnHeap = malloc(sizeof(int));
    if (addressOnStack > addressOnHeap)
    {
        puts("The stack is above the heap.");
    }
    else
    {
        puts("The heap is above the stack.");
    }
}

Trên Windows NT (và đó là trẻ em), chương trình này thường sẽ sản xuất:

Heap nằm trên stack

Trên các hộp POSIX, nó sẽ nói:

Ngăn xếp nằm trên đống

Mô hình bộ nhớ UNIX được giải thích khá rõ ở đây bởi @Sdaz MacSk Ribbon, vì vậy tôi sẽ không nhắc lại ở đây. Nhưng đó không phải là mô hình bộ nhớ duy nhất. Lý do POSIX yêu cầu mô hình này là cuộc gọi hệ thống sbrk . Về cơ bản, trên hộp POSIX, để có thêm bộ nhớ, một quy trình chỉ yêu cầu Kernel di chuyển dải phân cách giữa "lỗ" và "đống" hơn nữa vào vùng "lỗ". Không có cách nào để trả lại bộ nhớ cho hệ điều hành và bản thân hệ điều hành không quản lý được heap của bạn. Thư viện thời gian chạy C của bạn phải cung cấp điều đó (thông qua malloc).

Điều này cũng có ý nghĩa đối với loại mã thực sự được sử dụng trong các tệp nhị phân POSIX. Các hộp POSIX (gần như phổ biến) sử dụng định dạng tệp ELF. Trong định dạng này, hệ điều hành chịu trách nhiệm liên lạc giữa các thư viện trong các tệp ELF khác nhau. Do đó, tất cả các thư viện đều sử dụng mã độc lập với vị trí (Nghĩa là bản thân mã có thể được tải vào các địa chỉ bộ nhớ khác nhau và vẫn hoạt động) và tất cả các cuộc gọi giữa các thư viện được chuyển qua bảng tra cứu để tìm ra nơi điều khiển cần nhảy qua chức năng thư viện gọi. Điều này thêm một số chi phí và có thể được khai thác nếu một trong các thư viện thay đổi bảng tra cứu.

Mô hình bộ nhớ của Windows là khác nhau vì loại mã mà nó sử dụng là khác nhau. Windows sử dụng định dạng tệp PE, để lại mã ở định dạng phụ thuộc vào vị trí. Đó là, mã phụ thuộc vào vị trí chính xác trong bộ nhớ ảo mà mã được tải. Có một cờ trong thông số PE thông báo cho HĐH nơi chính xác trong bộ nhớ mà thư viện hoặc tệp thực thi muốn được ánh xạ khi chương trình của bạn chạy. Nếu một chương trình hoặc thư viện không thể tải tại địa chỉ ưa thích của nó, Windows loader phải rebasethư viện / thực thi - về cơ bản, nó di chuyển mã phụ thuộc vào vị trí để trỏ đến các vị trí mới - không yêu cầu bảng tra cứu và không thể khai thác vì không có bảng tra cứu để ghi đè. Thật không may, điều này đòi hỏi phải thực hiện rất phức tạp trong trình tải Windows và có thời gian khởi động đáng kể nếu một hình ảnh cần phải được khởi động lại. Các gói phần mềm thương mại lớn thường sửa đổi thư viện của họ để bắt đầu có chủ đích tại các địa chỉ khác nhau để tránh bị đánh lại; chính các cửa sổ thực hiện điều này với các thư viện riêng của nó (ví dụ: ntdll.dll, kernel32.dll, psapi.dll, v.v. - tất cả đều có địa chỉ bắt đầu khác nhau theo mặc định)

Trên Windows, bộ nhớ ảo được lấy từ hệ thống thông qua một cuộc gọi đến VirtualAlloc và nó được trả về hệ thống thông qua VirtualFree (Được rồi, về mặt kỹ thuật VirtualAlloc cung cấp cho NtAllocateVirtualMemory, nhưng đó là chi tiết triển khai) (Tương phản điều này với POSIX, nơi bộ nhớ không thể được khai hoang). Quá trình này diễn ra chậm (và IIRC, yêu cầu bạn phân bổ trong các phần có kích thước trang vật lý, thường là 4kb trở lên). Windows cũng cung cấp các hàm heap riêng của nó (HeapAlloc, HeapFree, v.v.) như một phần của thư viện có tên RtlHeap, được bao gồm như một phần của chính Windows, trong đó thời gian chạy C (nghĩa là mallocvà bạn bè) thường được triển khai.

Windows cũng có khá nhiều API phân bổ bộ nhớ kế thừa từ những ngày nó phải xử lý 80386 cũ và các chức năng này hiện được xây dựng dựa trên RtlHeap. Để biết thêm thông tin về các API khác nhau kiểm soát việc quản lý bộ nhớ trong Windows, hãy xem bài viết MSDN này: http://msdn.microsoft.com/en-us/l Library / ms810627 .

Cũng lưu ý rằng điều này có nghĩa là trên Windows một quy trình duy nhất (và thường là) có nhiều hơn một đống. (Thông thường, mỗi thư viện dùng chung sẽ tạo ra một đống riêng.)

(Hầu hết các thông tin này đến từ "Mã hóa bảo mật trong C và C ++" của Robert Seacord)


Thông tin tuyệt vời, cảm ơn! Hy vọng "user487117" cuối cùng thực sự quay trở lại. :-)
Sdaz MacSk Ribbon

5

Chồng

Trong kiến ​​trúc X86, CPU thực hiện các hoạt động với các thanh ghi. Các ngăn xếp chỉ được sử dụng vì lý do thuận tiện. Bạn có thể lưu nội dung của các thanh ghi của mình để xếp chồng lên nhau trước khi gọi một chương trình con hoặc một hàm hệ thống và sau đó tải chúng trở lại để tiếp tục hoạt động của bạn ở nơi bạn rời đi. (Bạn có thể sử dụng thủ công mà không cần ngăn xếp, nhưng đây là chức năng được sử dụng thường xuyên để có hỗ trợ CPU). Nhưng bạn có thể làm khá nhiều thứ mà không cần stack trong PC.

Ví dụ: phép nhân số nguyên:

MUL BX

Đa số đăng ký AX với đăng ký BX. (Kết quả sẽ là DX và AX, DX chứa các bit cao hơn).

Các máy dựa trên ngăn xếp (như JAVA VM) sử dụng ngăn xếp cho các hoạt động cơ bản của chúng. Phép nhân trên:

DMUL

Điều này hiện ra hai giá trị từ đỉnh ngăn xếp và nhân tem, sau đó đẩy kết quả trở lại ngăn xếp. Stack là cần thiết cho loại máy này.

Một số ngôn ngữ lập trình cấp cao hơn (như C và Pascal) sử dụng phương thức sau này để truyền tham số cho các hàm: các tham số được đẩy vào ngăn xếp theo thứ tự từ trái sang phải và được bật bởi thân hàm và các giá trị trả về được đẩy lùi. (Đây là một lựa chọn mà các nhà sản xuất trình biên dịch thực hiện và loại lạm dụng cách X86 sử dụng ngăn xếp).

Đống

Heap là một khái niệm khác chỉ tồn tại trong lĩnh vực của trình biên dịch. Việc xử lý bộ nhớ đằng sau các biến của bạn mất đi, nhưng nó không phải là chức năng của CPU hay HĐH, nó chỉ là một sự lựa chọn của việc quản lý khối mà bộ nhớ được đưa ra bởi HĐH. Bạn có thể làm điều này nhiều lần nếu bạn muốn.

Truy cập tài nguyên hệ thống

Hệ điều hành có giao diện chung để bạn có thể truy cập các chức năng của nó. Trong các tham số DOS được truyền vào các thanh ghi của CPU. Windows sử dụng ngăn xếp để truyền tham số cho các chức năng của HĐH (API Windows).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.