从常规中恢复失败

时间:2013-02-15 01:18:27

标签: assembly x86

我在汇编语言中有一个例程,用于执行字符串到整数转换。但我怎么能失败呢? (例如,在字符串中看到非数字)它将整数值返回到eax,非零值,因为我通常不是一个好主意为什么我不能区分"0"转换从错误到0。如果失败,也许stc?你是如何实现它的?

3 个答案:

答案 0 :(得分:1)

这取决于您的功能是否需要遵循传统的呼叫约定。如果它可以由您没有组件级控制的函数调用,例如C函数,那么你不能使用进位来指示错误,因为没有办法告诉编译器检查它。如果您的代码将在许多地方使用,那么最好遵循调用约定,因为它们都需要知道它如何返回值。

如果您的功能仅由您可以控制的汇编代码使用,那么您可以根据需要返回错误。设置进位标志(stc)是一种常见的选择。例如,它被BIOS功能使用,我个人之前已经使用过它。请务必在成功时清除进位标志(clc)。

另一种可能性是使用两个寄存器作为返回值,一个用于实际结果,一个用于错误代码。如果使用edx,这实际上与某些编译器兼容,例如gcc,它使用edx:eax作为64位整数的结果位置或64位的结构。

最后,如果您需要确保与所有编译器的兼容性,您应该让您的函数采用额外的参数,该参数是指向实际结果的指针,并且只返回错误代码。在C中,这看起来像这样:

int myFunction(int otherArguments, int *resultPointer) {
    int errorCode, result;
    ...
    *resultPointer = result;
    return errorCode;
}

答案 1 :(得分:1)

简单地说,你返回一个额外的值。

选项一(在C中),使用全局变量:

#include <stdio.h>

int error = 0;

int String2Int(const char* s)
{
  ...
  if (some_error_condition)
    error = 1;
  ...
}

int main(void)
{
  int value;
  error = 0;
  value = String2Int("12g");
  if (error != 0)
    printf("error!\n");
  return 0;
}

选项二,传递指向错误变量的指针:

#include <stdio.h>

int String2Int(const char* s, int* error)
{
  ...
  if (some_error_condition)
    *error = 1;
  ...
}

int main(void)
{
  int error = 0;
  int value = String2Int("12g", &error);
  if (error != 0)
    printf("error!\n");
  return 0;
}

选项树,返回一个结构:

#include <stdio.h>

struct valerr
{
  int value;
  int error;
};

struct valerr String2Int(const char* s)
{
  struct valerr ve;
  ...
  if (some_error_condition)
    ve.error = 1;
  ...
  return ve;
}

int main(void)
{
  struct valerr ve = String2Int("12g");
  if (ve.error != 0)
    printf("error!\n");
  return 0;
}

在后一种情况下,编译器可能会将一个隐式参数插入String2Int(),指向ve,以便return ve;知道存储返回结构的位置。

答案 2 :(得分:1)

如果这是汇编程序,由程序集调用,则可以使用各种选项。

您可以在%eax以外的寄存器中返回错误代码(0表示无错误,1表示错误或发生错误的字符串中的偏移量)(%ebx,%ecx,等等) - 只需确保调用者在调用你的函数之前保存寄存器。)

您可以在%eflags中设置一个标志,例如奇偶校验(PF)。 RET指令不会修改任何标志,因此清除条目上的标志并将其设置为退出将意味着在例程返回时仍然设置标志。确保选择一个在清除和设置之间不会被修改的标志!

你可以触发一个异常(例如溢出)并让调用者捕获它 - 但对于类似字符串转换的东西来说这有点笨拙。如果未正确捕获异常,您可能会使调用应用程序崩溃。

如果您希望将汇编语言例程调用为库函数(即通过未指定的编程语言中已建立的调用约定调用),那么您实际上有两个选项之一:使用全局或具有调用者传入一个指针,您的例程可以使用该指针来编写错误代码。看看strtoul(3)是如何做到的。