堆栈执行

Gentoo Logo

The GNU Stack Quickstart

Content:

1.  Introduction

With the rise of mainstream consumer machines with hardware stack protection (e.g. the NX bit on amd64), we developers have to be doubly sure that our packages build with the correct stack settings. Keep in mind that stack protection is an issue for all architectures, not just x86 or amd64.

The purpose of this document is to help package maintainers fix their packages when they break. We will be focusing our attention on the GNU_STACK ELF marking. ELF is simply a file format which all modern linux distros use. An ELF can be an executable (say /bin/ls) or a library (say /lib/libncurses.so). GNU_STACK is just an ELF program header which tells the system how to control the stack when the ELF is loaded into memory.

Before getting started, you should read through the Wikipedia entry on the NX bit. You can skip it of course if you're already familiar with the concept of executable versus non-executable stacks.

2.  Causes of executable stack markings

ELF files end up with executable stack markings in one of three ways:

  1. GCC generates code that uses executable stack
  2. an object built from assembler source includes a marking indicating to the linker that it needs an executable stack (the GNU-stack note set for executable stack)
  3. an object built from assembler source is missing the GNU-stack note; a very common occurrence especially for code expected to work on many platforms

GCC generates code to be executed on the stack when it implements a trampoline for nested functions. To remove the need for an executable stack in this case, it is necessary to rewrite the code another way. Sometimes this is relatively easy, other times not.

If an assembler source file includes a GNU-stack note that indicates it needs an executable stack, presumably this is by design. Again, in order to remove the need for an executable stack, the code probably needs to be rewritten.

If an assembler source contains no GNU-stack note, the system by default assumes that an executable stack may be required. However, usually if there's no GNU-stack note, this is simply because the author didn't include one, rather than the code actually needing an executable stack.

In the first two cases above, the executable stack marking is correct, and should only be removed by rewriting the code to eliminate the executable stack requirement. Such rewriting has to be considered on a case-by-case basis and is outside the scope of this document, at least for now. Here we focus on the third case, where the upstream author has not indicated whether the assembler object needs an executable stack; fixing this means adding the GNU-stack note to the source to indicate an executable stack is not necessary.

3.  Finding ELFs that ask for an executable stack

Before you can start fixing something, you have to make sure it's broken first, right? For this reason, we've developed a suite of tools named PaX Utilities. If you are not familiar with these utilities, you should read the PaX Utilities Guide now. Gentoo users can simply do emerge pax-utils. Non-Gentoo users s

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 的输入框可以接收用户输入的数字和运算符,用户输入后,程序会将其压入相应的堆栈中。当用户点击“=”按钮时,程序会从堆栈中依次取出数字和运算符,按照运算符的优先级进行计算,最终得出结果并显示在计算器的最下方输出框中。 设计这款计算器需要考虑以下几个方面: 1. 如何判断用户输入的是数字还是运算符? 可以通过判断输入的字符是否为数字或者运算符来区分。如果是数字,则将其转换为整数并压入数字堆栈中;如果是运算符,则将其压入运算符堆栈中。 2. 如何处理运算符的优先级? 可以将运算符按照优先级从高到低依次压入运算符堆栈中。当需要进行计算时,从运算符堆栈中取出一个运算符,再从数字堆栈中取出两个数字进行计算,将计算结果压入数字堆栈中。如果运算符堆栈中还有运算符,则继续取出运算符进行计算,直到运算符堆栈为空为止。 3. 如何处理错误输入? 需要对用户输入进行合法性检查,如果输入的字符不是数字或者运算符,则提示用户输入有误。如果用户输入的运算符不支持,则提示用户该运算符不支持。 4. 如何处理除数为的情况? 需要在进行除法运算时进行判断,如果除数为,则提示用户除数不能为。 通过以上几个方面的考虑,可以设计出一款简单的利用堆栈执行的计算器,帮助初学数据结构的小伙伴更好地理解堆栈的应用。 ### 回答2: 首先,我们需要了解堆栈stack)的概念。堆栈是一种特殊的线性数据结构,只允许在一端进行插入和删除操作,这一端被称为栈顶。该数据结构的特点是先进后出,后进先出的顺序。 接下来,我们可以开始设计计算器。首先,需要设计一个函数来将表达式转换成逆波兰表达式,也就是将中缀表达式转换成后缀表达式。这个过程可以使用堆栈来完成。具体方法如下: 1. 从左往右遍历中缀表达式的每一个元素,若该元素为数字则直接输出到结果中,若为运算符则执行以下步骤: 2. 若该运算符为“(”,则将其压入s2堆栈中; 3. 若该运算符为“)”,则将s2中的运算符弹出并压入s1中,直到遇到左括号,将左括号弹出丢弃; 4. 若该运算符的优先级比栈顶运算符的优先级高,则将其压入s2堆栈中; 5. 若该运算符的优先级比栈顶运算符的优先级低或相等,则将s2中的运算符弹出并压入s1中,重复步骤4,直到该运算符可以压入s2堆栈为止; 6. 当表达式遍历完后,若s2中仍然有运算符,则将它们依次弹出并压入s1中。 接下来,我们可以设计一个函数来计算后缀表达式的值。具体方法如下: 1. 从左往右遍历后缀表达式的每一个元素,若该元素为数字则压入s1堆栈中,若为运算符则执行以下步骤: 2. 从s1堆栈中弹出两个数字,分别为a和b; 3. 根据该运算符计算a和b的值,将结果压入s1堆栈中; 4. 重复步骤1-3,直到后缀表达式遍历完毕; 5. 最终s1中只剩下一个数字,即为计算结果。 最后,我们可以设计一个函数来实现整个计算器的功能。具体方法如下: 1. 从键盘读入一个中缀表达式; 2. 调用第一个函数将中缀表达式转换成后缀表达式; 3. 调用第二个函数计算后缀表达式的值,并输出结果。 通过以上操作,我们可以设计一个简单的利用堆栈执行的计算器,对于初学数据结构的小伙伴来说,可以作为一个良好的练手项目来帮助理解堆栈的概念。 ### 回答3: 为了创建一款简单易用的堆栈计算器,我们需要考虑以下几个方面: 1. 堆栈结构的实现 我们需要使用堆栈结构存储数字和运算符。堆栈是一种后进先出(LIFO)的数据结构,我们可以使用一个数组来模拟它们的实现。堆栈的基本操作是 push(压栈)和 pop(弹栈)。当我们 push 一个元素时,它会被添加到堆栈的顶部;当我们 pop 一个元素时,它会被从堆栈的顶部弹出。 下面是一个简单的实现示例: class Stack: def __init__(self): self.stack = [] def push(self, item): self.stack.append(item) def pop(self): if not self.is_empty(): return self.stack.pop() def is_empty(self): return len(self.stack) == 0 2. 计算器的设计 在计算器中,我们需要处理数字和运算符。当我们遇到一个数字时,我们将其 push 到数字堆栈中;当遇到一个运算符时,我们将其 push 到运算符堆栈中。我们还需要处理一些特殊字符,例如括号、小数点和正负号。 在计算器中,我们使用两个堆栈来处理数字和运算符,而且我们需要注意运算符之间的优先级。当一个运算符的优先级比另一个运算符高时,它会先被处理。为了实现这个功能,我们可以定义一个操作符优先级的字典。 下面是一个简单的堆栈计算器的示例代码: class Calculator: priority = {'+': 1, '-': 1, '*': 2, '/': 2} def __init__(self): self.numbers = Stack() self.operators = Stack() def calculate(self, expr): for c in expr: if c.isdigit(): self.numbers.push(float(c)) elif c == '.': num = self.numbers.pop() self.numbers.push(float(str(num) + c)) elif c in self.priority: while not self.operators.is_empty() and self.priority[c] <= self.priority[self.operators.stack[-1]]: self.do_math() self.operators.push(c) elif c == '(': self.operators.push(c) elif c == ')': while self.operators.stack[-1] != '(': self.do_math() self.operators.pop() elif c == '-': if not self.numbers.is_empty() and isinstance(self.numbers.stack[-1], float) and not isinstance(self.operators.stack[-1], str): num = self.numbers.pop() self.operators.push('*') self.numbers.push(-num) else: self.numbers.push(c) else: continue while not self.operators.is_empty(): self.do_math() return self.numbers.pop() def do_math(self): op = self.operators.pop() num2 = self.numbers.pop() num1 = self.numbers.pop() if op == '+': self.numbers.push(num1 + num2) elif op == '-': self.numbers.push(num1 - num2) elif op == '*': self.numbers.push(num1 * num2) else: self.numbers.push(num1 / num2) 3. 总结 在本示例中,我们介绍了一个简单的堆栈计算器的实现。堆栈是一种强大的数据结构,它在计算器中发挥着重要的作用。我们通过实现一个简单的堆栈计算器来展示堆栈的使用方法。希望这篇文章能够对初学数据结构和算法的小伙伴有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值