标签: x86-64

如何将汇编代码转换为二进制代码?

我使用以下代码创建了一个简单的 C++ 源文件:

    int main() {
    int a = 1;
    int b = 2;
    if(a < b) {
        return 1;
    }
    else if(a > b) {
        return 2;
    }
    else {
        return 3;
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用objdump命令来获取上述源代码的汇编代码。
该行int b = 2;已转换为mov DWORD PTR [rbp-0x4], 0x2.
其对应的机器码为C7 45 FC 02 00 00 00(十六进制格式)。

我想知道如何将汇编代码转换为二进制代码。我浏览了 x86-64 的英特尔参考手册,但我无法理解它,因为我是低级编程的新手。

binary assembly x86-64 instruction-encoding

1
推荐指数
1
解决办法
4568
查看次数

15字节指令如何从内存传输到CPU?

假设我们使用的是 x86-64 机器,这意味着它的通用寄存器是 64 位长,它的数据总线一次可以处理 64 位,它的 ALU 可以处理最大 64 位数量(对吗?)。

有一个简单的指令,例如

MOV $5, %eax
Run Code Online (Sandbox Code Playgroud)

通过 64 位数据总线将 32 位数字移入 CPU 寄存器。

我已阅读以下内容:

An x86-64 instruction may be at most 15 bytes in length.
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果数据总线最大为 64 位,这怎么可能?它如何处理 120 位的指令。CPU是否会在多个周期中获取它?

我的第二个问题是,是否有长度更大的特殊寄存器来存储所有 120 位?

assembly x86-64 instruction-set cpu-architecture cpu-registers

1
推荐指数
1
解决办法
1890
查看次数

使用读取 [ebp+4] 的 MSVC 内联汇编移植到 64 位

我正在使用 Microsoft Visual Studio 2010,并且我正在尝试支持我的项目的 64 位构建。据我所知,64 位架构不支持 __asm 关键字。

以下是当项目仅支持 32 位构建时它的工作原理。

void* 
Class1::Class2::operator new(size_t size) 
{ 
void *pCaller;
__asm mov edx, [ebp+4] 
__asm mov pCaller, edx 
char *pMem = (char *) malloc (sizeof(Class2) + size);
doSomething(pMem, pCaller);
void *ptr = (void *) (pMem + sizeof(Class2)); 
return(ptr);
}
Run Code Online (Sandbox Code Playgroud)

我可以使用预处理器指令使上述函数取决于建筑类型。

void* 
Class1::Class2::operator new(size_t size) 
{
#ifndef _WIN64  
void *pCaller;
__asm mov edx, [ebp+4] 
__asm mov pCaller, edx 
char *pMem = (char *) malloc (sizeof(Class2) + size);
doSomething(pMem, pCaller);
void *ptr …
Run Code Online (Sandbox Code Playgroud)

c++ porting x86-64 inline-assembly visual-c++

1
推荐指数
1
解决办法
892
查看次数

检查数字是否为偶数

我正在研究低级位黑客,并想为每个黑客编写一个汇编程序。这是我检查数字是否偶数的方法:

is_even:
    # check if an integer is even. 
    # This is the same as seeing if its a multiple of two, i.e., & 1<<n - 1
    # rdi stores the number
    xor %eax, %eax
    test $0b1, %rdi
    setz %al
    ret

_start:
    mov $5, %rdi
    call is_even
Run Code Online (Sandbox Code Playgroud)

有什么方法可以改进上述内容或使其更具可读性?是否可以is_even使用 2 条指令而不是 3 条指令进行检查,因为第一条xor和第二条指令setz似乎可能会转换为一条(如果可能的话)。

x86 assembly bit-manipulation x86-64

1
推荐指数
1
解决办法
728
查看次数

为什么 MSVC 不在生成的汇编代码中分配 32 字节影子空间?

我试图查看 MSVC 如何分配其 32 字节的影子空间,但似乎它只分配 8 字节的影子空间。

// Test.c
int main() {int var1 = 1;}
Run Code Online (Sandbox Code Playgroud)

上面的程序生成以下 .asm 文件:

var1$ = 0

main    PROC
; Test.c
    sub rsp, 24                    ; allocates 24 bytes
    mov DWORD PTR var1$[rsp], 1
    xor eax, eax
    add rsp, 24
    ret 0
main    ENDP
Run Code Online (Sandbox Code Playgroud)

它只分配24个字节。当我声明 4 个变量时,它会分配相同的数量,并且由于每个变量都是 4 个字节,因此必然意味着 24 个字节中的 16 个字节用于声明的变量,留下 8 个字节用于影子空间。
仅当声明 5 个变量时,它才会分配 40 字节的影子空间。为什么它只分配8字节的影子空间?
我使用命令编译了程序CL Test.c /Fa

c assembly x86-64 masm visual-c++

1
推荐指数
1
解决办法
444
查看次数

为什么 lea 将明显随机的地址移动到 rdi?

我有以下一段C代码:

#include <stdio.h>

int main()
{
    int i;
    for(i=0; i<10; i++)
        puts("hello, friend");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我这样编译的:gcc firstprog.c -o firstprog

然后,当使用gdb拆卸它时,我看到:

(gdb) disassemble 
Dump of assembler code for function main:
=> 0x0000555555555149 <+0>: endbr64 
   0x000055555555514d <+4>: push   rbp
   0x000055555555514e <+5>: mov    rbp,rsp
   0x0000555555555151 <+8>: sub    rsp,0x10
   0x0000555555555155 <+12>:    mov    DWORD PTR [rbp-0x4],0x0
   0x000055555555515c <+19>:    jmp    0x55555555516e <main+37>
   0x000055555555515e <+21>:    lea    rdi,[rip+0xe9f]        # 0x555555556004
   0x0000555555555165 <+28>:    call   0x555555555050 <puts@plt>
   0x000055555555516a <+33>:    add    DWORD PTR [rbp-0x4],0x1
   0x000055555555516e <+37>:    cmp …
Run Code Online (Sandbox Code Playgroud)

assembly x86-64 objdump string-literals

1
推荐指数
1
解决办法
1030
查看次数

如果我们只对 64 位寄存器的低 4 字节进行 mov 操作,那么它的高 4 字节是否设置为零

我正在从《计算机系统:程序员的视角》学习 x86-64 汇编,并且遇到了一个练习,要求将一行 C 代码转换为(两个)等效的汇编指令。该代码是关于使用指针将一种类型的变量复制到另一种类型的变量。

指针变量声明如下:

src_t *sp; //src_t and dest_t are typedefs
dest_t *dp;
Run Code Online (Sandbox Code Playgroud)

需要翻译的C代码是:

*dp = (dest_t)*sp;
Run Code Online (Sandbox Code Playgroud)

假设指针sp和分别dp存储在寄存器%rdi%rsi中,并且我们应该设置%rax(例如 、%eax%ax)的“适当部分”%al来进行中间数据复制(因为 x86-64 不允许源和目标同时复制)是内存引用)。

现在,当src_tisunsigned chardest_tis 时long,我为其编写了以下汇编代码:

movzbq (%rdi), %rax //move a byte into %rax with zero extension
movq %rax, (%rsi) //move 8 bytes of 'long' data 
Run Code Online (Sandbox Code Playgroud)

但这本书以及Godboltgcc (与 一起使用-O3)都说它应该是

movzbl  (%rdi), %eax …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc x86-64

1
推荐指数
1
解决办法
2046
查看次数

为什么添加 if(!memcmp()) 会加速循环,使随机短步跨过一个巨大的字节数组?

抱歉,我一直不明白这里的规则。我已经删除了所有重复的帖子。这是第一个相关问题。\n请不要将此帖子标记为我另一篇帖子的重复(执行次数减少 3 倍,但执行效率几乎不变。在 C 中),即使代码有些相似,他们提出了截然不同的问题。这也是我同一天发现的两个问题。类似的帖子因“误判”而被重复,然后被关闭。可能是我没有把这个问题说清楚。我真的很希望得到答案,所以我重新发布了它。希望大家能够看清问题,非常感谢!

\n

在下面的C代码中,我在第一次测试时间的循环中添加了一个“if”语句,执行时间完全相同。从理论上讲,它应该更慢。尽管分支预测可以使它们的性能几乎相同,但它实际上变得更快。这是什么原理呢?我尝试使用clang和gcc编译器分别在Mac和Linux环境中运行,并尝试了各种优化级别。为了防止缓存受到影响,我让速度较快的先执行,但有冗余代码的循环执行得更快。

\n

如果您认为我的描述不可信,请将以下代码编译到您的计算机中并运行。希望有人能为我回答这个问题\xef\xbc\x8c谢谢。

\n

C代码:

\n
#include <stdio.h>\n#include <time.h>\n#include <stdlib.h>\n#include <string.h>\n\n#define TLen 300000000\n#define SLen 10\n\nint main(int argc, const char * argv[]) {\n    srandom((unsigned)time(NULL));\n    \n    // An array to increase the index,\n    // the range of its elements is 1-256\n    int rand_arr[128];\n    for (int i = 0; i < 128; ++i)\n        rand_arr[i] = random()%256+1;\n    \n    // A random text(very long), the range of its elements is 0-127\n    char *tex = malloc((sizeof *tex) * …
Run Code Online (Sandbox Code Playgroud)

c performance x86-64 cpu-architecture

1
推荐指数
1
解决办法
470
查看次数

x86_64 汇编中的分段错误,代码位于 .text 节中:(节名称中带有冒号)

为什么会出现分段错误?

我用的nasm -f elf64 t.asm -o t.o ld t.o -o t是linux下的编译。

我已经做了我能想到的一切。

section .data:
  variable_int db 1
  variable_string db "yaaaa", 10
section .text:
  global _start
_start:
  mov rax, 1
  mov rdi, 1
  mov rsi, variable_string
  mov rdx, 14
  syscall
  mov rax, 60
  mov rdi, 0
  syscall
Run Code Online (Sandbox Code Playgroud)

assembly x86-64 nasm segmentation-fault

1
推荐指数
1
解决办法
372
查看次数

编译器真的会优化以使这两个函数成为相同的程序集吗?

我将其插入 Godbolt,并惊喜地发现这两个函数调用a()和在除(使用大多数主要编译器)b()之外的任何其他情况下都是等效的:-O0

#include <cmath>

struct A {
    int a,b,c;
    float bar() {
        return sqrt(a + b + c);
    }
};

struct B {
    int a[3];
    float bar() {
        int ret{0};
        for (int i = 0; i<3; ++i) {
            ret += a[i];
        }
        return sqrt(ret);
    }
};

float a() {
    A a{55,67,12};
    return a.bar();
}

float b() {
    B b{55,67,12};
    return b.bar();
}
Run Code Online (Sandbox Code Playgroud)

Godbolt 输出为:

a():
        movss   xmm0, DWORD PTR .LC0[rip]
        ret
b():
        movss   xmm0, DWORD …
Run Code Online (Sandbox Code Playgroud)

c++ assembly x86-64 compiler-optimization

1
推荐指数
1
解决办法
351
查看次数