惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
D
DataBreaches.Net
C
Check Point Blog
I
InfoQ
A
About on SuperTechFans
Engineering at Meta
Engineering at Meta
月光博客
月光博客
Recent Announcements
Recent Announcements
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tailwind CSS Blog
Y
Y Combinator Blog
博客园 - Franky
博客园_首页
罗磊的独立博客
量子位
美团技术团队
T
The Blog of Author Tim Ferriss
Last Week in AI
Last Week in AI
大猫的无限游戏
大猫的无限游戏
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Martin Fowler
Martin Fowler
博客园 - 叶小钗
aimingoo的专栏
aimingoo的专栏

faryou的博客

faryou的博客 faryou的博客 faryou的博客 faryou的博客 faryou的博客 faryou的博客-福建行小记 faryou的博客 faryou的博客 faryou的博客 faryou的博客 faryou的博客-夏令营小记 faryou的博客 faryou的博客 faryou的博客 faryou的博客-暑假阶段总结与展望 faryou的博客 faryou的博客 faryou的博客 faryou的博客 台风进行时 faryou的博客 limbo虚拟机初体验&安装Windows NT 4.0 faryou的博客 台风将来时 faryou的博客 faryou的博客 faryou的博客 faryou的博客 出租车上的对话 faryou的博客
【汇编基础教程】再谈栈
作者: faryou · 2026-01-30 · via faryou的博客

前言

两年前,我写过一篇《【汇编学习随记】汇编中栈的定义》,当时是初次接触汇编语言,对于栈的理解仅限于理解这是一种数据结构,自己却没有理解怎么用栈。当时确实是肤浅了。两年后的今天,我总算是搞清楚了汇编中栈究竟是什么,写下来分享给大家。

栈是什么

数据结构上理解栈,我想不必过多解释了,本质就是一块具有特定进出规则的内存空间,在这块空间内遵循数据先进后出的原则。
但我们作为汇编学习者,仅有这些理解是不够的,让我们从8086CPU的角度看看栈。在8086CPU中,提供了一对段寄存器SS和寄存器SP,用于指向栈顶,CPU对栈的两个操作push(入栈)和pop(出栈)都取决于这两个(段)寄存器,但却没有寄存器能用于标识栈底,这意味着如果我们不提前计算好哪些内存单元是栈空间,栈空间到哪里,那么就很容易出现栈顶超界的问题,可能影响到其他内存空间的数据,从而导致程序异常。(这里也体现了汇编语言和高级语言的不同:汇编语言要求你手动把内存空间抠的很细,但是用高级语言编程时肯定不用考虑这些,因为操作系统已经代为安排好了。想想C++ STL库里的那个栈,根本不用想栈顶是否超界对吧)。对此,我们只能在设计程序时就预留好栈。
因为这一特点,通常情况下,我们不会把栈和代码放在一个段里,而是给栈单独开一个段。
化学上常说,性质决定用途。由于栈这一独特的结构,(至少在汇编中)栈通常用于多层循环时,进入内层循环前暂存外层循环的数据,内层循环结束了再将这些数据恢复出来。这是一个编程时的惯例。

实际应用

上一篇文章中的双层循环就是一个不错的例子,这里就不新出题目了,直接搬过来,要求用栈暂存数据~
编程,将datasg段中每个单词改成小写字母(用栈)

assume cs:codesg,ds:datasg,ss:stacksg

stacksg segment
stacksg ends

datasg segment
  db 'Far             '
  db 'You             '
  db 'HJC             '
  db 'BBS             '
datasg ends

codesg segment
  start:
codesg ends
ends start

直接上答案:

assume cs:codesg,ds:datasg,ss:stacksg;三个段寄存器cs、ds、ss分别关联三个段:代码段、数据段、栈段

stacksg segment
  dw 0,0,0,0,0,0,0,0;定义出16个位,刚刚
stacksg ends

datasg segment
  db 'Far             '
  db 'You             '
  db 'HJC             '
  db 'BBS             '
datasg ends

codesg segment

  start:mov bx,0
        mov cx,4
        mov sp,0;标记当前栈底
        
     s0:push cx;进入内层循环前,cx入栈
        mov si,0
        mov cx,3;重置cx,进内层循环
        
      s:mov al,[bx+si]
        or al,00100000b
        mov [bx+si],al
        inc si
        loop s
        
        add bx,16
        pop cx
        loop s0
        
        mov ax,4c00h
        int 21h
codesg ends
end start