据我所知道的,唯一的区别__asm { ... };,并__asm__("...");是第一个使用mov eax, var第二个使用movl %0, %%eax与:"=r" (var)结尾.还有什么其他差异?那又怎么样asm?
我在这上面运行了gcc -S:
int main()
{
printf ("Hello world!");
}
Run Code Online (Sandbox Code Playgroud)
我得到了这个汇编代码:
.file "test.c"
.section .rodata
.LC0:
.string "Hello world!"
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
movl $.LC0, (%esp)
call printf
addl $20, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
我很想知道这个输出.有人可以在理解这个输出时分享一些指示,或者如果有人可以针对这些行/行组中的每一行标记注释来解释它的作用,那将会很棒.
编译以下代码片段时(clang x86-64 -O3)
std::array<int, 5> test()
{
std::array<int, 5> values {{0, 1, 2, 3, 4}};
return values;
}
Run Code Online (Sandbox Code Playgroud)
它产生了我期望的典型装配
test(): # @test()
mov rax, rdi
mov ecx, dword ptr [rip + .L__const.test().values+16]
mov dword ptr [rdi + 16], ecx
movups xmm0, xmmword ptr [rip + .L__const.test().values]
movups xmmword ptr [rdi], xmm0
ret
.L__const.test().values:
.long 0 # 0x0
.long 1 # 0x1
.long 2 # 0x2
.long 3 # 0x3
.long 4 # 0x4
Run Code Online (Sandbox Code Playgroud)
但是对于小型阵列,似乎已经找到了窍门?
std::array<int, 3> test()
{ …Run Code Online (Sandbox Code Playgroud) 在本文件中.27它说文本段从0x400000开始.为什么选择这个特定的地址?有什么理由吗?相同的地址被选择在GNU ld上Linux:
$ ld -verbose | grep -i text-segment
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
Run Code Online (Sandbox Code Playgroud)
这是令人惊讶的,因为这个地址在32位x86可执行文件中更大:
$ ld -verbose | grep -i text-segment
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); . = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS;
Run Code Online (Sandbox Code Playgroud)
我读了这个问题,讨论为什么为i386选择了0x080xxxxx地址,但它没有解释x86_64的变化.在这个问题上很难找到任何解释.有人有线索吗?
我的一个朋友从“理解和使用 C 指针 - Richard Reese,O'Reilly 出版物”中指出了第二个要点,我无法解释其中的第一句话。我错过了什么?
空指针
指向 void 的指针是一个通用指针,用于保存对任何数据类型的引用。指向 void 的指针的示例如下所示:
Run Code Online (Sandbox Code Playgroud)void *pv;它有两个有趣的特性:
- 指向 void 的指针将具有与指向 的指针相同的表示形式和内存对齐方式
char。- 指向 void 的指针永远不会等于另一个指针。但是,分配了一个
NULL值的两个空指针将是相等的。
这是我的代码,不是书中的代码,所有指针都具有相同的值并且相等。
#include <stdio.h>
int main()
{
int a = 10;
int *p = &a;
void *p1 = (void*)&a;
void *p2 = (void*)&a;
printf("%p %p\n",p1,p2);
printf("%p\n",p);
if(p == p1)
printf("Equal\n");
if(p1 == p2)
printf("Equal\n");
}
Run Code Online (Sandbox Code Playgroud)
输出:
0x7ffe1fbecfec 0x7ffe1fbecfec
0x7ffe1fbecfec
Equal
Equal
Run Code Online (Sandbox Code Playgroud) 汇编语言和机器语言(对于相同的底层系统)是否真的相同?这两个概念之间有什么不同吗?
我在课本中读到堆栈通过减少内存地址而增长; 也就是说,从较高地址到较低地址.这可能是一个糟糕的问题,但我没有把这个概念弄好.你可以解释吗?
x86架构上的Linux内核的默认内存页面大小是4 KB,我想知道这是如何计算的,为什么?
我是指令优化的新手.
我对一个简单的函数dotp进行了简单的分析,该函数用于获取两个浮点数组的点积.
C代码如下:
float dotp(
const float x[],
const float y[],
const short n
)
{
short i;
float suma;
suma = 0.0f;
for(i=0; i<n; i++)
{
suma += x[i] * y[i];
}
return suma;
}
Run Code Online (Sandbox Code Playgroud)
我用昂纳雾在网络上提供的测试框架testp.
在这种情况下使用的数组是对齐的:
int n = 2048;
float* z2 = (float*)_mm_malloc(sizeof(float)*n, 64);
char *mem = (char*)_mm_malloc(1<<18,4096);
char *a = mem;
char *b = a+n*sizeof(float);
char *c = b+n*sizeof(float);
float *x = (float*)a;
float *y = (float*)b;
float *z = (float*)c;
Run Code Online (Sandbox Code Playgroud)
然后我调用函数dotp,n = 2048,repeat …
C++11 通过该库支持伪随机数生成<random>。
我看过多本书籍,其中提到持续构建和销毁std::random_device, std::uniform_int_distribution<>,std::uniform_real_distribution<>对象的成本非常高,并且他们建议在应用程序中保留这些对象的单个副本。
为什么创建/销毁这些对象的成本很高?这里的贵到底是什么意思呢?就执行速度、可执行文件大小或其他方面而言,它是否昂贵?
有人可以提供一些解释吗?
assembly ×4
c ×3
linux ×3
abi ×2
c++ ×2
gcc ×2
x86 ×2
x86-64 ×2
architecture ×1
c++11 ×1
callstack ×1
elf ×1
isa ×1
kernel ×1
machine-code ×1
memory ×1
optimization ×1
performance ×1
pointers ×1
random ×1
sse ×1
stack ×1
visual-c++ ×1