Los tecnólogos de Microsoft hablan sobre la rareza de la arquitectura x86

[Nota del editor de CSDN] El 8 de junio de 1978, Intel lanzó un nuevo microprocesador de 16 bits "8086", que también marcó el comienzo de una nueva era: nació la arquitectura x86. x86 se refiere a algunos conjuntos de instrucciones de lenguaje informático ejecutados por un microprocesador específico, que define las reglas básicas de uso del chip, al igual que x64, IA64, etc. No solo ha logrado la prominencia de Intel, sino que también se ha convertido en un estándar de la industria, donde x86 se puede encontrar incluso en los potentes procesadores multinúcleo de la actualidad.

El tecnólogo de Microsoft, Raymond Chen, ha estado involucrado en el desarrollo de Windows durante 25 años y, en la práctica, cree que la arquitectura X86 tiene muchas rarezas.

Dirección original: https://devblogs.microsoft.com/oldnewthing/20220418-00/?p=106489

Este artículo está traducido por CSDN, y la fuente debe indicarse para su reimpresión.

Traductor | Editado por Zhang Yuming | Producido por Zhang Hongyue
| CSDN (ID: CSDNnews)

La siguiente es la traducción:

Recientemente, descubrí que la arquitectura x86 es diferente de otras arquitecturas: la forma en que se administran las excepciones estructuradas de Windows.

En Windows, todas las demás arquitecturas realizan un seguimiento del manejo de excepciones mediante el uso de código de desenredado y otra información declarada como metadatos. Si ingresa a una función en otras arquitecturas, no verá ninguna instrucción relacionada con el manejo de excepciones. Solo cuando ocurre una excepción, el sistema busca el puntero de instrucción en la información de manejo de excepciones en los metadatos y lo usa para decidir qué hacer: ¿qué controlador de excepción debe ejecutarse? ¿Qué objetos necesitan ser destruidos? y otras cuestiones similares.

Pero curiosamente, en Windows, x86 rastrea la información de excepción en tiempo de ejecución. Cuando el control ingresa a una función que necesita manejar una excepción (ya sea porque quiere manejar la excepción o simplemente porque quiere ejecutar el destructor cuando la función lanza la excepción), el código debe crear una entrada y anclarse con el valor en .NET. En la implementación de Microsoft Visual C++, el nodo de lista enlazada también contiene un número entero que representa el progreso de la función actual, que se actualiza cada vez que cambia la lista de objetos que se van a destruir. Se actualiza inmediatamente después de que se completa la construcción de un objeto e inmediatamente antes de que comience la destrucción del objeto. fs:[0]

Este número entero en particular es un problema muy problemático, porque el optimizador lo ve como un almacén de desechos y quiere optimizarlo. Es cierto que a veces es una tienda abandonada, pero a veces no lo es.

struct S { S(); ~S(); };
​
​
void f1();
void f2();
​
​
S g()
{
    S s1;
    f1();
    S s2;
    f2();
    return S();
}

El proceso de generación de código para esta función es el siguiente:

struct ExceptionNode
{
    ExceptionNode* next;
    int (__stdcall *handler)(PEXCEPTION_POINTERS);
    int state;
};
​
​
S g()
{
    // Create a new node
    ExceptionNode node;
    node.next = fs:[0];
    node.handler = exception_handler_function;
    node.state = -1; // nothing needs to be destructed
​
​
    // Make it the new head of the linked list
    fs:[0] = &node;
​
​
    construct s1;
    node.state = 0; // s1 needs to be destructed
​
​
    f1();
​
​
    construct s2;
    node.state = 1; // s1 and s2 need to be destructed
​
​
    f2();
​
​
    construct return value;
    node.state = 2; // s1, s2, and return value need to be destructed
​
​
    node.state = 3; // s1 and return value need to be destructed
    destruct s2;
​
​
    node.state = 4; // return value needs to be destructed
    destruct s1;
}
 
 

Cada vez que cambia la lista de "objetos para destruir", se actualiza la variable de estado de desenrollado. En lo que respecta al optimizador, todas estas actualizaciones parecen ser tiendas obsoletas porque nadie parece leerlas. .Expresar

Pero la gente los lee: .the. El problema es que la llamada al es invisible. Se llama cuando una función o lanza una excepción, o el destructor de un objeto.

Sin embargo, algunos de ellos son realmente almacenes abandonados. Por ejemplo, la asignación de 2 es un almacén obsoleto porque le sigue el almacén de 3 sin nada intermedio, por lo que cuando el valor es 2, no se producirá ninguna excepción. Asimismo, el almacenamiento de 3 está obsoleto porque el destructor de 3 está implícito. No se pueden producir excepciones cuando se destruye .node.stateSnoexcepts1.

Si o se cambia a .f1f2noexcept, la tienda obsoleta puede eliminarse.

Por lo tanto, el optimizador se encuentra en un dilema. Quiere eliminar el almacenamiento obsoleto, pero los algoritmos simples para identificar el almacenamiento obsoleto no funcionan aquí debido al potencial de anomalías.

Las corrutinas empeoran las cosas: cuando se suspende una corrutina, el nodo de manejo de excepciones debe copiarse de la pila al marco de la corrutina y luego eliminarse del marco de la pila. Y cuando se reanuda la corrutina, el estado debe volver a copiarse en la pila desde el marco de la corrutina y vincularse a la cadena del controlador de excepciones.

Es difícil saber exactamente cuándo desvincular y volver a vincular, porque todavía tiene que detectar las excepciones que ocurren en ellos y almacenarlas en promesas. Pero lo más probable es que esto no sea factible porque es posible que la rutina se haya reanudado y se haya completado antes de regresar.

.await_suspendawait_suspendawait_suspend

void await_suspend(coroutine_handle<> handle)
{
  arrange_for_resumption(handle);
  throw oops; // who catches this?
}

La excepción lanzada es capturada por el marco coroutine, que llama a .NET Framework. ¡Pero es posible que las promesas ya no existan! promesa.excepción_no controlada()

Manejar todos estos casos hace que el manejo de excepciones en x86, especialmente para rutinas en x86, sea un trabajo bastante complejo.

Supongo que te gusta

Origin blog.csdn.net/csdnnews/article/details/124301287
Recomendado
Clasificación