X64 GCC内联汇编调用scanf:动态二维数组输入解析问询
How to Use Inline Assembly to Call
scanf for a Dynamically Allocated 2D Int Array on x64 GCC Alright, let's tackle this step by step. First, let's get clear on the ground rules for x64 GCC (which uses the System V AMD64 calling convention) and how scanf works as a variadic function. Then we'll build the code with inline assembly, following your requirement of nested loops and stack balancing.
Key Background
- x64 System V Calling Convention: For variadic functions like
scanf, the first 6 integer/pointer arguments go into registersrdi,rsi,rdx,rcx,r8,r9. Any extra arguments are pushed onto the stack in reverse order (rightmost parameter first). The caller is responsible for cleaning up the stack after the call. - Dynamic 2D Array: We're assuming your
imageis anint**— an array of pointers, each pointing to a row ofints. - Format String: We need a format string with exactly
width * heightinstances of%d(since we're readingints). We'll dynamically build this string to match your dimensions.
Complete Code Example
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { // Dynamic dimensions (can be set at runtime) int height = 3; int width = 3; int total_elements = height * width; // 1. Allocate the 2D array int** image = malloc(height * sizeof(int*)); if (!image) { perror("malloc failed"); return 1; } for (int i = 0; i < height; i++) { image[i] = malloc(width * sizeof(int)); if (!image[i]) { perror("malloc failed"); return 1; } } // 2. Build the format string: e.g., "%d %d %d %d %d %d %d %d %d" // Each %d is followed by a space to handle whitespace in input size_t format_len = total_elements * 3; // "%d " is 3 chars, minus trailing space char* format = malloc(format_len); if (!format) { perror("malloc failed"); return 1; } strcpy(format, ""); for (int i = 0; i < total_elements; i++) { strcat(format, "%d"); if (i != total_elements - 1) strcat(format, " "); } // 3. Inline assembly to call scanf __asm__ volatile ( // Outer loop: start from last row (height-1) down to 0 "movl %[height], %%ecx\n" // ecx = height (outer loop counter) "movl %%ecx, %%ebx\n" "decl %%ebx\n" // ebx = i = height - 1 "outer_loop:\n" // Inner loop: start from last column (width-1) down to 0 "movl %[width], %%edx\n" // edx = width (inner loop counter) "movl %%edx, %%esi\n" "decl %%esi\n" // esi = j = width - 1 "inner_loop:\n" // Calculate address of image[i][j] "movq %[image], %%rdi\n" // rdi = base pointer of 2D array "movq (%%rdi, %%rbx, 8), %%rdi\n" // rdi = pointer to row i (each int* is 8 bytes) "leaq (%%rdi, %%rsi, 4), %%r8\n" // r8 = &image[i][j] (each int is 4 bytes) "pushq %%r8\n" // Push the element address to stack // Decrement inner loop counter, loop if not negative "decl %%esi\n" "jns inner_loop\n" // Decrement outer loop counter, loop if not negative "decl %%ebx\n" "jns outer_loop\n" // Push format string address (last parameter in stack order) "pushq %[format]\n" // Call scanf "call scanf\n" // Balance the stack: total_elements + 1 pointers, each 8 bytes "addq $%[stack_offset], %%rsp\n" // Input operands : : [image] "r" (image), [height] "r" (height), [width] "r" (width), [format] "r" (format), [stack_offset] "i" (8 * (total_elements + 1)) // Clobbered registers: tell GCC which registers we modify : "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", "memory" ); // Verify the input (optional) printf("You entered:\n"); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { printf("%d ", image[i][j]); } printf("\n"); } // Cleanup memory for (int i = 0; i < height; i++) { free(image[i]); } free(image); free(format); return 0; }
Breakdown of the Inline Assembly
- Loop Direction: We iterate from the last element to the first because
scanfexpects parameters in reverse stack order (rightmost argument pushed first). This ensures the first element's address is the first parameter read after the format string. - Address Calculation:
movq (%%rdi, %%rbx, 8), %%rdi: Fetches the pointer to rowi— since eachint*is 8 bytes in x64, we scale the row index by 8.leaq (%%rdi, %%rsi, 4), %%r8: Computes the address ofimage[i][j]— eachintis 4 bytes, so we scale the column index by 4.
- Stack Management: We push all element addresses first, then the format string. After calling
scanf, we adjust the stack pointer to clean up all pushed parameters — this is critical to avoid crashes. - Clobber List: We explicitly list registers we modify so GCC doesn't use them for other variables. The
memoryclobber ensures GCC knows we're writing to the array memory.
Important Notes
- Input Flexibility:
scanfskips any whitespace (spaces, newlines, tabs), so you can enter the data in any format (single line, multiple lines, etc.). - Performance Alternative: For better efficiency, you could pass the first 6 element addresses in registers instead of pushing them to the stack. The code above sticks strictly to your requirement of using nested loops to push all addresses.
内容的提问来源于stack exchange,提问作者markable
相关产品推荐
相关产品推荐

